Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
李少辉-开发者
gitlab-foss
提交
cd023d42
G
gitlab-foss
项目概览
李少辉-开发者
/
gitlab-foss
通知
15
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
gitlab-foss
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
cd023d42
编写于
5月 30, 2017
作者:
F
Filipa Lacerda
提交者:
Phil Hughes
5月 30, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Update looks job log
上级
763a3acd
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
480 addition
and
483 deletion
+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
未找到文件。
app/assets/javascripts/build.js
浏览文件 @
cd023d42
...
...
@@ -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,141 +206,30 @@ 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
()
{
...
...
@@ -257,18 +238,23 @@ window.Build = (function () {
};
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
浏览文件 @
cd023d42
...
...
@@ -29,129 +29,140 @@
}
}
.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
;
margin
:
0
auto
;
right
:
5p
x
;
left
:
5px
;
}
height
:
35px
;
display
:
fle
x
;
justify-content
:
flex-end
;
border-bottom
:
1px
outset
$white-light
;
.truncated-info-size
{
margin
:
0
5px
;
}
.truncated-info
{
margin
:
0
auto
;
align-self
:
center
;
.raw-link
{
color
:
inherit
;
margin-left
:
5px
;
text-decoration
:
underline
;
.truncated-info-size
{
margin
:
0
5px
;
}
.raw-link
{
color
:
inherit
;
margin-left
:
5px
;
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
浏览文件 @
cd023d42
...
...
@@ -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
浏览文件 @
cd023d42
...
...
@@ -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
浏览文件 @
cd023d42
<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
已删除
100644 → 0
浏览文件 @
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
浏览文件 @
cd023d42
<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
已删除
100644 → 0
浏览文件 @
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
浏览文件 @
cd023d42
...
...
@@ -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
浏览文件 @
cd023d42
...
...
@@ -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
'
);
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
));
deferred2
.
resolve
();
args
.
success
.
call
(
$
,
{
deferred3
.
resolve
(
{
html
:
'
<span>More</span>
'
,
status
:
'
running
'
,
state
:
'
finalstate
'
,
...
...
@@ -114,150 +88,222 @@ 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
);
success
.
call
(
$
,
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
:
50
,
total
:
100
,
});
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
not
.
toContain
(
'
hidden
'
);
describe
(
'
truncated information
'
,
()
=>
{
describe
(
'
when size is less than total
'
,
()
=>
{
it
(
'
shows information about truncated log
'
,
()
=>
{
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
const
deferred
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
:
50
,
total
:
100
,
});
it
(
'
shows the size in KiB
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
const
size
=
50
;
success
.
call
(
$
,
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
,
total
:
100
,
});
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
bytesToKiB
(
size
)}
`
);
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
not
.
toContain
(
'
hidden
'
);
});
it
(
'
shows the size in KiB
'
,
()
=>
{
const
size
=
50
;
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
const
deferred
=
$
.
Deferred
();
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
,
total
:
100
,
});
it
(
'
shows incremented size
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
let
args
=
$
.
ajax
.
calls
.
argsFor
(
0
)[
0
];
args
.
success
.
call
(
$
,
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
:
50
,
total
:
100
,
});
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
(
$
,
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
true
,
size
:
10
,
total
:
100
,
});
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
bytesToKiB
(
60
)}
`
);
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
bytesToKiB
(
size
)}
`
);
});
it
(
'
shows incremented size
'
,
()
=>
{
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
,
size
:
50
,
total
:
100
,
});
it
(
'
renders the raw link
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
success
.
call
(
$
,
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
:
50
,
total
:
100
,
});
expect
(
document
.
querySelector
(
'
.js-raw-link
'
).
textContent
.
trim
(),
).
toContain
(
'
Complete Raw
'
);
deferred2
.
resolve
();
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
bytesToKiB
(
50
)}
`
);
jasmine
.
clock
().
tick
(
4001
);
deferred3
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
true
,
size
:
10
,
total
:
100
,
});
expect
(
document
.
querySelector
(
'
.js-truncated-info-size
'
).
textContent
.
trim
(),
).
toEqual
(
`
${
bytesToKiB
(
60
)}
`
);
});
describe
(
'
when size is equal than total
'
,
()
=>
{
it
(
'
does not show the trunctated information
'
,
()
=>
{
jasmine
.
clock
().
tick
(
4001
);
const
[{
success
}]
=
$
.
ajax
.
calls
.
argsFor
(
0
);
it
(
'
renders the raw link
'
,
()
=>
{
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
,
});
success
.
call
(
$
,
{
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
:
100
,
total
:
100
,
});
this
.
build
=
new
Build
();
expect
(
document
.
querySelector
(
'
.js-truncated-info
'
).
classList
).
toContain
(
'
hidden
'
);
expect
(
document
.
querySelector
(
'
.js-raw-link
'
).
textContent
.
trim
(),
).
toContain
(
'
Complete Raw
'
);
});
});
describe
(
'
when size is equal than total
'
,
()
=>
{
it
(
'
does not show the trunctated information
'
,
()
=>
{
const
deferred
=
$
.
Deferred
();
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
spyOn
(
$
,
'
ajax
'
).
and
.
returnValue
(
deferred
.
promise
());
deferred
.
resolve
({
html
:
'
<span>Update</span>
'
,
status
:
'
success
'
,
append
:
false
,
size
:
100
,
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>
'
);
});
});
});
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录