Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
f47e86fe
Commit
f47e86fe
authored
May 30, 2017
by
Phil Hughes
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '30117-update-looks-job-log' into 'master'
Update looks job log Closes #30117 See merge request !11663
parents
763a3acd
cd023d42
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
480 additions
and
483 deletions
+480
-483
app/assets/javascripts/build.js
app/assets/javascripts/build.js
+150
-183
app/assets/stylesheets/pages/builds.scss
app/assets/stylesheets/pages/builds.scss
+104
-119
app/views/projects/builds/_sidebar.html.haml
app/views/projects/builds/_sidebar.html.haml
+0
-7
app/views/projects/builds/show.html.haml
app/views/projects/builds/show.html.haml
+36
-24
app/views/shared/icons/_scroll_down.svg
app/views/shared/icons/_scroll_down.svg
+4
-2
app/views/shared/icons/_scroll_down_hover_active.svg
app/views/shared/icons/_scroll_down_hover_active.svg
+0
-3
app/views/shared/icons/_scroll_up.svg
app/views/shared/icons/_scroll_up.svg
+1
-3
app/views/shared/icons/_scroll_up_hover_active.svg
app/views/shared/icons/_scroll_up_hover_active.svg
+0
-3
spec/features/projects/builds_spec.rb
spec/features/projects/builds_spec.rb
+9
-9
spec/javascripts/build_spec.js
spec/javascripts/build_spec.js
+176
-130
No files found.
app/assets/javascripts/build.js
View file @
f47e86fe
...
...
@@ -2,15 +2,11 @@
consistent-return, prefer-rest-params */
/* global Breakpoints */
import
_
from
'
underscore
'
;
import
{
bytesToKiB
}
from
'
./lib/utils/number_utils
'
;
const
bind
=
function
(
fn
,
me
)
{
return
function
()
{
return
fn
.
apply
(
me
,
arguments
);
};
};
const
AUTO_SCROLL_OFFSET
=
75
;
const
DOWN_BUILD_TRACE
=
'
#down-build-trace
'
;
window
.
Build
=
(
function
()
{
Build
.
timeout
=
null
;
Build
.
state
=
null
;
function
Build
(
options
)
{
...
...
@@ -23,21 +19,22 @@ window.Build = (function () {
this
.
buildStage
=
this
.
options
.
buildStage
;
this
.
$document
=
$
(
document
);
this
.
logBytes
=
0
;
this
.
scrollOffsetPadding
=
30
;
this
.
updateDropdown
=
bind
(
this
.
updateDropdown
,
this
);
this
.
updateDropdown
=
this
.
updateDropdown
.
bind
(
this
);
this
.
getBuildTrace
=
this
.
getBuildTrace
.
bind
(
this
);
this
.
scrollToBottom
=
this
.
scrollToBottom
.
bind
(
this
);
this
.
$body
=
$
(
'
body
'
);
this
.
$buildTrace
=
$
(
'
#build-trace
'
);
this
.
$autoScrollContainer
=
$
(
'
.autoscroll-container
'
);
this
.
$autoScrollStatus
=
$
(
'
#autoscroll-status
'
);
this
.
$autoScrollStatusText
=
this
.
$autoScrollStatus
.
find
(
'
.status-text
'
);
this
.
$upBuildTrace
=
$
(
'
#up-build-trace
'
);
this
.
$downBuildTrace
=
$
(
DOWN_BUILD_TRACE
);
this
.
$scrollTopBtn
=
$
(
'
#scroll-top
'
);
this
.
$scrollBottomBtn
=
$
(
'
#scroll-bottom
'
);
this
.
$buildRefreshAnimation
=
$
(
'
.js-build-refresh
'
);
this
.
$buildScroll
=
$
(
'
#js-build-scroll
'
);
this
.
$truncatedInfo
=
$
(
'
.js-truncated-info
'
);
this
.
$buildTraceOutput
=
$
(
'
.js-build-output
'
);
this
.
$scrollContainer
=
$
(
'
.js-scroll-container
'
);
// Scroll controllers
this
.
$scrollTopBtn
=
$
(
'
.js-scroll-up
'
);
this
.
$scrollBottomBtn
=
$
(
'
.js-scroll-down
'
);
clearTimeout
(
Build
.
timeout
);
// Init breakpoint checker
...
...
@@ -56,54 +53,149 @@ window.Build = (function () {
.
off
(
'
click
'
,
'
.stage-item
'
)
.
on
(
'
click
'
,
'
.stage-item
'
,
this
.
updateDropdown
);
this
.
$document
.
on
(
'
scroll
'
,
this
.
initScrollMonitor
.
bind
(
this
));
// add event listeners to the scroll buttons
this
.
$scrollTopBtn
.
off
(
'
click
'
)
.
on
(
'
click
'
,
this
.
scrollToTop
.
bind
(
this
));
this
.
$scrollBottomBtn
.
off
(
'
click
'
)
.
on
(
'
click
'
,
this
.
scrollToBottom
.
bind
(
this
));
$
(
window
)
.
off
(
'
resize.build
'
)
.
on
(
'
resize.build
'
,
this
.
sidebarOnResize
.
bind
(
this
));
$
(
'
a
'
,
this
.
$buildScroll
)
.
off
(
'
click.stepTrace
'
)
.
on
(
'
click.stepTrace
'
,
this
.
stepTrace
);
this
.
updateArtifactRemoveDate
();
this
.
initScrollButtonAffix
();
this
.
invokeBuildTrace
();
// eslint-disable-next-line
this
.
getBuildTrace
()
.
then
(()
=>
this
.
makeTraceScrollable
())
.
then
(()
=>
this
.
scrollToBottom
());
this
.
verifyTopPosition
();
}
Build
.
prototype
.
makeTraceScrollable
=
function
()
{
this
.
$scrollContainer
.
niceScroll
({
cursorcolor
:
'
#fff
'
,
cursoropacitymin
:
1
,
cursorwidth
:
'
3px
'
,
railpadding
:
{
top
:
5
,
bottom
:
5
,
right
:
5
},
});
this
.
$scrollContainer
.
on
(
'
scroll
'
,
_
.
throttle
(
this
.
toggleScroll
.
bind
(
this
),
100
));
this
.
toggleScroll
();
};
Build
.
prototype
.
canScroll
=
function
()
{
return
(
this
.
$scrollContainer
.
prop
(
'
scrollHeight
'
)
-
this
.
scrollOffsetPadding
)
>
this
.
$scrollContainer
.
height
();
};
/**
* | | Up | Down |
* |--------------------------|----------|----------|
* | on scroll bottom | active | disabled |
* | on scroll top | disabled | active |
* | no scroll | disabled | disabled |
* | on.('scroll') is on top | disabled | active |
* | on('scroll) is on bottom | active | disabled |
*
*/
Build
.
prototype
.
toggleScroll
=
function
()
{
const
bottomScroll
=
this
.
$scrollContainer
.
scrollTop
()
+
this
.
scrollOffsetPadding
+
this
.
$scrollContainer
.
height
();
if
(
this
.
canScroll
())
{
if
(
this
.
$scrollContainer
.
scrollTop
()
===
0
)
{
this
.
toggleDisableButton
(
this
.
$scrollTopBtn
,
true
);
this
.
toggleDisableButton
(
this
.
$scrollBottomBtn
,
false
);
}
else
if
(
bottomScroll
===
this
.
$scrollContainer
.
prop
(
'
scrollHeight
'
))
{
this
.
toggleDisableButton
(
this
.
$scrollTopBtn
,
false
);
this
.
toggleDisableButton
(
this
.
$scrollBottomBtn
,
true
);
}
else
{
this
.
toggleDisableButton
(
this
.
$scrollTopBtn
,
false
);
this
.
toggleDisableButton
(
this
.
$scrollBottomBtn
,
false
);
}
}
};
Build
.
prototype
.
scrollToTop
=
function
()
{
this
.
$scrollContainer
.
getNiceScroll
(
0
).
doScrollTop
(
0
);
this
.
toggleScroll
();
};
Build
.
prototype
.
scrollToBottom
=
function
()
{
this
.
$scrollContainer
.
getNiceScroll
(
0
).
doScrollTo
(
this
.
$scrollContainer
.
prop
(
'
scrollHeight
'
));
this
.
toggleScroll
();
};
Build
.
prototype
.
toggleDisableButton
=
function
(
$button
,
disable
)
{
if
(
disable
&&
$button
.
prop
(
'
disabled
'
))
return
;
$button
.
prop
(
'
disabled
'
,
disable
);
};
Build
.
prototype
.
toggleScrollAnimation
=
function
(
toggle
)
{
this
.
$scrollBottomBtn
.
toggleClass
(
'
animate
'
,
toggle
);
};
/**
* Build trace top position depends on the space ocupied by the elments rendered before
*/
Build
.
prototype
.
verifyTopPosition
=
function
()
{
const
$buildPage
=
$
(
'
.build-page
'
);
const
$header
=
$
(
'
.build-header
'
,
$buildPage
);
const
$runnersStuck
=
$
(
'
.js-build-stuck
'
,
$buildPage
);
const
$startsEnvironment
=
$
(
'
.js-environment-container
'
,
$buildPage
);
const
$erased
=
$
(
'
.js-build-erased
'
,
$buildPage
);
let
topPostion
=
168
;
if
(
$header
)
{
topPostion
+=
$header
.
outerHeight
();
}
if
(
$runnersStuck
)
{
topPostion
+=
$runnersStuck
.
outerHeight
();
}
if
(
$startsEnvironment
)
{
topPostion
+=
$startsEnvironment
.
outerHeight
();
}
if
(
$erased
)
{
topPostion
+=
$erased
.
outerHeight
()
+
10
;
}
this
.
$buildTrace
.
css
({
top
:
topPostion
,
});
};
Build
.
prototype
.
initSidebar
=
function
()
{
this
.
$sidebar
=
$
(
'
.js-build-sidebar
'
);
this
.
$sidebar
.
niceScroll
();
this
.
$document
.
off
(
'
click
'
,
'
.js-sidebar-build-toggle
'
)
.
on
(
'
click
'
,
'
.js-sidebar-build-toggle
'
,
this
.
toggleSidebar
);
};
Build
.
prototype
.
invokeBuildTrace
=
function
()
{
return
this
.
getBuildTrace
();
};
Build
.
prototype
.
getBuildTrace
=
function
()
{
return
$
.
ajax
({
url
:
`
${
this
.
pageUrl
}
/trace.json`
,
dataType
:
'
json
'
,
data
:
{
state
:
this
.
state
,
},
success
:
((
log
)
=>
{
const
$buildContainer
=
$
(
'
.js-build-output
'
);
data
:
this
.
state
,
})
.
done
((
log
)
=>
{
gl
.
utils
.
setCiStatusFavicon
(
`
${
this
.
pageUrl
}
/status.json`
);
if
(
log
.
state
)
{
this
.
state
=
log
.
state
;
}
if
(
log
.
append
)
{
$buildContainer
.
append
(
log
.
html
);
this
.
$buildTraceOutput
.
append
(
log
.
html
);
this
.
logBytes
+=
log
.
size
;
}
else
{
$buildContainer
.
html
(
log
.
html
);
this
.
$buildTraceOutput
.
html
(
log
.
html
);
this
.
logBytes
=
log
.
size
;
}
...
...
@@ -114,161 +206,55 @@ window.Build = (function () {
const
size
=
bytesToKiB
(
this
.
logBytes
);
$
(
'
.js-truncated-info-size
'
).
html
(
`
${
size
}
`
);
this
.
$truncatedInfo
.
removeClass
(
'
hidden
'
);
this
.
initAffixTruncatedInfo
();
}
else
{
this
.
$truncatedInfo
.
addClass
(
'
hidden
'
);
}
this
.
checkAutoscroll
();
if
(
!
log
.
complete
)
{
this
.
toggleScrollAnimation
(
true
);
Build
.
timeout
=
setTimeout
(()
=>
{
this
.
invokeBuildTrace
();
//eslint-disable-next-line
this
.
getBuildTrace
()
.
then
(()
=>
this
.
scrollToBottom
());
},
4000
);
}
else
{
this
.
$buildRefreshAnimation
.
remove
();
this
.
toggleScrollAnimation
(
false
);
}
if
(
log
.
status
!==
this
.
buildStatus
)
{
let
pageUrl
=
this
.
pageUrl
;
if
(
this
.
$autoScrollStatus
.
data
(
'
state
'
)
===
'
enabled
'
)
{
pageUrl
+=
DOWN_BUILD_TRACE
;
}
gl
.
utils
.
visitUrl
(
pageUrl
);
gl
.
utils
.
visitUrl
(
this
.
pageUrl
);
}
})
,
error
:
()
=>
{
})
.
fail
(
()
=>
{
this
.
$buildRefreshAnimation
.
remove
();
return
this
.
initScrollMonitor
();
},
});
};
Build
.
prototype
.
checkAutoscroll
=
function
()
{
if
(
this
.
$autoScrollStatus
.
data
(
'
state
'
)
===
'
enabled
'
)
{
return
$
(
'
html,body
'
).
scrollTop
(
this
.
$buildTrace
.
height
());
}
// Handle a situation where user started new build
// but never scrolled a page
if
(
!
this
.
$scrollTopBtn
.
is
(
'
:visible
'
)
&&
!
this
.
$scrollBottomBtn
.
is
(
'
:visible
'
)
&&
!
gl
.
utils
.
isInViewport
(
this
.
$downBuildTrace
.
get
(
0
)))
{
this
.
$scrollBottomBtn
.
show
();
}
};
Build
.
prototype
.
initScrollButtonAffix
=
function
()
{
// Hide everything initially
this
.
$scrollTopBtn
.
hide
();
this
.
$scrollBottomBtn
.
hide
();
this
.
$autoScrollContainer
.
hide
();
};
// Page scroll listener to detect if user has scrolling page
// and handle following cases
// 1) User is at Top of Build Log;
// - Hide Top Arrow button
// - Show Bottom Arrow button
// - Disable Autoscroll and hide indicator (when build is running)
// 2) User is at Bottom of Build Log;
// - Show Top Arrow button
// - Hide Bottom Arrow button
// - Enable Autoscroll and show indicator (when build is running)
// 3) User is somewhere in middle of Build Log;
// - Show Top Arrow button
// - Show Bottom Arrow button
// - Disable Autoscroll and hide indicator (when build is running)
Build
.
prototype
.
initScrollMonitor
=
function
()
{
if
(
!
gl
.
utils
.
isInViewport
(
this
.
$upBuildTrace
.
get
(
0
))
&&
!
gl
.
utils
.
isInViewport
(
this
.
$downBuildTrace
.
get
(
0
)))
{
// User is somewhere in middle of Build Log
this
.
$scrollTopBtn
.
show
();
if
(
this
.
buildStatus
===
'
success
'
||
this
.
buildStatus
===
'
failed
'
)
{
// Check if Build is completed
this
.
$scrollBottomBtn
.
show
();
}
else
if
(
this
.
$buildRefreshAnimation
.
is
(
'
:visible
'
)
&&
!
gl
.
utils
.
isInViewport
(
this
.
$buildRefreshAnimation
.
get
(
0
)))
{
this
.
$scrollBottomBtn
.
show
();
}
else
{
this
.
$scrollBottomBtn
.
hide
();
}
// Hide Autoscroll Status Indicator
if
(
this
.
$scrollBottomBtn
.
is
(
'
:visible
'
))
{
this
.
$autoScrollContainer
.
hide
();
this
.
$autoScrollStatusText
.
removeClass
(
'
animate
'
);
}
else
{
this
.
$autoScrollContainer
.
css
({
top
:
this
.
$body
.
outerHeight
()
-
AUTO_SCROLL_OFFSET
,
}).
show
();
this
.
$autoScrollStatusText
.
addClass
(
'
animate
'
);
}
}
else
if
(
gl
.
utils
.
isInViewport
(
this
.
$upBuildTrace
.
get
(
0
))
&&
!
gl
.
utils
.
isInViewport
(
this
.
$downBuildTrace
.
get
(
0
)))
{
// User is at Top of Build Log
this
.
$scrollTopBtn
.
hide
();
this
.
$scrollBottomBtn
.
show
();
this
.
$autoScrollContainer
.
hide
();
this
.
$autoScrollStatusText
.
removeClass
(
'
animate
'
);
}
else
if
((
!
gl
.
utils
.
isInViewport
(
this
.
$upBuildTrace
.
get
(
0
))
&&
gl
.
utils
.
isInViewport
(
this
.
$downBuildTrace
.
get
(
0
)))
||
(
this
.
$buildRefreshAnimation
.
is
(
'
:visible
'
)
&&
gl
.
utils
.
isInViewport
(
this
.
$buildRefreshAnimation
.
get
(
0
))))
{
// User is at Bottom of Build Log
this
.
$scrollTopBtn
.
show
();
this
.
$scrollBottomBtn
.
hide
();
// Show and Reposition Autoscroll Status Indicator
this
.
$autoScrollContainer
.
css
({
top
:
this
.
$body
.
outerHeight
()
-
AUTO_SCROLL_OFFSET
,
}).
show
();
this
.
$autoScrollStatusText
.
addClass
(
'
animate
'
);
}
else
if
(
gl
.
utils
.
isInViewport
(
this
.
$upBuildTrace
.
get
(
0
))
&&
gl
.
utils
.
isInViewport
(
this
.
$downBuildTrace
.
get
(
0
)))
{
// Build Log height is small
this
.
$scrollTopBtn
.
hide
();
this
.
$scrollBottomBtn
.
hide
();
// Hide Autoscroll Status Indicator
this
.
$autoScrollContainer
.
hide
();
this
.
$autoScrollStatusText
.
removeClass
(
'
animate
'
);
}
if
(
this
.
buildStatus
===
'
running
'
||
this
.
buildStatus
===
'
pending
'
)
{
// Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise.
this
.
$autoScrollStatus
.
data
(
'
state
'
,
gl
.
utils
.
isInViewport
(
this
.
$buildRefreshAnimation
.
get
(
0
))
?
'
enabled
'
:
'
disabled
'
,
);
}
};
Build
.
prototype
.
shouldHideSidebarForViewport
=
function
()
{
const
bootstrapBreakpoint
=
this
.
bp
.
getBreakpointSize
();
return
bootstrapBreakpoint
===
'
xs
'
||
bootstrapBreakpoint
===
'
sm
'
;
};
Build
.
prototype
.
toggleSidebar
=
function
(
shouldHide
)
{
const
shouldShow
=
typeof
shouldHide
===
'
boolean
'
?
!
shouldHide
:
undefined
;
const
shouldShow
=
!
shouldHide
;
this
.
$buildScroll
.
toggleClass
(
'
sidebar-expanded
'
,
shouldShow
)
this
.
$buildTrace
.
toggleClass
(
'
sidebar-expanded
'
,
shouldShow
)
.
toggleClass
(
'
sidebar-collapsed
'
,
shouldHide
);
this
.
$truncatedInfo
.
toggleClass
(
'
sidebar-expanded
'
,
shouldShow
)
.
toggleClass
(
'
sidebar-collapsed
'
,
shouldHide
);
this
.
$sidebar
.
toggleClass
(
'
right-sidebar-expanded
'
,
shouldShow
)
this
.
$sidebar
.
toggleClass
(
'
right-sidebar-expanded
'
,
shouldShow
)
.
toggleClass
(
'
right-sidebar-collapsed
'
,
shouldHide
);
};
Build
.
prototype
.
sidebarOnResize
=
function
()
{
this
.
toggleSidebar
(
this
.
shouldHideSidebarForViewport
());
this
.
verifyTopPosition
();
if
(
this
.
$scrollContainer
.
getNiceScroll
(
0
))
{
this
.
toggleScroll
();
}
};
Build
.
prototype
.
sidebarOnClick
=
function
()
{
...
...
@@ -301,24 +287,5 @@ window.Build = (function () {
this
.
populateJobs
(
stage
);
};
Build
.
prototype
.
stepTrace
=
function
(
e
)
{
e
.
preventDefault
();
const
$currentTarget
=
$
(
e
.
currentTarget
);
$
.
scrollTo
(
$currentTarget
.
attr
(
'
href
'
),
{
offset
:
0
,
});
};
Build
.
prototype
.
initAffixTruncatedInfo
=
function
()
{
const
offsetTop
=
this
.
$buildTrace
.
offset
().
top
;
this
.
$truncatedInfo
.
affix
({
offset
:
{
top
:
offsetTop
,
},
});
};
return
Build
;
})();
app/assets/stylesheets/pages/builds.scss
View file @
f47e86fe
...
...
@@ -29,65 +29,53 @@
}
}
.build-page
{
pre
.trace
{
background
:
$builds-trace-bg
;
color
:
$white-light
;
font-family
:
$monospace_font
;
white-space
:
pre-wrap
;
overflow
:
auto
;
overflow-y
:
hidden
;
font-size
:
12px
;
.fa-spinner
{
font-size
:
24px
;
margin-left
:
20px
;
}
}
.environment-information
{
background-color
:
$gray-light
;
border
:
1px
solid
$border-color
;
padding
:
12px
$gl-padding
;
border-radius
:
$border-radius-default
;
@keyframes
blinking-scroll-button
{
0
%
{
opacity
:
0
.2
;
}
25
%
{
opacity
:
0
.5
;
}
50
%
{
opacity
:
0
.7
;
}
100
%
{
opacity
:
1
;
}
}
svg
{
position
:
relative
;
top
:
1px
;
margin-right
:
5px
;
}
.build-page
{
.sticky
{
position
:
absolute
;
left
:
0
;
right
:
0
;
}
.truncated-info
{
text-align
:
center
;
border-bottom
:
1px
solid
;
background-color
:
$black
;
height
:
45px
;
padding
:
15px
;
.build-trace-container
{
position
:
absolute
;
top
:
225px
;
left
:
15px
;
bottom
:
10px
;
background
:
$black
;
color
:
$gray-darkest
;
font-family
:
$monospace_font
;
font-size
:
12px
;
&
.
affix
{
top
:
0
;
&
.
sidebar-expanded
{
right
:
305px
;
}
// with sidebar
&
.affix.sidebar-expanded
{
right
:
312px
;
left
:
22px
;
&
.sidebar-collapsed
{
right
:
16px
;
}
// without sidebar
&
.affix.sidebar-collapsed
{
right
:
20px
;
left
:
20px
;
code
{
background
:
$black
;
color
:
$gray-darkest
;
}
&
.affix-top
{
position
:
absolute
;
.top-bar
{
top
:
0
;
height
:
35px
;
display
:
flex
;
justify-content
:
flex-end
;
border-bottom
:
1px
outset
$white-light
;
.truncated-info
{
margin
:
0
auto
;
right
:
5px
;
left
:
5px
;
}
align-self
:
center
;
.truncated-info-size
{
margin
:
0
5px
;
...
...
@@ -99,59 +87,82 @@
text-decoration
:
underline
;
}
}
}
}
.scroll-controls
{
height
:
100%
;
.controllers
{
display
:
flex
;
align-self
:
center
;
font-size
:
15px
;
.scroll-step
{
width
:
31px
;
margin
:
0
0
0
auto
;
svg
{
height
:
15px
;
display
:
block
;
fill
:
$white-light
;
}
.scroll-link
,
.autoscroll-container
{
right
:
25
px
;
z-index
:
1
;
a
,
.btn-scroll
{
margin
:
0
8
px
;
color
:
$white-light
;
}
.scroll-link
{
position
:
fixed
;
display
:
block
;
margin-bottom
:
10px
;
.btn-scroll.animate
{
.first-triangle
{
animation
:
blinking-scroll-button
1s
ease
infinite
;
animation-delay
:
.3s
;
}
&
.scroll-top
.gitlab-icon-scroll-up-hover
,
&
.scroll-top
:hover
.gitlab-icon-scroll-up
,
&
.scroll-bottom
.gitlab-icon-scroll-down-hover
,
&
.scroll-bottom
:hover
.gitlab-icon-scroll-down
{
display
:
none
;
.second-triangle
{
animation
:
blinking-scroll-button
1s
ease
infinite
;
animation-delay
:
.2s
;
}
&
.scroll-top
:hover
.gitlab-icon-scroll-up-hover
,
&
.scroll-bottom
:hover
.gitlab-icon-scroll-down-hover
{
display
:
inline-block
;
.third-triangle
{
animation
:
blinking-scroll-button
1s
ease
infinite
;
}
&
.scroll-top
{
top
:
10px
;
&
:disabled
{
opacity
:
1
;
}
}
&
.scroll-bottom
{
bottom
:
-2px
;
.btn-scroll
:disabled
{
opacity
:
0
.35
;
cursor
:
not
-
allowed
;
}
}
}
.autoscroll-container
{
position
:
absolute
;
.bash
{
top
:
35px
;
left
:
10px
;
bottom
:
0
;
overflow-y
:
hidden
;
padding-bottom
:
20px
;
padding-right
:
20px
;
}
&
.sidebar-expanded
{
.environment-information
{
background-color
:
$gray-light
;
border
:
1px
solid
$border-color
;
padding
:
12px
$gl-padding
;
border-radius
:
$border-radius-default
;
.scroll-link
,
.autoscroll-container
{
right
:
(
$gutter_width
+
(
$gl-padding
*
2
));
svg
{
position
:
relative
;
top
:
1px
;
margin-right
:
5px
;
}
}
.build-loader-animation
{
position
:
relative
;
width
:
6px
;
height
:
6px
;
margin
:
auto
auto
12px
2px
;
border-radius
:
50%
;
animation
:
blinking-dots
1s
linear
infinite
;
}
}
.status-message
{
...
...
@@ -223,32 +234,6 @@
}
}
.build-trace
{
background
:
$black
;
color
:
$gray-darkest
;
white-space
:
pre
;
overflow-x
:
auto
;
font-size
:
12px
;
position
:
relative
;
.fa-spinner
{
font-size
:
24px
;
}
.bash
{
display
:
block
;
}
.build-loader-animation
{
position
:
relative
;
width
:
6px
;
height
:
6px
;
margin
:
auto
auto
12px
2px
;
border-radius
:
50%
;
animation
:
blinking-dots
1s
linear
infinite
;
}
}
.right-sidebar.build-sidebar
{
padding
:
$gl-padding
0
;
...
...
app/views/projects/builds/_sidebar.html.haml
View file @
f47e86fe
...
...
@@ -68,15 +68,8 @@
-
elsif
@build
.
runner
\##{@build.runner.id}
.btn-group.btn-group-justified
{
role: :group
}
-
if
@build
.
has_trace?
=
link_to
'Raw'
,
raw_namespace_project_build_path
(
@project
.
namespace
,
@project
,
@build
),
class:
'btn btn-sm btn-default'
-
if
@build
.
active?
=
link_to
"Cancel"
,
cancel_namespace_project_build_path
(
@project
.
namespace
,
@project
,
@build
),
class:
'btn btn-sm btn-default'
,
method: :post
-
if
can?
(
current_user
,
:update_build
,
@project
)
&&
@build
.
erasable?
=
link_to
erase_namespace_project_build_path
(
@project
.
namespace
,
@project
,
@build
),
class:
"btn btn-sm btn-default"
,
method: :post
,
data:
{
confirm:
"Are you sure you want to erase this build?"
}
do
Erase
-
if
@build
.
trigger_request
.build-widget
...
...
app/views/projects/builds/show.html.haml
View file @
f47e86fe
...
...
@@ -8,7 +8,7 @@
-
if
@build
.
stuck?
-
unless
@build
.
any_runners_online?
.bs-callout.bs-callout-warning
.bs-callout.bs-callout-warning
.js-build-stuck
%p
-
if
no_runners_for_project?
(
@build
.
project
)
This job is stuck, because the project doesn't have any runners online assigned to it.
...
...
@@ -26,7 +26,7 @@
Runners page
-
if
@build
.
starts_environment?
.prepend-top-default
.prepend-top-default
.js-environment-container
.environment-information
-
if
@build
.
outdated_deployment?
=
ci_icon_for_status
(
'success_with_warnings'
)
...
...
@@ -47,39 +47,51 @@
-
if
environment
.
try
(
:last_deployment
)
and will overwrite the
#{
deployment_link
(
environment
.
last_deployment
,
text:
'latest deployment'
)
}
.prepend-top-default
.prepend-top-default
.js-build-erased
-
if
@build
.
erased?
.erased.alert.alert-warning
-
if
@build
.
erased_by_user?
Job has been erased by
#{
link_to
(
@build
.
erased_by_name
,
user_path
(
@build
.
erased_by
))
}
#{
time_ago_with_tooltip
(
@build
.
erased_at
)
}
-
else
Job has been erased
#{
time_ago_with_tooltip
(
@build
.
erased_at
)
}
-
else
#js-build-scroll
.scroll-controls
.scroll-step
%a
.scroll-link.scroll-top
{
href:
'#up-build-trace'
,
id:
'scroll-top'
,
title:
'Scroll to top'
}
=
custom_icon
(
'scroll_up'
)
=
custom_icon
(
'scroll_up_hover_active'
)
%a
.scroll-link.scroll-bottom
{
href:
'#down-build-trace'
,
id:
'scroll-bottom'
,
title:
'Scroll to bottom'
}
=
custom_icon
(
'scroll_down'
)
=
custom_icon
(
'scroll_down_hover_active'
)
-
if
@build
.
active?
.autoscroll-container
%span
.status-message
#autoscroll-status
{
data:
{
state:
'disabled'
}
}
%span
.status-text
Autoscroll active
%i
.status-icon
=
custom_icon
(
'scroll_down_hover_active'
)
#up-build-trace
%pre
.build-trace
#build-trace
.prepend-top-default
.build-trace-container
#build-trace
.top-bar.sticky
.js-truncated-info.truncated-info.hidden
<
Showing
last
%span
.js-truncated-info-size.truncated-info-size
><
KiB
of
log
-
%a
.js-raw-link.raw-link
{
:href
=>
raw_namespace_project_build_path
(
@project
.
namespace
,
@project
,
@build
)
}><
Complete
Raw
%code
.bash.js-build-output
.build-loader-animation.js-build-refresh
%a
.js-raw-link.raw-link
{
href:
raw_namespace_project_build_path
(
@project
.
namespace
,
@project
,
@build
)
}><
Complete
Raw
.controllers
-
if
@build
.
has_trace?
=
link_to
raw_namespace_project_build_path
(
@project
.
namespace
,
@project
,
@build
),
title:
'Open raw trace'
,
data:
{
placement:
'top'
,
container:
'body'
},
class:
'js-raw-link-controller has-tooltip'
do
=
icon
(
'download'
)
-
if
can?
(
current_user
,
:update_build
,
@project
)
&&
@build
.
erasable?
=
link_to
erase_namespace_project_build_path
(
@project
.
namespace
,
@project
,
@build
),
method: :post
,
data:
{
confirm:
'Are you sure you want to erase this build?'
,
placement:
'top'
,
container:
'body'
},
title:
'Erase Build'
,
class:
'has-tooltip js-erase-link'
do
=
icon
(
'trash'
)
#down-build-trace
%button
.js-scroll-up.btn-scroll.btn-transparent.btn-blank.has-tooltip
{
type:
'button'
,
disabled:
true
,
title:
'Scroll Up'
,
data:
{
placement:
'top'
,
container:
'body'
}
}
=
custom_icon
(
'scroll_up'
)
%button
.js-scroll-down.btn-scroll.btn-transparent.btn-blank.has-tooltip
{
type:
'button'
,
disabled:
true
,
title:
'Scroll Down'
,
data:
{
placement:
'top'
,
container:
'body'
}
}
=
custom_icon
(
'scroll_down'
)
.bash.sticky.js-scroll-container
%code
.js-build-output
.build-loader-animation.js-build-refresh
=
render
"sidebar"
...
...
app/views/shared/icons/_scroll_down.svg
View file @
f47e86fe
<svg
width=
"16"
height=
"33"
class=
"gitlab-icon-scroll-down"
viewBox=
"0 0 16 33"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
fill=
"#ffffff"
d=
"M1.385 5.534v12.47a4.145 4.145 0 0 0 4.144 4.15h4.942a4.151 4.151 0 0 0 4.144-4.15V5.535a4.145 4.145 0 0 0-4.144-4.15H5.53a4.151 4.151 0 0 0-4.144 4.15zM8.88 30.27v-4.351a.688.688 0 0 0-.69-.688.687.687 0 0 0-.69.688v4.334l-1.345-1.346a.69.69 0 0 0-.976.976l2.526 2.526a.685.685 0 0 0 .494.2.685.685 0 0 0 .493-.2l2.526-2.526a.69.69 0 1 0-.976-.976L8.88 30.27zM0 5.534A5.536 5.536 0 0 1 5.529 0h4.942A5.53 5.53 0 0 1 16 5.534v12.47a5.536 5.536 0 0 1-5.529 5.534H5.53A5.53 5.53 0 0 1 0 18.005V5.534zm7 1.01a1 1 0 1 1 2 0v2.143a1 1 0 1 1-2 0V6.544z"
fill-rule=
"evenodd"
/>
<svg
width=
"12"
height=
"16"
viewBox=
"0 0 12 16"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
class=
"first-triangle"
d=
"M1.048 14.155a.508.508 0 0 0-.32.105c-.091.07-.136.154-.136.25v.71c0 .095.045.178.135.249.09.07.197.105.321.105h10.043c.124 0 .23-.035.321-.105.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"
/>
<path
class=
"second-triangle"
d=
"M.687 8.027c-.09-.087-.122-.16-.093-.22.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 12.91a.458.458 0 0 1-.136.089h-.37a.626.626 0 0 1-.136-.09"
/>
<path
class=
"third-triangle"
d=
"M.687 1.027C.597.94.565.867.594.807c.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 5.91A.458.458 0 0 1 6.257 6h-.37a.626.626 0 0 1-.136-.09"
/>
</svg>
app/views/shared/icons/_scroll_down_hover_active.svg
deleted
100644 → 0
View file @
763a3acd
<svg
width=
"16"
height=
"33"
class=
"gitlab-icon-scroll-down-hover"
viewBox=
"0 0 16 33"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
fill=
"#ffffff"
d=
"M8.88 30.27v-4.351a.688.688 0 0 0-.69-.688.687.687 0 0 0-.69.688v4.334l-1.345-1.346a.69.69 0 0 0-.976.976l2.526 2.526a.685.685 0 0 0 .494.2.685.685 0 0 0 .493-.2l2.526-2.526a.69.69 0 1 0-.976-.976L8.88 30.27zM0 5.534A5.536 5.536 0 0 1 5.529 0h4.942A5.53 5.53 0 0 1 16 5.534v12.47a5.536 5.536 0 0 1-5.529 5.534H5.53A5.53 5.53 0 0 1 0 18.005V5.534zm7 1.01a1 1 0 1 1 2 0v2.143a1 1 0 1 1-2 0V6.544z"
fill-rule=
"evenodd"
/>
</svg>
app/views/shared/icons/_scroll_up.svg
View file @
f47e86fe
<svg
width=
"16"
height=
"33"
class=
"gitlab-icon-scroll-up"
viewBox=
"0 0 16 33"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
fill=
"#ffffff"
d=
"M1.385 14.534v12.47a4.145 4.145 0 0 0 4.144 4.15h4.942a4.151 4.151 0 0 0 4.144-4.15v-12.47a4.145 4.145 0 0 0-4.144-4.15H5.53a4.151 4.151 0 0 0-4.144 4.15zM8.88 2.609V6.96a.688.688 0 0 1-.69.688.687.687 0 0 1-.69-.688V2.627L6.155 3.972a.69.69 0 0 1-.976-.976L7.705.47a.685.685 0 0 1 .494-.2.685.685 0 0 1 .493.2l2.526 2.526a.69.69 0 1 1-.976.976L8.88 2.609zM0 14.534A5.536 5.536 0 0 1 5.529 9h4.942A5.53 5.53 0 0 1 16 14.534v12.47a5.536 5.536 0 0 1-5.529 5.534H5.53A5.53 5.53 0 0 1 0 27.005V14.534zm7 1.01a1 1 0 1 1 2 0v2.143a1 1 0 1 1-2 0v-2.143z"
fill-rule=
"evenodd"
/>
</svg>
<svg
width=
"12"
height=
"16"
viewBox=
"0 0 12 16"
xmlns=
"http://www.w3.org/2000/svg"
><path
d=
"M1.048 1.845a.508.508 0 0 1-.32-.105c-.091-.07-.136-.154-.136-.25V.78c0-.095.045-.178.135-.249a.508.508 0 0 1 .321-.105h10.043c.124 0 .23.035.321.105.09.07.136.154.136.25v.71c0 .095-.045.178-.136.249a.508.508 0 0 1-.32.105"
/><path
d=
"M.687 7.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 3.09A.458.458 0 0 0 6.257 3h-.37a.626.626 0 0 0-.136.09"
/><path
d=
"M.687 14.973c-.09.087-.122.16-.093.22.028.06.104.09.228.09h10.5c.123 0 .2-.03.228-.09.029-.06-.002-.133-.093-.22L6.393 10.09A.458.458 0 0 0 6.257 10h-.37a.626.626 0 0 0-.136.09"
/></svg>
app/views/shared/icons/_scroll_up_hover_active.svg
deleted
100644 → 0
View file @
763a3acd
<svg
width=
"16"
height=
"33"
class=
"gitlab-icon-scroll-up-hover"
viewBox=
"0 0 16 33"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
fill=
"#ffffff"
d=
"M8.88 2.646l1.362 1.362a.69.69 0 0 0 .976-.976L8.692.507A.685.685 0 0 0 8.2.306a.685.685 0 0 0-.494.2L5.179 3.033a.69.69 0 1 0 .976.976L7.5 2.663v4.179c0 .38.306.688.69.688.381 0 .69-.306.69-.688V2.646zM0 14.534A5.536 5.536 0 0 1 5.529 9h4.942A5.53 5.53 0 0 1 16 14.534v12.47a5.536 5.536 0 0 1-5.529 5.534H5.53A5.53 5.53 0 0 1 0 27.005V14.534zm7 1.01a1 1 0 1 1 2 0v2.143a1 1 0 1 1-2 0v-2.143z"
fill-rule=
"evenodd"
/>
</svg>
spec/features/projects/builds_spec.rb
View file @
f47e86fe
...
...
@@ -190,7 +190,7 @@ feature 'Builds', :feature do
end
it
do
expect
(
page
).
to
have_
link
'Raw'
expect
(
page
).
to
have_
css
(
'.js-raw-link'
)
end
end
...
...
@@ -369,14 +369,14 @@ feature 'Builds', :feature do
end
end
describe
'GET /:project/builds/:id/raw'
do
describe
'GET /:project/builds/:id/raw'
,
:js
do
context
'access source'
do
context
'build from project'
do
before
do
Capybara
.
current_session
.
driver
.
header
(
'X-Sendfile-Type'
,
'X-Sendfile'
)
Capybara
.
current_session
.
driver
.
header
s
=
{
'X-Sendfile-Type'
=>
'X-Sendfile'
}
build
.
run!
visit
namespace_project_build_path
(
project
.
namespace
,
project
,
build
)
page
.
within
(
'.js-build-sidebar'
)
{
click_link
'Raw'
}
find
(
'.js-raw-link-controller'
).
click
()
end
it
'sends the right headers'
do
...
...
@@ -388,7 +388,7 @@ feature 'Builds', :feature do
context
'build from other project'
do
before
do
Capybara
.
current_session
.
driver
.
header
(
'X-Sendfile-Type'
,
'X-Sendfile'
)
Capybara
.
current_session
.
driver
.
header
s
=
{
'X-Sendfile-Type'
=>
'X-Sendfile'
}
build2
.
run!
visit
raw_namespace_project_build_path
(
project
.
namespace
,
project
,
build2
)
end
...
...
@@ -403,7 +403,7 @@ feature 'Builds', :feature do
let
(
:existing_file
)
{
Tempfile
.
new
(
'existing-trace-file'
).
path
}
before
do
Capybara
.
current_session
.
driver
.
header
(
'X-Sendfile-Type'
,
'X-Sendfile'
)
Capybara
.
current_session
.
driver
.
header
s
=
{
'X-Sendfile-Type'
=>
'X-Sendfile'
}
build
.
run!
...
...
@@ -413,13 +413,13 @@ feature 'Builds', :feature do
visit
namespace_project_build_path
(
project
.
namespace
,
project
,
build
)
end
context
'when build has trace in file'
do
context
'when build has trace in file'
,
:js
do
let
(
:paths
)
do
[
existing_file
]
end
before
do
page
.
within
(
'.js-build-sidebar'
)
{
click_link
'Raw'
}
find
(
'.js-raw-link-controller'
).
click
()
end
it
'sends the right headers'
do
...
...
@@ -433,7 +433,7 @@ feature 'Builds', :feature do
let
(
:paths
)
{
[]
}
it
'sends the right headers'
do
expect
(
page
.
status_code
).
not_to
have_
link
(
'Raw
'
)
expect
(
page
.
status_code
).
not_to
have_
selector
(
'.js-raw-link-controller
'
)
end
end
end
...
...
spec/javascripts/build_spec.js
View file @
f47e86fe
...
...
@@ -14,7 +14,6 @@ describe('Build', () => {
beforeEach
(()
=>
{
loadFixtures
(
'
builds/build-with-artifacts.html.raw
'
);
spyOn
(
$
,
'
ajax
'
);
});
describe
(
'
class constructor
'
,
()
=>
{
...
...
@@ -33,7 +32,6 @@ describe('Build', () => {
it
(
'
copies build options
'
,
function
()
{
expect
(
this
.
build
.
pageUrl
).
toBe
(
BUILD_URL
);
expect
(
this
.
build
.
buildUrl
).
toBe
(
`
${
BUILD_URL
}
.json`
);
expect
(
this
.
build
.
buildStatus
).
toBe
(
'
success
'
);
expect
(
this
.
build
.
buildStage
).
toBe
(
'
test
'
);
expect
(
this
.
build
.
state
).
toBe
(
''
);
...
...
@@ -65,27 +63,14 @@ describe('Build', () => {
});
describe
(
'
running build
'
,
()
=>
{
beforeEach
(
function
()
{
this
.
build
=
new
Build
();
});
it
(
'
updates the build trace on an interval
'
,
function
()
{
const
deferred1
=
$
.
Deferred
();
const
deferred2
=
$
.
Deferred
();
const
deferred3
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValues
(
deferred1
.
promise
(),
deferred2
.
promise
(),
deferred3
.
promise
());
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
jasmine
.
clock
().
tick
(
4001
);
expect
(
$
.
ajax
.
calls
.
count
()).
toBe
(
1
);
// We have to do it this way to prevent Webpack to fail to compile
// when destructuring assignments and reusing
// the same variables names inside the same scope
let
args
=
$
.
ajax
.
calls
.
argsFor
(
0
)[
0
];
expect
(
args
.
url
).
toBe
(
`
${
BUILD_URL
}
/trace.json`
);
expect
(
args
.
dataType
).
toBe
(
'
json
'
);
expect
(
args
.
success
).
toEqual
(
jasmine
.
any
(
Function
));
args
.
success
.
call
(
$
,
{
deferred1
.
resolve
({
html
:
'
<span>Update<span>
'
,
status
:
'
running
'
,
state
:
'
newstate
'
,
...
...
@@ -93,20 +78,9 @@ describe('Build', () => {
complete
:
false
,
});
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
expect
(
this
.
build
.
state
).
toBe
(
'
newstate
'
);
deferred2
.
resolve
();
jasmine
.
clock
().
tick
(
4001
);
expect
(
$
.
ajax
.
calls
.
count
()).
toBe
(
3
);
args
=
$
.
ajax
.
calls
.
argsFor
(
2
)[
0
];
expect
(
args
.
url
).
toBe
(
`
${
BUILD_URL
}
/trace.json`
);
expect
(
args
.
dataType
).
toBe
(
'
json
'
);
expect
(
args
.
data
.
state
).
toBe
(
'
newstate
'
);
expect
(
args
.
success
).
toEqual
(
jasmine
.
any
(
Function
));
args
.
success
.
call
(
$
,
{
deferred3
.
resolve
({
html
:
'
<span>More</span>
'
,
status
:
'
running
'
,
state
:
'
finalstate
'
,
...
...
@@ -114,58 +88,77 @@ describe('Build', () => {
complete
:
true
,
});
this
.
build
=
new
Build
();
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
expect
(
this
.
build
.
state
).
toBe
(
'
newstate
'
);
jasmine
.
clock
().
tick
(
4001
);
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/UpdateMore/
);
expect
(
this
.
build
.
state
).
toBe
(
'
finalstate
'
);
});
it
(
'
replaces the entire build trace
'
,
()
=>
{
const
deferred1
=
$
.
Deferred
();
const
deferred2
=
$
.
Deferred
();
const
deferred3
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValues
(
deferred1
.
promise
(),
deferred2
.
promise
(),
deferred3
.
promise
());
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
jasmine
.
clock
().
tick
(
4001
);
let
args
=
$
.
ajax
.
calls
.
argsFor
(
0
)[
0
];
args
.
success
.
call
(
$
,
{
html
:
'
<span>Update</span>
'
,
deferred1
.
resolve
({
html
:
'
<span>Update<span>
'
,
status
:
'
running
'
,
append
:
false
,
complete
:
false
,
});
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
deferred2
.
resolve
(
);
jasmine
.
clock
().
tick
(
4001
);
args
=
$
.
ajax
.
calls
.
argsFor
(
2
)[
0
];
args
.
success
.
call
(
$
,
{
deferred3
.
resolve
({
html
:
'
<span>Different</span>
'
,
status
:
'
running
'
,
append
:
false
,
});
this
.
build
=
new
Build
();
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Update/
);
jasmine
.
clock
().
tick
(
4001
);
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
not
.
toMatch
(
/Update/
);
expect
(
$
(
'
#build-trace .js-build-output
'
).
text
()).
toMatch
(
/Different/
);
});
it
(
'
reloads the page when the build is done
'
,
()
=>
{
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
const
deferred
=
$
.
Deferred
();
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
success
.
call
(
$
,
{
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Final</span>
'
,
status
:
'
passed
'
,
append
:
true
,
complete
:
true
,
});
this
.
build
=
new
Build
();
expect
(
gl
.
utils
.
visitUrl
).
toHaveBeenCalledWith
(
BUILD_URL
);
});
});
describe
(
'
truncated information
'
,
()
=>
{
describe
(
'
when size is less than total
'
,
()
=>
{
it
(
'
shows information about truncated log
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
const
deferred
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
success
.
call
(
$
,
{
deferred
.
resolve
(
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
...
...
@@ -173,15 +166,18 @@ describe('Build', () => {
total
:
100
,
});
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
not
.
toContain
(
'
hidden
'
);
});
it
(
'
shows the size in KiB
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
const
size
=
50
;
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
const
deferred
=
$
.
Deferred
();
success
.
call
(
$
,
{
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
...
...
@@ -189,15 +185,23 @@ describe('Build', () => {
total
:
100
,
});
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
bytesToKiB
(
size
)}
`
);
});
it
(
'
shows incremented size
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
let
args
=
$
.
ajax
.
calls
.
argsFor
(
0
)[
0
];
args
.
success
.
call
(
$
,
{
const
deferred1
=
$
.
Deferred
();
const
deferred2
=
$
.
Deferred
();
const
deferred3
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValues
(
deferred1
.
promise
(),
deferred2
.
promise
(),
deferred3
.
promise
());
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
deferred1
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
...
...
@@ -205,13 +209,17 @@ describe('Build', () => {
total
:
100
,
});
deferred2
.
resolve
();
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
bytesToKiB
(
50
)}
`
);
jasmine
.
clock
().
tick
(
4001
);
args
=
$
.
ajax
.
calls
.
argsFor
(
2
)[
0
];
args
.
success
.
call
(
$
,
{
deferred3
.
resolve
(
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
true
,
...
...
@@ -225,10 +233,11 @@ describe('Build', () => {
});
it
(
'
renders the raw link
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
const
deferred
=
$
.
Deferred
(
);
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
success
.
call
(
$
,
{
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
...
...
@@ -236,6 +245,8 @@ describe('Build', () => {
total
:
100
,
});
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-raw-link
'
).
textContent
.
trim
(),
).
toContain
(
'
Complete Raw
'
);
...
...
@@ -244,10 +255,11 @@ describe('Build', () => {
describe
(
'
when size is equal than total
'
,
()
=>
{
it
(
'
does not show the trunctated information
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
const
deferred
=
$
.
Deferred
(
);
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
success
.
call
(
$
,
{
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
...
...
@@ -255,10 +267,44 @@ describe('Build', () => {
total
:
100
,
});
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
toContain
(
'
hidden
'
);
});
});
});
describe
(
'
output trace
'
,
()
=>
{
beforeEach
(()
=>
{
const
deferred
=
$
.
Deferred
();
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
:
50
,
total
:
100
,
});
this
.
build
=
new
Build
();
});
it
(
'
should render trace controls
'
,
()
=>
{
const
controllers
=
document
.
querySelector
(
'
.controllers
'
);
expect
(
controllers
.
querySelector
(
'
.js-raw-link-controller
'
)).
toBeDefined
();
expect
(
controllers
.
querySelector
(
'
.js-erase-link
'
)).
toBeDefined
();
expect
(
controllers
.
querySelector
(
'
.js-scroll-up
'
)).
toBeDefined
();
expect
(
controllers
.
querySelector
(
'
.js-scroll-down
'
)).
toBeDefined
();
});
it
(
'
should render received output
'
,
()
=>
{
expect
(
document
.
querySelector
(
'
.js-build-output
'
).
innerHTML
,
).
toEqual
(
'
<span>Update</span>
'
);
});
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment