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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
fc5537c3
Commit
fc5537c3
authored
May 30, 2018
by
Phil Hughes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
EE port of ide-jobs-list-components
parent
121e0edb
Changes
44
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
1571 additions
and
547 deletions
+1571
-547
app/assets/javascripts/api.js
app/assets/javascripts/api.js
+0
-16
app/assets/javascripts/ide/components/ide.vue
app/assets/javascripts/ide/components/ide.vue
+6
-0
app/assets/javascripts/ide/components/ide_status_bar.vue
app/assets/javascripts/ide/components/ide_status_bar.vue
+8
-7
app/assets/javascripts/ide/components/jobs/item.vue
app/assets/javascripts/ide/components/jobs/item.vue
+46
-0
app/assets/javascripts/ide/components/jobs/list.vue
app/assets/javascripts/ide/components/jobs/list.vue
+44
-0
app/assets/javascripts/ide/components/jobs/stage.vue
app/assets/javascripts/ide/components/jobs/stage.vue
+108
-0
app/assets/javascripts/ide/components/panes/right.vue
app/assets/javascripts/ide/components/panes/right.vue
+65
-0
app/assets/javascripts/ide/components/pipelines/list.vue
app/assets/javascripts/ide/components/pipelines/list.vue
+146
-0
app/assets/javascripts/ide/constants.js
app/assets/javascripts/ide/constants.js
+4
-0
app/assets/javascripts/ide/ide_router.js
app/assets/javascripts/ide/ide_router.js
+1
-1
app/assets/javascripts/ide/index.js
app/assets/javascripts/ide/index.js
+9
-1
app/assets/javascripts/ide/stores/actions.js
app/assets/javascripts/ide/stores/actions.js
+6
-0
app/assets/javascripts/ide/stores/actions/project.js
app/assets/javascripts/ide/stores/actions/project.js
+0
-62
app/assets/javascripts/ide/stores/index.js
app/assets/javascripts/ide/stores/index.js
+13
-10
app/assets/javascripts/ide/stores/modules/pipelines/actions.js
...ssets/javascripts/ide/stores/modules/pipelines/actions.js
+60
-29
app/assets/javascripts/ide/stores/modules/pipelines/constants.js
...ets/javascripts/ide/stores/modules/pipelines/constants.js
+4
-0
app/assets/javascripts/ide/stores/modules/pipelines/getters.js
...ssets/javascripts/ide/stores/modules/pipelines/getters.js
+18
-3
app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js
...avascripts/ide/stores/modules/pipelines/mutation_types.js
+2
-0
app/assets/javascripts/ide/stores/modules/pipelines/mutations.js
...ets/javascripts/ide/stores/modules/pipelines/mutations.js
+43
-30
app/assets/javascripts/ide/stores/modules/pipelines/state.js
app/assets/javascripts/ide/stores/modules/pipelines/state.js
+1
-1
app/assets/javascripts/ide/stores/modules/pipelines/utils.js
app/assets/javascripts/ide/stores/modules/pipelines/utils.js
+7
-0
app/assets/javascripts/ide/stores/mutation_types.js
app/assets/javascripts/ide/stores/mutation_types.js
+3
-1
app/assets/javascripts/ide/stores/mutations.js
app/assets/javascripts/ide/stores/mutations.js
+10
-1
app/assets/javascripts/ide/stores/mutations/branch.js
app/assets/javascripts/ide/stores/mutations/branch.js
+0
-9
app/assets/javascripts/ide/stores/state.js
app/assets/javascripts/ide/stores/state.js
+2
-0
app/assets/javascripts/vue_shared/components/ci_icon.vue
app/assets/javascripts/vue_shared/components/ci_icon.vue
+22
-1
app/assets/javascripts/vue_shared/components/tabs/tab.vue
app/assets/javascripts/vue_shared/components/tabs/tab.vue
+42
-0
app/assets/javascripts/vue_shared/components/tabs/tabs.js
app/assets/javascripts/vue_shared/components/tabs/tabs.js
+64
-0
app/assets/stylesheets/framework/gitlab_theme.scss
app/assets/stylesheets/framework/gitlab_theme.scss
+4
-0
app/assets/stylesheets/pages/repo.scss
app/assets/stylesheets/pages/repo.scss
+119
-0
app/views/ide/index.html.haml
app/views/ide/index.html.haml
+3
-1
spec/javascripts/ide/components/jobs/item_spec.js
spec/javascripts/ide/components/jobs/item_spec.js
+29
-0
spec/javascripts/ide/components/jobs/list_spec.js
spec/javascripts/ide/components/jobs/list_spec.js
+67
-0
spec/javascripts/ide/components/jobs/stage_spec.js
spec/javascripts/ide/components/jobs/stage_spec.js
+95
-0
spec/javascripts/ide/components/pipelines/list_spec.js
spec/javascripts/ide/components/pipelines/list_spec.js
+117
-0
spec/javascripts/ide/helpers.js
spec/javascripts/ide/helpers.js
+2
-0
spec/javascripts/ide/mock_data.js
spec/javascripts/ide/mock_data.js
+62
-8
spec/javascripts/ide/stores/actions/project_spec.js
spec/javascripts/ide/stores/actions/project_spec.js
+1
-110
spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
.../javascripts/ide/stores/modules/pipelines/actions_spec.js
+130
-135
spec/javascripts/ide/stores/modules/pipelines/getters_spec.js
.../javascripts/ide/stores/modules/pipelines/getters_spec.js
+0
-31
spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js
...avascripts/ide/stores/modules/pipelines/mutations_spec.js
+108
-54
spec/javascripts/ide/stores/mutations/branch_spec.js
spec/javascripts/ide/stores/mutations/branch_spec.js
+0
-36
spec/javascripts/vue_shared/components/tabs/tab_spec.js
spec/javascripts/vue_shared/components/tabs/tab_spec.js
+32
-0
spec/javascripts/vue_shared/components/tabs/tabs_spec.js
spec/javascripts/vue_shared/components/tabs/tabs_spec.js
+68
-0
No files found.
app/assets/javascripts/api.js
View file @
fc5537c3
...
...
@@ -25,8 +25,6 @@ const Api = {
commitPipelinesPath
:
'
/:project_id/commit/:sha/pipelines
'
,
branchSinglePath
:
'
/api/:version/projects/:id/repository/branches/:branch
'
,
createBranchPath
:
'
/api/:version/projects/:id/repository/branches
'
,
pipelinesPath
:
'
/api/:version/projects/:id/pipelines
'
,
pipelineJobsPath
:
'
/api/:version/projects/:id/pipelines/:pipeline_id/jobs
'
,
geoNodesPath
:
'
/api/:version/geo_nodes
'
,
group
(
groupId
,
callback
)
{
...
...
@@ -240,20 +238,6 @@ const Api = {
});
},
pipelines
(
projectPath
,
params
=
{})
{
const
url
=
Api
.
buildUrl
(
this
.
pipelinesPath
).
replace
(
'
:id
'
,
encodeURIComponent
(
projectPath
));
return
axios
.
get
(
url
,
{
params
});
},
pipelineJobs
(
projectPath
,
pipelineId
,
params
=
{})
{
const
url
=
Api
.
buildUrl
(
this
.
pipelineJobsPath
)
.
replace
(
'
:id
'
,
encodeURIComponent
(
projectPath
))
.
replace
(
'
:pipeline_id
'
,
pipelineId
);
return
axios
.
get
(
url
,
{
params
});
},
approverUsers
(
search
,
options
,
callback
=
$
.
noop
)
{
const
url
=
Api
.
buildUrl
(
'
/autocomplete/users.json
'
);
return
axios
...
...
app/assets/javascripts/ide/components/ide.vue
View file @
fc5537c3
...
...
@@ -6,6 +6,7 @@ import RepoTabs from './repo_tabs.vue';
import
IdeStatusBar
from
'
./ide_status_bar.vue
'
;
import
RepoEditor
from
'
./repo_editor.vue
'
;
import
FindFile
from
'
./file_finder/index.vue
'
;
import
RightPane
from
'
./panes/right.vue
'
;
const
originalStopCallback
=
Mousetrap
.
stopCallback
;
...
...
@@ -16,6 +17,7 @@ export default {
IdeStatusBar
,
RepoEditor
,
FindFile
,
RightPane
,
},
computed
:
{
...
mapState
([
...
...
@@ -25,6 +27,7 @@ export default {
'
currentMergeRequestId
'
,
'
fileFindVisible
'
,
'
emptyStateSvgPath
'
,
'
currentProjectId
'
,
]),
...
mapGetters
([
'
activeFile
'
,
'
hasChanges
'
]),
},
...
...
@@ -122,6 +125,9 @@ export default {
</div>
</
template
>
</div>
<right-pane
v-if=
"currentProjectId"
/>
</div>
<ide-status-bar
:file=
"activeFile"
/>
</article>
...
...
app/assets/javascripts/ide/components/ide_status_bar.vue
View file @
fc5537c3
...
...
@@ -31,6 +31,7 @@ export default {
computed
:
{
...
mapState
([
'
currentBranchId
'
,
'
currentProjectId
'
]),
...
mapGetters
([
'
currentProject
'
,
'
lastCommit
'
]),
...
mapState
(
'
pipelines
'
,
[
'
latestPipeline
'
]),
},
watch
:
{
lastCommit
()
{
...
...
@@ -51,14 +52,14 @@ export default {
}
},
methods
:
{
...
mapActions
(
[
'
pipelinePoll
'
,
'
stopPipelinePolling
'
]),
...
mapActions
(
'
pipelines
'
,
[
'
fetchLatestPipeline
'
,
'
stopPipelinePolling
'
]),
startTimer
()
{
this
.
intervalId
=
setInterval
(()
=>
{
this
.
commitAgeUpdate
();
},
1000
);
},
initPipelinePolling
()
{
this
.
pipelinePoll
();
this
.
fetchLatestPipeline
();
this
.
isPollingInitialized
=
true
;
},
commitAgeUpdate
()
{
...
...
@@ -81,18 +82,18 @@ export default {
>
<span
class=
"ide-status-pipeline"
v-if=
"la
stCommit.pipeline && lastCommit.p
ipeline.details"
v-if=
"la
testPipeline && latestP
ipeline.details"
>
<ci-icon
:status=
"la
stCommit.p
ipeline.details.status"
:status=
"la
testP
ipeline.details.status"
v-tooltip
:title=
"la
stCommit.p
ipeline.details.status.text"
:title=
"la
testP
ipeline.details.status.text"
/>
Pipeline
<a
class=
"monospace"
:href=
"la
stCommit.pipeline.details.status.details_path"
>
#
{{
lastCommit
.
p
ipeline
.
id
}}
</a>
{{
la
stCommit
.
p
ipeline
.
details
.
status
.
text
}}
:href=
"la
testPipeline.details.status.details_path"
>
#
{{
latestP
ipeline
.
id
}}
</a>
{{
la
testP
ipeline
.
details
.
status
.
text
}}
for
</span>
...
...
app/assets/javascripts/ide/components/jobs/item.vue
0 → 100644
View file @
fc5537c3
<
script
>
import
Icon
from
'
../../../vue_shared/components/icon.vue
'
;
import
CiIcon
from
'
../../../vue_shared/components/ci_icon.vue
'
;
export
default
{
components
:
{
Icon
,
CiIcon
,
},
props
:
{
job
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
jobId
()
{
return
`#
${
this
.
job
.
id
}
`
;
},
},
};
</
script
>
<
template
>
<div
class=
"ide-job-item"
>
<ci-icon
:status=
"job.status"
:borderless=
"true"
:size=
"24"
/>
<span
class=
"prepend-left-8"
>
{{
job
.
name
}}
<a
:href=
"job.path"
target=
"_blank"
class=
"ide-external-link"
>
{{
jobId
}}
<icon
name=
"external-link"
:size=
"12"
/>
</a>
</span>
</div>
</
template
>
app/assets/javascripts/ide/components/jobs/list.vue
0 → 100644
View file @
fc5537c3
<
script
>
import
{
mapActions
}
from
'
vuex
'
;
import
LoadingIcon
from
'
../../../vue_shared/components/loading_icon.vue
'
;
import
Stage
from
'
./stage.vue
'
;
export
default
{
components
:
{
LoadingIcon
,
Stage
,
},
props
:
{
stages
:
{
type
:
Array
,
required
:
true
,
},
loading
:
{
type
:
Boolean
,
required
:
true
,
},
},
methods
:
{
...
mapActions
(
'
pipelines
'
,
[
'
fetchJobs
'
,
'
toggleStageCollapsed
'
]),
},
};
</
script
>
<
template
>
<div>
<loading-icon
v-if=
"loading && !stages.length"
class=
"prepend-top-default"
size=
"2"
/>
<template
v-else
>
<stage
v-for=
"stage in stages"
:key=
"stage.id"
:stage=
"stage"
@
fetch=
"fetchJobs"
@
toggleCollapsed=
"toggleStageCollapsed"
/>
</
template
>
</div>
</template>
app/assets/javascripts/ide/components/jobs/stage.vue
0 → 100644
View file @
fc5537c3
<
script
>
import
tooltip
from
'
../../../vue_shared/directives/tooltip
'
;
import
Icon
from
'
../../../vue_shared/components/icon.vue
'
;
import
CiIcon
from
'
../../../vue_shared/components/ci_icon.vue
'
;
import
LoadingIcon
from
'
../../../vue_shared/components/loading_icon.vue
'
;
import
Item
from
'
./item.vue
'
;
export
default
{
directives
:
{
tooltip
,
},
components
:
{
Icon
,
CiIcon
,
LoadingIcon
,
Item
,
},
props
:
{
stage
:
{
type
:
Object
,
required
:
true
,
},
},
data
()
{
return
{
showTooltip
:
false
,
};
},
computed
:
{
collapseIcon
()
{
return
this
.
stage
.
isCollapsed
?
'
angle-left
'
:
'
angle-down
'
;
},
showLoadingIcon
()
{
return
this
.
stage
.
isLoading
&&
!
this
.
stage
.
jobs
.
length
;
},
jobsCount
()
{
return
this
.
stage
.
jobs
.
length
;
},
},
mounted
()
{
const
{
stageTitle
}
=
this
.
$refs
;
this
.
showTooltip
=
stageTitle
.
scrollWidth
>
stageTitle
.
offsetWidth
;
this
.
$emit
(
'
fetch
'
,
this
.
stage
);
},
methods
:
{
toggleCollapsed
()
{
this
.
$emit
(
'
toggleCollapsed
'
,
this
.
stage
.
id
);
},
},
};
</
script
>
<
template
>
<div
class=
"ide-stage card prepend-top-default"
>
<div
class=
"card-header"
:class=
"
{
'border-bottom-0': stage.isCollapsed
}"
@click="toggleCollapsed"
>
<ci-icon
:status=
"stage.status"
:size=
"24"
/>
<strong
v-tooltip=
"showTooltip"
:title=
"showTooltip ? stage.name : null"
data-container=
"body"
class=
"prepend-left-8 ide-stage-title"
ref=
"stageTitle"
>
{{
stage
.
name
}}
</strong>
<div
v-if=
"!stage.isLoading || stage.jobs.length"
class=
"append-right-8 prepend-left-4"
>
<span
class=
"badge badge-pill"
>
{{
jobsCount
}}
</span>
</div>
<icon
:name=
"collapseIcon"
css-classes=
"ide-stage-collapse-icon"
/>
</div>
<div
class=
"card-body"
v-show=
"!stage.isCollapsed"
>
<loading-icon
v-if=
"showLoadingIcon"
/>
<template
v-else
>
<item
v-for=
"job in stage.jobs"
:key=
"job.id"
:job=
"job"
/>
</
template
>
</div>
</div>
</template>
app/assets/javascripts/ide/components/panes/right.vue
0 → 100644
View file @
fc5537c3
<
script
>
import
{
mapActions
,
mapState
}
from
'
vuex
'
;
import
tooltip
from
'
../../../vue_shared/directives/tooltip
'
;
import
Icon
from
'
../../../vue_shared/components/icon.vue
'
;
import
{
rightSidebarViews
}
from
'
../../constants
'
;
import
PipelinesList
from
'
../pipelines/list.vue
'
;
export
default
{
directives
:
{
tooltip
,
},
components
:
{
Icon
,
PipelinesList
,
},
computed
:
{
...
mapState
([
'
rightPane
'
]),
},
methods
:
{
...
mapActions
([
'
setRightPane
'
]),
clickTab
(
e
,
view
)
{
e
.
target
.
blur
();
this
.
setRightPane
(
view
);
},
},
rightSidebarViews
,
};
</
script
>
<
template
>
<div
class=
"multi-file-commit-panel ide-right-sidebar"
>
<div
class=
"multi-file-commit-panel-inner"
v-if=
"rightPane"
>
<component
:is=
"rightPane"
/>
</div>
<nav
class=
"ide-activity-bar"
>
<ul
class=
"list-unstyled"
>
<li>
<button
v-tooltip
data-container=
"body"
data-placement=
"left"
:title=
"__('Pipelines')"
class=
"ide-sidebar-link is-right"
:class=
"
{
active: rightPane === $options.rightSidebarViews.pipelines
}"
type="button"
@click="clickTab($event, $options.rightSidebarViews.pipelines)"
>
<icon
:size=
"16"
name=
"pipeline"
/>
</button>
</li>
</ul>
</nav>
</div>
</
template
>
app/assets/javascripts/ide/components/pipelines/list.vue
0 → 100644
View file @
fc5537c3
<
script
>
import
{
mapActions
,
mapGetters
,
mapState
}
from
'
vuex
'
;
import
_
from
'
underscore
'
;
import
{
sprintf
,
__
}
from
'
../../../locale
'
;
import
LoadingIcon
from
'
../../../vue_shared/components/loading_icon.vue
'
;
import
Icon
from
'
../../../vue_shared/components/icon.vue
'
;
import
CiIcon
from
'
../../../vue_shared/components/ci_icon.vue
'
;
import
Tabs
from
'
../../../vue_shared/components/tabs/tabs
'
;
import
Tab
from
'
../../../vue_shared/components/tabs/tab.vue
'
;
import
EmptyState
from
'
../../../pipelines/components/empty_state.vue
'
;
import
JobsList
from
'
../jobs/list.vue
'
;
export
default
{
components
:
{
LoadingIcon
,
Icon
,
CiIcon
,
Tabs
,
Tab
,
JobsList
,
EmptyState
,
},
computed
:
{
...
mapState
([
'
pipelinesEmptyStateSvgPath
'
,
'
links
'
]),
...
mapGetters
([
'
currentProject
'
]),
...
mapGetters
(
'
pipelines
'
,
[
'
jobsCount
'
,
'
failedJobsCount
'
,
'
failedStages
'
,
'
pipelineFailed
'
]),
...
mapState
(
'
pipelines
'
,
[
'
isLoadingPipeline
'
,
'
latestPipeline
'
,
'
stages
'
,
'
isLoadingJobs
'
]),
ciLintText
()
{
return
sprintf
(
__
(
'
You can also test your .gitlab-ci.yml in the %{linkStart}Lint%{linkEnd}
'
),
{
linkStart
:
`<a href="
${
_
.
escape
(
this
.
currentProject
.
web_url
)}
/-/ci/lint">`
,
linkEnd
:
'
</a>
'
,
},
false
,
);
},
showLoadingIcon
()
{
return
this
.
isLoadingPipeline
&&
this
.
latestPipeline
===
null
;
},
},
created
()
{
this
.
fetchLatestPipeline
();
},
methods
:
{
...
mapActions
(
'
pipelines
'
,
[
'
fetchLatestPipeline
'
]),
},
};
</
script
>
<
template
>
<div
class=
"ide-pipeline"
>
<loading-icon
v-if=
"showLoadingIcon"
class=
"prepend-top-default"
size=
"2"
/>
<template
v-else-if=
"latestPipeline !== null"
>
<header
v-if=
"latestPipeline"
class=
"ide-tree-header ide-pipeline-header"
>
<ci-icon
:status=
"latestPipeline.details.status"
:size=
"24"
/>
<span
class=
"prepend-left-8"
>
<strong>
{{
__
(
'
Pipeline
'
)
}}
</strong>
<a
:href=
"latestPipeline.path"
target=
"_blank"
class=
"ide-external-link"
>
#
{{
latestPipeline
.
id
}}
<icon
name=
"external-link"
:size=
"12"
/>
</a>
</span>
</header>
<empty-state
v-if=
"latestPipeline === false"
:help-page-path=
"links.ciHelpPagePath"
:empty-state-svg-path=
"pipelinesEmptyStateSvgPath"
:can-set-ci=
"true"
/>
<div
v-else-if=
"latestPipeline.yamlError"
class=
"bs-callout bs-callout-danger"
>
<p
class=
"append-bottom-0"
>
{{
__
(
'
Found errors in your .gitlab-ci.yml:
'
)
}}
</p>
<p
class=
"append-bottom-0"
>
{{
latestPipeline
.
yamlError
}}
</p>
<p
class=
"append-bottom-0"
v-html=
"ciLintText"
></p>
</div>
<tabs
v-else
class=
"ide-pipeline-list"
>
<tab
:active=
"!pipelineFailed"
>
<template
slot=
"title"
>
{{
__
(
'
Jobs
'
)
}}
<span
v-if=
"jobsCount"
class=
"badge badge-pill"
>
{{
jobsCount
}}
</span>
</
template
>
<jobs-list
:loading=
"isLoadingJobs"
:stages=
"stages"
/>
</tab>
<tab
:active=
"pipelineFailed"
>
<
template
slot=
"title"
>
{{
__
(
'
Failed Jobs
'
)
}}
<span
v-if=
"failedJobsCount"
class=
"badge badge-pill"
>
{{
failedJobsCount
}}
</span>
</
template
>
<jobs-list
:loading=
"isLoadingJobs"
:stages=
"failedStages"
/>
</tab>
</tabs>
</template>
</div>
</template>
app/assets/javascripts/ide/constants.js
View file @
fc5537c3
...
...
@@ -20,3 +20,7 @@ export const viewerTypes = {
edit
:
'
editor
'
,
diff
:
'
diff
'
,
};
export
const
rightSidebarViews
=
{
pipelines
:
'
pipelines-list
'
,
};
app/assets/javascripts/ide/ide_router.js
View file @
fc5537c3
...
...
@@ -63,7 +63,7 @@ router.beforeEach((to, from, next) => {
.
then
(()
=>
{
const
fullProjectId
=
`
${
to
.
params
.
namespace
}
/
${
to
.
params
.
project
}
`
;
const
baseSplit
=
to
.
params
[
0
].
split
(
'
/-/
'
)
;
const
baseSplit
=
(
to
.
params
[
0
]
&&
to
.
params
[
0
].
split
(
'
/-/
'
))
||
[
''
]
;
const
branchId
=
baseSplit
[
0
].
slice
(
-
1
)
===
'
/
'
?
baseSplit
[
0
].
slice
(
0
,
-
1
)
:
baseSplit
[
0
];
if
(
branchId
)
{
...
...
app/assets/javascripts/ide/index.js
View file @
fc5537c3
import
Vue
from
'
vue
'
;
import
{
mapActions
}
from
'
vuex
'
;
import
Translate
from
'
~/vue_shared/translate
'
;
import
ide
from
'
./components/ide.vue
'
;
import
store
from
'
./stores
'
;
...
...
@@ -17,11 +18,18 @@ export function initIde(el) {
ide
,
},
created
()
{
this
.
$store
.
dispatch
(
'
setEmptyStateSvgs
'
,
{
this
.
setEmptyStateSvgs
(
{
emptyStateSvgPath
:
el
.
dataset
.
emptyStateSvgPath
,
noChangesStateSvgPath
:
el
.
dataset
.
noChangesStateSvgPath
,
committedStateSvgPath
:
el
.
dataset
.
committedStateSvgPath
,
pipelinesEmptyStateSvgPath
:
el
.
dataset
.
pipelinesEmptyStateSvgPath
,
});
this
.
setLinks
({
ciHelpPagePath
:
el
.
dataset
.
ciHelpPagePath
,
});
},
methods
:
{
...
mapActions
([
'
setEmptyStateSvgs
'
,
'
setLinks
'
]),
},
render
(
createElement
)
{
return
createElement
(
'
ide
'
);
...
...
app/assets/javascripts/ide/stores/actions.js
View file @
fc5537c3
...
...
@@ -169,6 +169,12 @@ export const burstUnusedSeal = ({ state, commit }) => {
}
};
export
const
setRightPane
=
({
commit
},
view
)
=>
{
commit
(
types
.
SET_RIGHT_PANE
,
view
);
};
export
const
setLinks
=
({
commit
},
links
)
=>
commit
(
types
.
SET_LINKS
,
links
);
export
*
from
'
./actions/tree
'
;
export
*
from
'
./actions/file
'
;
export
*
from
'
./actions/project
'
;
...
...
app/assets/javascripts/ide/stores/actions/project.js
View file @
fc5537c3
import
Visibility
from
'
visibilityjs
'
;
import
flash
from
'
~/flash
'
;
import
{
__
}
from
'
~/locale
'
;
import
service
from
'
../../services
'
;
import
*
as
types
from
'
../mutation_types
'
;
import
Poll
from
'
../../../lib/utils/poll
'
;
let
eTagPoll
;
export
const
getProjectData
=
({
commit
,
state
},
{
namespace
,
projectId
,
force
=
false
}
=
{})
=>
new
Promise
((
resolve
,
reject
)
=>
{
...
...
@@ -85,61 +81,3 @@ export const refreshLastCommitData = ({ commit }, { projectId, branchId } = {})
.
catch
(()
=>
{
flash
(
__
(
'
Error loading last commit.
'
),
'
alert
'
,
document
,
null
,
false
,
true
);
});
export
const
pollSuccessCallBack
=
({
commit
,
state
},
{
data
})
=>
{
if
(
data
.
pipelines
&&
data
.
pipelines
.
length
)
{
const
lastCommitHash
=
state
.
projects
[
state
.
currentProjectId
].
branches
[
state
.
currentBranchId
].
commit
.
id
;
const
lastCommitPipeline
=
data
.
pipelines
.
find
(
pipeline
=>
pipeline
.
commit
.
id
===
lastCommitHash
,
);
commit
(
types
.
SET_LAST_COMMIT_PIPELINE
,
{
projectId
:
state
.
currentProjectId
,
branchId
:
state
.
currentBranchId
,
pipeline
:
lastCommitPipeline
||
{},
});
}
return
data
;
};
export
const
pipelinePoll
=
({
getters
,
dispatch
})
=>
{
eTagPoll
=
new
Poll
({
resource
:
service
,
method
:
'
lastCommitPipelines
'
,
data
:
{
getters
,
},
successCallback
:
({
data
})
=>
dispatch
(
'
pollSuccessCallBack
'
,
{
data
}),
errorCallback
:
()
=>
{
flash
(
__
(
'
Something went wrong while fetching the latest pipeline status.
'
),
'
alert
'
,
document
,
null
,
false
,
true
,
);
},
});
if
(
!
Visibility
.
hidden
())
{
eTagPoll
.
makeRequest
();
}
Visibility
.
change
(()
=>
{
if
(
!
Visibility
.
hidden
())
{
eTagPoll
.
restart
();
}
else
{
eTagPoll
.
stop
();
}
});
};
export
const
stopPipelinePolling
=
()
=>
{
eTagPoll
.
stop
();
};
export
const
restartPipelinePolling
=
()
=>
{
eTagPoll
.
restart
();
};
app/assets/javascripts/ide/stores/index.js
View file @
fc5537c3
...
...
@@ -9,13 +9,16 @@ import pipelines from './modules/pipelines';
Vue
.
use
(
Vuex
);
export
default
new
Vuex
.
Store
({
state
:
state
(),
actions
,
mutations
,
getters
,
modules
:
{
commit
:
commitModule
,
pipelines
,
},
});
export
const
createStore
=
()
=>
new
Vuex
.
Store
({
state
:
state
(),
actions
,
mutations
,
getters
,
modules
:
{
commit
:
commitModule
,
pipelines
,
},
});
export
default
createStore
();
app/assets/javascripts/ide/stores/modules/pipelines/actions.js
View file @
fc5537c3
import
Visibility
from
'
visibilityjs
'
;
import
axios
from
'
axios
'
;
import
{
__
}
from
'
../../../../locale
'
;
import
Api
from
'
../../../../api
'
;
import
flash
from
'
../../../../flash
'
;
import
Poll
from
'
../../../../lib/utils/poll
'
;
import
service
from
'
../../../services
'
;
import
*
as
types
from
'
./mutation_types
'
;
let
eTagPoll
;
export
const
clearEtagPoll
=
()
=>
{
eTagPoll
=
null
;
};
export
const
stopPipelinePolling
=
()
=>
eTagPoll
&&
eTagPoll
.
stop
();
export
const
restartPipelinePolling
=
()
=>
eTagPoll
&&
eTagPoll
.
restart
();
export
const
requestLatestPipeline
=
({
commit
})
=>
commit
(
types
.
REQUEST_LATEST_PIPELINE
);
export
const
receiveLatestPipelineError
=
({
commit
})
=>
{
export
const
receiveLatestPipelineError
=
({
commit
,
dispatch
})
=>
{
flash
(
__
(
'
There was an error loading latest pipeline
'
));
commit
(
types
.
RECEIVE_LASTEST_PIPELINE_ERROR
);
dispatch
(
'
stopPipelinePolling
'
);
};
export
const
receiveLatestPipelineSuccess
=
({
rootGetters
,
commit
},
{
pipelines
})
=>
{
let
lastCommitPipeline
=
false
;
if
(
pipelines
&&
pipelines
.
length
)
{
const
lastCommitHash
=
rootGetters
.
lastCommit
&&
rootGetters
.
lastCommit
.
id
;
lastCommitPipeline
=
pipelines
.
find
(
pipeline
=>
pipeline
.
commit
.
id
===
lastCommitHash
);
}
commit
(
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
,
lastCommitPipeline
);
};
export
const
receiveLatestPipelineSuccess
=
({
commit
},
pipeline
)
=>
commit
(
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
,
pipeline
);
export
const
fetchLatestPipeline
=
({
dispatch
,
rootState
},
sha
)
=>
{
export
const
fetchLatestPipeline
=
({
dispatch
,
rootGetters
})
=>
{
if
(
eTagPoll
)
return
;
dispatch
(
'
requestLatestPipeline
'
);
return
Api
.
pipelines
(
rootState
.
currentProjectId
,
{
sha
,
per_page
:
'
1
'
})
.
then
(({
data
})
=>
{
dispatch
(
'
receiveLatestPipelineSuccess
'
,
data
.
pop
());
})
.
catch
(()
=>
dispatch
(
'
receiveLatestPipelineError
'
));
eTagPoll
=
new
Poll
({
resource
:
service
,
method
:
'
lastCommitPipelines
'
,
data
:
{
getters
:
rootGetters
},
successCallback
:
({
data
})
=>
dispatch
(
'
receiveLatestPipelineSuccess
'
,
data
),
errorCallback
:
()
=>
dispatch
(
'
receiveLatestPipelineError
'
),
});
if
(
!
Visibility
.
hidden
())
{
eTagPoll
.
makeRequest
();
}
Visibility
.
change
(()
=>
{
if
(
!
Visibility
.
hidden
())
{
eTagPoll
.
restart
();
}
else
{
eTagPoll
.
stop
();
}
});
};
export
const
requestJobs
=
({
commit
}
)
=>
commit
(
types
.
REQUEST_JOBS
);
export
const
receiveJobsError
=
({
commit
})
=>
{
export
const
requestJobs
=
({
commit
}
,
id
)
=>
commit
(
types
.
REQUEST_JOBS
,
id
);
export
const
receiveJobsError
=
({
commit
}
,
id
)
=>
{
flash
(
__
(
'
There was an error loading jobs
'
));
commit
(
types
.
RECEIVE_JOBS_ERROR
);
commit
(
types
.
RECEIVE_JOBS_ERROR
,
id
);
};
export
const
receiveJobsSuccess
=
({
commit
},
data
)
=>
commit
(
types
.
RECEIVE_JOBS_SUCCESS
,
data
);
export
const
receiveJobsSuccess
=
({
commit
},
{
id
,
data
})
=>
commit
(
types
.
RECEIVE_JOBS_SUCCESS
,
{
id
,
data
});
export
const
fetchJobs
=
({
dispatch
,
state
,
rootState
},
page
=
'
1
'
)
=>
{
dispatch
(
'
requestJobs
'
);
export
const
fetchJobs
=
({
dispatch
},
stage
)
=>
{
dispatch
(
'
requestJobs
'
,
stage
.
id
);
Api
.
pipelineJobs
(
rootState
.
currentProjectId
,
state
.
latestPipeline
.
id
,
{
page
,
})
.
then
(({
data
,
headers
})
=>
{
const
nextPage
=
headers
&&
headers
[
'
x-next-page
'
];
dispatch
(
'
receiveJobsSuccess
'
,
data
);
if
(
nextPage
)
{
dispatch
(
'
fetchJobs
'
,
nextPage
);
}
})
.
catch
(()
=>
dispatch
(
'
receiveJobsError
'
));
axios
.
get
(
stage
.
dropdownPath
)
.
then
(({
data
})
=>
dispatch
(
'
receiveJobsSuccess
'
,
{
id
:
stage
.
id
,
data
}))
.
catch
(()
=>
dispatch
(
'
receiveJobsError
'
,
stage
.
id
));
};
export
const
toggleStageCollapsed
=
({
commit
},
stageId
)
=>
commit
(
types
.
TOGGLE_STAGE_COLLAPSE
,
stageId
);
export
default
()
=>
{};
app/assets/javascripts/ide/stores/modules/pipelines/constants.js
0 → 100644
View file @
fc5537c3
// eslint-disable-next-line import/prefer-default-export
export
const
states
=
{
failed
:
'
failed
'
,
};
app/assets/javascripts/ide/stores/modules/pipelines/getters.js
View file @
fc5537c3
import
{
states
}
from
'
./constants
'
;
export
const
hasLatestPipeline
=
state
=>
!
state
.
isLoadingPipeline
&&
!!
state
.
latestPipeline
;
export
const
failedJobs
=
state
=>
export
const
pipelineFailed
=
state
=>
state
.
latestPipeline
&&
state
.
latestPipeline
.
details
.
status
.
text
===
states
.
failed
;
export
const
failedStages
=
state
=>
state
.
stages
.
filter
(
stage
=>
stage
.
status
.
text
.
toLowerCase
()
===
states
.
failed
).
map
(
stage
=>
({
...
stage
,
jobs
:
stage
.
jobs
.
filter
(
job
=>
job
.
status
.
text
.
toLowerCase
()
===
states
.
failed
),
}));
export
const
failedJobsCount
=
state
=>
state
.
stages
.
reduce
(
(
acc
,
stage
)
=>
acc
.
concat
(
stage
.
jobs
.
filter
(
job
=>
job
.
status
===
'
failed
'
))
,
[]
,
(
acc
,
stage
)
=>
acc
+
stage
.
jobs
.
filter
(
j
=>
j
.
status
.
text
===
states
.
failed
).
length
,
0
,
);
export
const
jobsCount
=
state
=>
state
.
stages
.
reduce
((
acc
,
stage
)
=>
acc
+
stage
.
jobs
.
length
,
0
);
export
default
()
=>
{};
app/assets/javascripts/ide/stores/modules/pipelines/mutation_types.js
View file @
fc5537c3
...
...
@@ -5,3 +5,5 @@ export const RECEIVE_LASTEST_PIPELINE_SUCCESS = 'RECEIVE_LASTEST_PIPELINE_SUCCES
export
const
REQUEST_JOBS
=
'
REQUEST_JOBS
'
;
export
const
RECEIVE_JOBS_ERROR
=
'
RECEIVE_JOBS_ERROR
'
;
export
const
RECEIVE_JOBS_SUCCESS
=
'
RECEIVE_JOBS_SUCCESS
'
;
export
const
TOGGLE_STAGE_COLLAPSE
=
'
TOGGLE_STAGE_COLLAPSE
'
;
app/assets/javascripts/ide/stores/modules/pipelines/mutations.js
View file @
fc5537c3
/* eslint-disable no-param-reassign */
import
*
as
types
from
'
./mutation_types
'
;
import
{
normalizeJob
}
from
'
./utils
'
;
export
default
{
[
types
.
REQUEST_LATEST_PIPELINE
](
state
)
{
...
...
@@ -14,40 +15,52 @@ export default {
if
(
pipeline
)
{
state
.
latestPipeline
=
{
id
:
pipeline
.
id
,
status
:
pipeline
.
status
,
path
:
pipeline
.
path
,
commit
:
pipeline
.
commit
,
details
:
{
status
:
pipeline
.
details
.
status
,
},
yamlError
:
pipeline
.
yaml_errors
,
};
state
.
stages
=
pipeline
.
details
.
stages
.
map
((
stage
,
i
)
=>
{
const
foundStage
=
state
.
stages
.
find
(
s
=>
s
.
id
===
i
);
return
{
id
:
i
,
dropdownPath
:
stage
.
dropdown_path
,
name
:
stage
.
name
,
status
:
stage
.
status
,
isCollapsed
:
foundStage
?
foundStage
.
isCollapsed
:
false
,
isLoading
:
foundStage
?
foundStage
.
isLoading
:
false
,
jobs
:
foundStage
?
foundStage
.
jobs
:
[],
};
});
}
else
{
state
.
latestPipeline
=
false
;
}
},
[
types
.
REQUEST_JOBS
](
state
)
{
state
.
isLoadingJobs
=
true
;
[
types
.
REQUEST_JOBS
](
state
,
id
)
{
state
.
stages
=
state
.
stages
.
map
(
stage
=>
({
...
stage
,
isLoading
:
stage
.
id
===
id
?
true
:
stage
.
isLoading
,
}));
},
[
types
.
RECEIVE_JOBS_ERROR
](
state
)
{
state
.
isLoadingJobs
=
false
;
[
types
.
RECEIVE_JOBS_ERROR
](
state
,
id
)
{
state
.
stages
=
state
.
stages
.
map
(
stage
=>
({
...
stage
,
isLoading
:
stage
.
id
===
id
?
false
:
stage
.
isLoading
,
}));
},
[
types
.
RECEIVE_JOBS_SUCCESS
](
state
,
jobs
)
{
state
.
isLoadingJobs
=
false
;
state
.
stages
=
jobs
.
reduce
((
acc
,
job
)
=>
{
let
stage
=
acc
.
find
(
s
=>
s
.
title
===
job
.
stage
);
if
(
!
stage
)
{
stage
=
{
title
:
job
.
stage
,
jobs
:
[],
};
acc
.
push
(
stage
);
}
stage
.
jobs
=
stage
.
jobs
.
concat
({
id
:
job
.
id
,
name
:
job
.
name
,
status
:
job
.
status
,
stage
:
job
.
stage
,
duration
:
job
.
duration
,
});
return
acc
;
},
state
.
stages
);
[
types
.
RECEIVE_JOBS_SUCCESS
](
state
,
{
id
,
data
})
{
state
.
stages
=
state
.
stages
.
map
(
stage
=>
({
...
stage
,
isLoading
:
stage
.
id
===
id
?
false
:
stage
.
isLoading
,
jobs
:
data
.
latest_statuses
.
map
(
normalizeJob
),
}));
},
[
types
.
TOGGLE_STAGE_COLLAPSE
](
state
,
id
)
{
state
.
stages
=
state
.
stages
.
map
(
stage
=>
({
...
stage
,
isCollapsed
:
stage
.
id
===
id
?
!
stage
.
isCollapsed
:
stage
.
isCollapsed
,
}));
},
};
app/assets/javascripts/ide/stores/modules/pipelines/state.js
View file @
fc5537c3
export
default
()
=>
({
isLoadingPipeline
:
fals
e
,
isLoadingPipeline
:
tru
e
,
isLoadingJobs
:
false
,
latestPipeline
:
null
,
stages
:
[],
...
...
app/assets/javascripts/ide/stores/modules/pipelines/utils.js
0 → 100644
View file @
fc5537c3
// eslint-disable-next-line import/prefer-default-export
export
const
normalizeJob
=
job
=>
({
id
:
job
.
id
,
name
:
job
.
name
,
status
:
job
.
status
,
path
:
job
.
build_path
,
});
app/assets/javascripts/ide/stores/mutation_types.js
View file @
fc5537c3
...
...
@@ -6,6 +6,7 @@ export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED';
export
const
SET_RIGHT_PANEL_COLLAPSED
=
'
SET_RIGHT_PANEL_COLLAPSED
'
;
export
const
SET_RESIZING_STATUS
=
'
SET_RESIZING_STATUS
'
;
export
const
SET_EMPTY_STATE_SVGS
=
'
SET_EMPTY_STATE_SVGS
'
;
export
const
SET_LINKS
=
'
SET_LINKS
'
;
// Project Mutation Types
export
const
SET_PROJECT
=
'
SET_PROJECT
'
;
...
...
@@ -23,7 +24,6 @@ export const SET_BRANCH = 'SET_BRANCH';
export
const
SET_BRANCH_COMMIT
=
'
SET_BRANCH_COMMIT
'
;
export
const
SET_BRANCH_WORKING_REFERENCE
=
'
SET_BRANCH_WORKING_REFERENCE
'
;
export
const
TOGGLE_BRANCH_OPEN
=
'
TOGGLE_BRANCH_OPEN
'
;
export
const
SET_LAST_COMMIT_PIPELINE
=
'
SET_LAST_COMMIT_PIPELINE
'
;
// Tree mutation types
export
const
SET_DIRECTORY_DATA
=
'
SET_DIRECTORY_DATA
'
;
...
...
@@ -66,3 +66,5 @@ export const UPDATE_ACTIVITY_BAR_VIEW = 'UPDATE_ACTIVITY_BAR_VIEW';
export
const
UPDATE_TEMP_FLAG
=
'
UPDATE_TEMP_FLAG
'
;
export
const
TOGGLE_FILE_FINDER
=
'
TOGGLE_FILE_FINDER
'
;
export
const
BURST_UNUSED_SEAL
=
'
BURST_UNUSED_SEAL
'
;
export
const
SET_RIGHT_PANE
=
'
SET_RIGHT_PANE
'
;
app/assets/javascripts/ide/stores/mutations.js
View file @
fc5537c3
...
...
@@ -114,12 +114,13 @@ export default {
},
[
types
.
SET_EMPTY_STATE_SVGS
](
state
,
{
emptyStateSvgPath
,
noChangesStateSvgPath
,
committedStateSvgPath
},
{
emptyStateSvgPath
,
noChangesStateSvgPath
,
committedStateSvgPath
,
pipelinesEmptyStateSvgPath
},
)
{
Object
.
assign
(
state
,
{
emptyStateSvgPath
,
noChangesStateSvgPath
,
committedStateSvgPath
,
pipelinesEmptyStateSvgPath
,
});
},
[
types
.
TOGGLE_FILE_FINDER
](
state
,
fileFindVisible
)
{
...
...
@@ -148,6 +149,14 @@ export default {
unusedSeal
:
false
,
});
},
[
types
.
SET_RIGHT_PANE
](
state
,
view
)
{
Object
.
assign
(
state
,
{
rightPane
:
state
.
rightPane
===
view
?
null
:
view
,
});
},
[
types
.
SET_LINKS
](
state
,
links
)
{
Object
.
assign
(
state
,
{
links
});
},
...
projectMutations
,
...
mergeRequestMutation
,
...
fileMutations
,
...
...
app/assets/javascripts/ide/stores/mutations/branch.js
View file @
fc5537c3
...
...
@@ -14,10 +14,6 @@ export default {
treeId
:
`
${
projectPath
}
/
${
branchName
}
`
,
active
:
true
,
workingReference
:
''
,
commit
:
{
...
branch
.
commit
,
pipeline
:
{},
},
},
},
});
...
...
@@ -32,9 +28,4 @@ export default {
commit
,
});
},
[
types
.
SET_LAST_COMMIT_PIPELINE
](
state
,
{
projectId
,
branchId
,
pipeline
})
{
Object
.
assign
(
state
.
projects
[
projectId
].
branches
[
branchId
].
commit
,
{
pipeline
,
});
},
};
app/assets/javascripts/ide/stores/state.js
View file @
fc5537c3
...
...
@@ -23,4 +23,6 @@ export default () => ({
currentActivityView
:
activityBarViews
.
edit
,
unusedSeal
:
true
,
fileFindVisible
:
false
,
rightPane
:
null
,
links
:
{},
});
app/assets/javascripts/vue_shared/components/ci_icon.vue
View file @
fc5537c3
...
...
@@ -23,6 +23,8 @@ import Icon from '../../vue_shared/components/icon.vue';
* - Jobs show view sidebar
* - Linked pipelines
*/
const
validSizes
=
[
8
,
12
,
16
,
18
,
24
,
32
,
48
,
72
];
export
default
{
components
:
{
Icon
,
...
...
@@ -32,17 +34,36 @@ export default {
type
:
Object
,
required
:
true
,
},
size
:
{
type
:
Number
,
required
:
false
,
default
:
16
,
validator
(
value
)
{
return
validSizes
.
includes
(
value
);
},
},
borderless
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
cssClass
()
{
const
status
=
this
.
status
.
group
;
return
`ci-status-icon ci-status-icon-
${
status
}
js-ci-status-icon-
${
status
}
`
;
},
icon
()
{
return
this
.
borderless
?
`
${
this
.
status
.
icon
}
_borderless`
:
this
.
status
.
icon
;
},
},
};
</
script
>
<
template
>
<span
:class=
"cssClass"
>
<icon
:name=
"status.icon"
/>
<icon
:name=
"icon"
:size=
"size"
/>
</span>
</
template
>
app/assets/javascripts/vue_shared/components/tabs/tab.vue
0 → 100644
View file @
fc5537c3
<
script
>
export
default
{
props
:
{
title
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
active
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
// props can't be updated, so we map it to data where we can
localActive
:
this
.
active
,
};
},
watch
:
{
active
()
{
this
.
localActive
=
this
.
active
;
},
},
created
()
{
this
.
isTab
=
true
;
},
};
</
script
>
<
template
>
<div
class=
"tab-pane"
:class=
"
{
active: localActive
}"
role="tabpanel"
>
<slot></slot>
</div>
</
template
>
app/assets/javascripts/vue_shared/components/tabs/tabs.js
0 → 100644
View file @
fc5537c3
export
default
{
data
()
{
return
{
currentIndex
:
0
,
tabs
:
[],
};
},
mounted
()
{
this
.
updateTabs
();
},
methods
:
{
updateTabs
()
{
this
.
tabs
=
this
.
$children
.
filter
(
child
=>
child
.
isTab
);
this
.
currentIndex
=
this
.
tabs
.
findIndex
(
tab
=>
tab
.
localActive
);
},
setTab
(
index
)
{
this
.
tabs
[
this
.
currentIndex
].
localActive
=
false
;
this
.
tabs
[
index
].
localActive
=
true
;
this
.
currentIndex
=
index
;
},
},
render
(
h
)
{
const
navItems
=
this
.
tabs
.
map
((
tab
,
i
)
=>
h
(
'
li
'
,
{
key
:
i
,
},
[
h
(
'
a
'
,
{
class
:
tab
.
localActive
?
'
active
'
:
null
,
attrs
:
{
href
:
'
#
'
,
},
on
:
{
click
:
()
=>
this
.
setTab
(
i
),
},
},
tab
.
$slots
.
title
||
tab
.
title
,
),
],
),
);
const
nav
=
h
(
'
ul
'
,
{
class
:
'
nav-links tab-links
'
,
},
[
navItems
],
);
const
content
=
h
(
'
div
'
,
{
class
:
[
'
tab-content
'
],
},
[
this
.
$slots
.
default
],
);
return
h
(
'
div
'
,
{},
[[
nav
],
content
]);
},
};
app/assets/stylesheets/framework/gitlab_theme.scss
View file @
fc5537c3
...
...
@@ -189,6 +189,10 @@
&
.active
{
color
:
$color-700
;
box-shadow
:
inset
3px
0
$color-700
;
&
.is-right
{
box-shadow
:
inset
-3px
0
$color-700
;
}
}
}
}
...
...
app/assets/stylesheets/pages/repo.scss
View file @
fc5537c3
...
...
@@ -909,6 +909,16 @@
width
:
1px
;
background
:
$white-light
;
}
&
.is-right
{
padding-right
:
$gl-padding
;
padding-left
:
$gl-padding
+
1px
;
&
:
:
after
{
right
:
auto
;
left
:
-1px
;
}
}
}
}
...
...
@@ -1121,3 +1131,112 @@
white-space
:
nowrap
;
}
}
.ide-external-link
{
svg
{
display
:
none
;
}
&
:hover
,
&
:focus
{
svg
{
display
:
inline-block
;
}
}
}
.ide-right-sidebar
{
width
:
auto
;
min-width
:
60px
;
.ide-activity-bar
{
border-left
:
1px
solid
$white-dark
;
}
.multi-file-commit-panel-inner
{
width
:
350px
;
padding
:
$grid-size
$gl-padding
;
background-color
:
$white-light
;
border-left
:
1px
solid
$white-dark
;
}
}
.ide-pipeline
{
display
:
flex
;
flex-direction
:
column
;
height
:
100%
;
.empty-state
{
margin-top
:
auto
;
margin-bottom
:
auto
;
p
{
margin
:
$grid-size
0
;
text-align
:
center
;
line-height
:
24px
;
}
.btn
,
h4
{
margin
:
0
;
}
}
}
.ide-pipeline-list
{
flex
:
1
;
overflow
:
auto
;
}
.ide-pipeline-header
{
min-height
:
50px
;
padding-left
:
$gl-padding
;
padding-right
:
$gl-padding
;
.ci-status-icon
{
display
:
flex
;
}
}
.ide-job-item
{
display
:
flex
;
padding
:
16px
;
&
:not
(
:last-child
)
{
border-bottom
:
1px
solid
$border-color
;
}
.ci-status-icon
{
display
:
flex
;
justify-content
:
center
;
height
:
20px
;
margin-top
:
-2px
;
overflow
:
hidden
;
}
}
.ide-stage
{
.card-header
{
display
:
flex
;
cursor
:
pointer
;
.ci-status-icon
{
display
:
flex
;
align-items
:
center
;
}
}
.card-body
{
padding
:
0
;
}
}
.ide-stage-collapse-icon
{
margin
:
auto
0
auto
auto
;
}
.ide-stage-title
{
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
app/views/ide/index.html.haml
View file @
fc5537c3
...
...
@@ -3,7 +3,9 @@
#ide
.ide-loading
{
data:
{
"empty-state-svg-path"
=>
image_path
(
'illustrations/multi_file_editor_empty.svg'
),
"no-changes-state-svg-path"
=>
image_path
(
'illustrations/multi-editor_no_changes_empty.svg'
),
"committed-state-svg-path"
=>
image_path
(
'illustrations/multi-editor_all_changes_committed_empty.svg'
)
}
}
"committed-state-svg-path"
=>
image_path
(
'illustrations/multi-editor_all_changes_committed_empty.svg'
),
"pipelines-empty-state-svg-path"
:
image_path
(
'illustrations/pipelines_empty.svg'
),
"ci-help-page-path"
=>
help_page_path
(
'ci/quick_start/README'
),
}
}
.text-center
=
icon
(
'spinner spin 2x'
)
%h2
.clgray
=
_
(
'Loading the GitLab IDE...'
)
spec/javascripts/ide/components/jobs/item_spec.js
0 → 100644
View file @
fc5537c3
import
Vue
from
'
vue
'
;
import
JobItem
from
'
~/ide/components/jobs/item.vue
'
;
import
mountComponent
from
'
../../../helpers/vue_mount_component_helper
'
;
import
{
jobs
}
from
'
../../mock_data
'
;
describe
(
'
IDE jobs item
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
JobItem
);
const
job
=
jobs
[
0
];
let
vm
;
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
job
,
});
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
it
(
'
renders job details
'
,
()
=>
{
expect
(
vm
.
$el
.
textContent
).
toContain
(
job
.
name
);
expect
(
vm
.
$el
.
textContent
).
toContain
(
`#
${
job
.
id
}
`
);
});
it
(
'
renders CI icon
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.ic-status_passed_borderless
'
)).
not
.
toBe
(
null
);
});
});
spec/javascripts/ide/components/jobs/list_spec.js
0 → 100644
View file @
fc5537c3
import
Vue
from
'
vue
'
;
import
StageList
from
'
~/ide/components/jobs/list.vue
'
;
import
{
createStore
}
from
'
~/ide/stores
'
;
import
{
createComponentWithStore
}
from
'
../../../helpers/vue_mount_component_helper
'
;
import
{
stages
,
jobs
}
from
'
../../mock_data
'
;
describe
(
'
IDE stages list
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
StageList
);
let
vm
;
beforeEach
(()
=>
{
const
store
=
createStore
();
vm
=
createComponentWithStore
(
Component
,
store
,
{
stages
:
stages
.
map
((
mappedState
,
i
)
=>
({
...
mappedState
,
id
:
i
,
dropdownPath
:
mappedState
.
dropdown_path
,
jobs
:
[...
jobs
],
isLoading
:
false
,
isCollapsed
:
false
,
})),
loading
:
false
,
});
spyOn
(
vm
,
'
fetchJobs
'
);
spyOn
(
vm
,
'
toggleStageCollapsed
'
);
vm
.
$mount
();
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
it
(
'
renders list of stages
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.card
'
).
length
).
toBe
(
2
);
});
it
(
'
renders loading icon when no stages & is loading
'
,
done
=>
{
vm
.
stages
=
[];
vm
.
loading
=
true
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.loading-container
'
)).
not
.
toBe
(
null
);
done
();
});
});
it
(
'
calls toggleStageCollapsed when clicking stage header
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.card-header
'
).
click
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
toggleStageCollapsed
).
toHaveBeenCalledWith
(
0
);
done
();
});
});
it
(
'
calls fetchJobs when stage is mounted
'
,
()
=>
{
expect
(
vm
.
fetchJobs
.
calls
.
count
()).
toBe
(
stages
.
length
);
expect
(
vm
.
fetchJobs
.
calls
.
argsFor
(
0
)).
toEqual
([
vm
.
stages
[
0
]]);
expect
(
vm
.
fetchJobs
.
calls
.
argsFor
(
1
)).
toEqual
([
vm
.
stages
[
1
]]);
});
});
spec/javascripts/ide/components/jobs/stage_spec.js
0 → 100644
View file @
fc5537c3
import
Vue
from
'
vue
'
;
import
Stage
from
'
~/ide/components/jobs/stage.vue
'
;
import
{
stages
,
jobs
}
from
'
../../mock_data
'
;
describe
(
'
IDE pipeline stage
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
Stage
);
let
vm
;
let
stage
;
beforeEach
(()
=>
{
stage
=
{
...
stages
[
0
],
id
:
0
,
dropdownPath
:
stages
[
0
].
dropdown_path
,
jobs
:
[...
jobs
],
isLoading
:
false
,
isCollapsed
:
false
,
};
vm
=
new
Component
({
propsData
:
{
stage
},
});
spyOn
(
vm
,
'
$emit
'
);
vm
.
$mount
();
});
afterEach
(()
=>
{
vm
.
$destroy
();
});
it
(
'
emits fetch event when mounted
'
,
()
=>
{
expect
(
vm
.
$emit
).
toHaveBeenCalledWith
(
'
fetch
'
,
vm
.
stage
);
});
it
(
'
renders stages details
'
,
()
=>
{
expect
(
vm
.
$el
.
textContent
).
toContain
(
vm
.
stage
.
name
);
});
it
(
'
renders CI icon
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.ic-status_failed
'
)).
not
.
toBe
(
null
);
});
describe
(
'
collapsed
'
,
()
=>
{
it
(
'
emits event when clicking header
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.card-header
'
).
click
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$emit
).
toHaveBeenCalledWith
(
'
toggleCollapsed
'
,
vm
.
stage
.
id
);
done
();
});
});
it
(
'
toggles collapse status when collapsed
'
,
done
=>
{
vm
.
stage
.
isCollapsed
=
true
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.card-body
'
).
style
.
display
).
toBe
(
'
none
'
);
done
();
});
});
it
(
'
sets border bottom class when collapsed
'
,
done
=>
{
vm
.
stage
.
isCollapsed
=
true
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.card-header
'
).
classList
).
toContain
(
'
border-bottom-0
'
);
done
();
});
});
});
it
(
'
renders jobs count
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.badge
'
).
textContent
).
toContain
(
'
4
'
);
});
it
(
'
renders loading icon when no jobs and isLoading is true
'
,
done
=>
{
vm
.
stage
.
isLoading
=
true
;
vm
.
stage
.
jobs
=
[];
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.loading-container
'
)).
not
.
toBe
(
null
);
done
();
});
});
it
(
'
renders list of jobs
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.ide-job-item
'
).
length
).
toBe
(
4
);
});
});
spec/javascripts/ide/components/pipelines/list_spec.js
0 → 100644
View file @
fc5537c3
import
Vue
from
'
vue
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
createStore
}
from
'
~/ide/stores
'
;
import
List
from
'
~/ide/components/pipelines/list.vue
'
;
import
{
createComponentWithStore
}
from
'
../../../helpers/vue_mount_component_helper
'
;
import
{
pipelines
,
projectData
,
stages
,
jobs
}
from
'
../../mock_data
'
;
describe
(
'
IDE pipelines list
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
List
);
let
vm
;
let
mock
;
beforeEach
(
done
=>
{
const
store
=
createStore
();
mock
=
new
MockAdapter
(
axios
);
store
.
state
.
currentProjectId
=
'
abc/def
'
;
store
.
state
.
currentBranchId
=
'
master
'
;
store
.
state
.
projects
[
'
abc/def
'
]
=
{
...
projectData
,
path_with_namespace
:
'
abc/def
'
,
branches
:
{
master
:
{
commit
:
{
id
:
'
123
'
}
},
},
};
store
.
state
.
links
=
{
ciHelpPagePath
:
gl
.
TEST_HOST
};
store
.
state
.
pipelinesEmptyStateSvgPath
=
gl
.
TEST_HOST
;
store
.
state
.
pipelines
.
stages
=
stages
.
map
((
mappedState
,
i
)
=>
({
...
mappedState
,
id
:
i
,
dropdownPath
:
mappedState
.
dropdown_path
,
jobs
:
[...
jobs
],
isLoading
:
false
,
isCollapsed
:
false
,
}));
mock
.
onGet
(
'
/abc/def/commit/123/pipelines
'
)
.
replyOnce
(
200
,
{
pipelines
:
[...
pipelines
]
},
{
'
poll-interval
'
:
'
-1
'
});
vm
=
createComponentWithStore
(
Component
,
store
).
$mount
();
setTimeout
(
done
);
});
afterEach
(()
=>
{
vm
.
$store
.
dispatch
(
'
pipelines/stopPipelinePolling
'
);
vm
.
$store
.
dispatch
(
'
pipelines/clearEtagPoll
'
);
vm
.
$destroy
();
mock
.
restore
();
});
it
(
'
renders pipeline data
'
,
()
=>
{
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
#1
'
);
});
it
(
'
renders CI icon
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.ci-status-icon-failed
'
)).
not
.
toBe
(
null
);
});
it
(
'
renders list of jobs
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.tab-pane:first-child .ide-job-item
'
).
length
).
toBe
(
jobs
.
length
*
stages
.
length
,
);
});
it
(
'
renders list of failed jobs on failed jobs tab
'
,
done
=>
{
vm
.
$el
.
querySelectorAll
(
'
.tab-links a
'
)[
1
].
click
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.tab-pane.active .ide-job-item
'
).
length
).
toBe
(
2
);
done
();
});
});
describe
(
'
YAML error
'
,
()
=>
{
it
(
'
renders YAML error
'
,
done
=>
{
vm
.
$store
.
state
.
pipelines
.
latestPipeline
.
yamlError
=
'
test yaml error
'
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
Found errors in your .gitlab-ci.yml:
'
);
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
test yaml error
'
);
done
();
});
});
});
describe
(
'
empty state
'
,
()
=>
{
it
(
'
renders pipelines empty state
'
,
done
=>
{
vm
.
$store
.
state
.
pipelines
.
latestPipeline
=
false
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.empty-state
'
)).
not
.
toBe
(
null
);
done
();
});
});
});
describe
(
'
loading state
'
,
()
=>
{
it
(
'
renders loading state when there is no latest pipeline
'
,
done
=>
{
vm
.
$store
.
state
.
pipelines
.
latestPipeline
=
null
;
vm
.
$store
.
state
.
pipelines
.
isLoadingPipeline
=
true
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.loading-container
'
)).
not
.
toBe
(
null
);
done
();
});
});
});
});
spec/javascripts/ide/helpers.js
View file @
fc5537c3
import
{
decorateData
}
from
'
~/ide/stores/utils
'
;
import
state
from
'
~/ide/stores/state
'
;
import
commitState
from
'
~/ide/stores/modules/commit/state
'
;
import
pipelinesState
from
'
~/ide/stores/modules/pipelines/state
'
;
export
const
resetStore
=
store
=>
{
const
newState
=
{
...
state
(),
commit
:
commitState
(),
pipelines
:
pipelinesState
(),
};
store
.
replaceState
(
newState
);
};
...
...
spec/javascripts/ide/mock_data.js
View file @
fc5537c3
...
...
@@ -19,13 +19,48 @@ export const pipelines = [
id
:
1
,
ref
:
'
master
'
,
sha
:
'
123
'
,
status
:
'
failed
'
,
details
:
{
status
:
{
icon
:
'
status_failed
'
,
group
:
'
failed
'
,
text
:
'
Failed
'
,
},
},
commit
:
{
id
:
'
123
'
},
},
{
id
:
2
,
ref
:
'
master
'
,
sha
:
'
213
'
,
status
:
'
success
'
,
details
:
{
status
:
{
icon
:
'
status_failed
'
,
group
:
'
failed
'
,
text
:
'
Failed
'
,
},
},
commit
:
{
id
:
'
213
'
},
},
];
export
const
stages
=
[
{
dropdown_path
:
`
${
gl
.
TEST_HOST
}
/testing`
,
name
:
'
build
'
,
status
:
{
icon
:
'
status_failed
'
,
group
:
'
failed
'
,
text
:
'
failed
'
,
},
},
{
dropdown_path
:
'
testing
'
,
name
:
'
test
'
,
status
:
{
icon
:
'
status_failed
'
,
group
:
'
failed
'
,
text
:
'
failed
'
,
},
},
];
...
...
@@ -33,28 +68,44 @@ export const jobs = [
{
id
:
1
,
name
:
'
test
'
,
status
:
'
failed
'
,
path
:
'
testing
'
,
status
:
{
icon
:
'
status_passed
'
,
text
:
'
passed
'
,
},
stage
:
'
test
'
,
duration
:
1
,
},
{
id
:
2
,
name
:
'
test 2
'
,
status
:
'
failed
'
,
path
:
'
testing2
'
,
status
:
{
icon
:
'
status_passed
'
,
text
:
'
passed
'
,
},
stage
:
'
test
'
,
duration
:
1
,
},
{
id
:
3
,
name
:
'
test 3
'
,
status
:
'
failed
'
,
path
:
'
testing3
'
,
status
:
{
icon
:
'
status_passed
'
,
text
:
'
passed
'
,
},
stage
:
'
test
'
,
duration
:
1
,
},
{
id
:
4
,
name
:
'
test 3
'
,
status
:
'
failed
'
,
name
:
'
test 4
'
,
path
:
'
testing4
'
,
status
:
{
icon
:
'
status_failed
'
,
text
:
'
failed
'
,
},
stage
:
'
build
'
,
duration
:
1
,
},
...
...
@@ -68,14 +119,16 @@ export const fullPipelinesResponse = {
pipelines
:
[
{
id
:
'
51
'
,
path
:
'
test
'
,
commit
:
{
id
:
'
xxxxxxxxxxxxxxxxxxxx
'
,
id
:
'
123
'
,
},
details
:
{
status
:
{
icon
:
'
status_failed
'
,
text
:
'
failed
'
,
},
stages
:
[...
stages
],
},
},
{
...
...
@@ -88,6 +141,7 @@ export const fullPipelinesResponse = {
icon
:
'
status_passed
'
,
text
:
'
passed
'
,
},
stages
:
[...
stages
],
},
},
],
...
...
spec/javascripts/ide/stores/actions/project_spec.js
View file @
fc5537c3
import
Visibility
from
'
visibilityjs
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
{
refreshLastCommitData
,
pollSuccessCallBack
}
from
'
~/ide/stores/actions
'
;
import
{
refreshLastCommitData
}
from
'
~/ide/stores/actions
'
;
import
store
from
'
~/ide/stores
'
;
import
service
from
'
~/ide/services
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
fullPipelinesResponse
}
from
'
../../mock_data
'
;
import
{
resetStore
}
from
'
../../helpers
'
;
import
testAction
from
'
../../../helpers/vuex_action_helper
'
;
describe
(
'
IDE store project actions
'
,
()
=>
{
const
setProjectState
=
()
=>
{
store
.
state
.
currentProjectId
=
'
abc/def
'
;
store
.
state
.
currentBranchId
=
'
master
'
;
store
.
state
.
projects
[
'
abc/def
'
]
=
{
id
:
4
,
path_with_namespace
:
'
abc/def
'
,
branches
:
{
master
:
{
commit
:
{
id
:
'
abc123def456ghi789jkl
'
,
title
:
'
example
'
,
},
},
},
};
};
beforeEach
(()
=>
{
store
.
state
.
projects
[
'
abc/def
'
]
=
{};
});
...
...
@@ -101,92 +80,4 @@ describe('IDE store project actions', () => {
);
});
});
describe
(
'
pipelinePoll
'
,
()
=>
{
let
mock
;
beforeEach
(()
=>
{
setProjectState
();
jasmine
.
clock
().
install
();
mock
=
new
MockAdapter
(
axios
);
mock
.
onGet
(
'
/abc/def/commit/abc123def456ghi789jkl/pipelines
'
)
.
reply
(
200
,
{
data
:
{
foo
:
'
bar
'
}
},
{
'
poll-interval
'
:
'
10000
'
});
});
afterEach
(()
=>
{
jasmine
.
clock
().
uninstall
();
mock
.
restore
();
store
.
dispatch
(
'
stopPipelinePolling
'
);
});
it
(
'
calls service periodically
'
,
done
=>
{
spyOn
(
axios
,
'
get
'
).
and
.
callThrough
();
spyOn
(
Visibility
,
'
hidden
'
).
and
.
returnValue
(
false
);
store
.
dispatch
(
'
pipelinePoll
'
)
.
then
(()
=>
{
jasmine
.
clock
().
tick
(
1000
);
expect
(
axios
.
get
).
toHaveBeenCalled
();
expect
(
axios
.
get
.
calls
.
count
()).
toBe
(
1
);
})
.
then
(()
=>
new
Promise
(
resolve
=>
requestAnimationFrame
(
resolve
)))
.
then
(()
=>
{
jasmine
.
clock
().
tick
(
10000
);
expect
(
axios
.
get
.
calls
.
count
()).
toBe
(
2
);
})
.
then
(()
=>
new
Promise
(
resolve
=>
requestAnimationFrame
(
resolve
)))
.
then
(()
=>
{
jasmine
.
clock
().
tick
(
10000
);
expect
(
axios
.
get
.
calls
.
count
()).
toBe
(
3
);
})
.
then
(()
=>
new
Promise
(
resolve
=>
requestAnimationFrame
(
resolve
)))
.
then
(()
=>
{
jasmine
.
clock
().
tick
(
10000
);
expect
(
axios
.
get
.
calls
.
count
()).
toBe
(
4
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
pollSuccessCallBack
'
,
()
=>
{
beforeEach
(()
=>
{
setProjectState
();
});
it
(
'
commits correct pipeline
'
,
done
=>
{
testAction
(
pollSuccessCallBack
,
fullPipelinesResponse
,
store
.
state
,
[
{
type
:
'
SET_LAST_COMMIT_PIPELINE
'
,
payload
:
{
projectId
:
'
abc/def
'
,
branchId
:
'
master
'
,
pipeline
:
{
id
:
'
50
'
,
commit
:
{
id
:
'
abc123def456ghi789jkl
'
,
},
details
:
{
status
:
{
icon
:
'
status_passed
'
,
text
:
'
passed
'
,
},
},
},
},
},
],
// mutations
[],
// action
done
,
);
});
});
});
spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
View file @
fc5537c3
This diff is collapsed.
Click to expand it.
spec/javascripts/ide/stores/modules/pipelines/getters_spec.js
View file @
fc5537c3
...
...
@@ -37,35 +37,4 @@ describe('IDE pipeline getters', () => {
expect
(
getters
.
hasLatestPipeline
(
mockedState
)).
toBe
(
true
);
});
});
describe
(
'
failedJobs
'
,
()
=>
{
it
(
'
returns array of failed jobs
'
,
()
=>
{
mockedState
.
stages
=
[
{
title
:
'
test
'
,
jobs
:
[{
id
:
1
,
status
:
'
failed
'
},
{
id
:
2
,
status
:
'
success
'
}],
},
{
title
:
'
build
'
,
jobs
:
[{
id
:
3
,
status
:
'
failed
'
},
{
id
:
4
,
status
:
'
failed
'
}],
},
];
expect
(
getters
.
failedJobs
(
mockedState
).
length
).
toBe
(
3
);
expect
(
getters
.
failedJobs
(
mockedState
)).
toEqual
([
{
id
:
1
,
status
:
jasmine
.
anything
(),
},
{
id
:
3
,
status
:
jasmine
.
anything
(),
},
{
id
:
4
,
status
:
jasmine
.
anything
(),
},
]);
});
});
});
spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js
View file @
fc5537c3
import
mutations
from
'
~/ide/stores/modules/pipelines/mutations
'
;
import
state
from
'
~/ide/stores/modules/pipelines/state
'
;
import
*
as
types
from
'
~/ide/stores/modules/pipelines/mutation_types
'
;
import
{
pipelin
es
,
jobs
}
from
'
../../../mock_data
'
;
import
{
fullPipelinesResponse
,
stag
es
,
jobs
}
from
'
../../../mock_data
'
;
describe
(
'
IDE pipelines mutations
'
,
()
=>
{
let
mockedState
;
...
...
@@ -28,93 +28,147 @@ describe('IDE pipelines mutations', () => {
describe
(
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
,
()
=>
{
it
(
'
sets loading to false on success
'
,
()
=>
{
mutations
[
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
](
mockedState
,
pipelines
[
0
]);
mutations
[
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
](
mockedState
,
fullPipelinesResponse
.
data
.
pipelines
[
0
],
);
expect
(
mockedState
.
isLoadingPipeline
).
toBe
(
false
);
});
it
(
'
sets latestPipeline
'
,
()
=>
{
mutations
[
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
](
mockedState
,
pipelines
[
0
]);
mutations
[
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
](
mockedState
,
fullPipelinesResponse
.
data
.
pipelines
[
0
],
);
expect
(
mockedState
.
latestPipeline
).
toEqual
({
id
:
pipelines
[
0
].
id
,
status
:
pipelines
[
0
].
status
,
id
:
'
51
'
,
path
:
'
test
'
,
commit
:
{
id
:
'
123
'
},
details
:
{
status
:
jasmine
.
any
(
Object
)
},
yamlError
:
undefined
,
});
});
it
(
'
does not set latest pipeline if pipeline is null
'
,
()
=>
{
mutations
[
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
](
mockedState
,
null
);
expect
(
mockedState
.
latestPipeline
).
toEqual
(
null
);
expect
(
mockedState
.
latestPipeline
).
toEqual
(
false
);
});
it
(
'
sets stages
'
,
()
=>
{
mutations
[
types
.
RECEIVE_LASTEST_PIPELINE_SUCCESS
](
mockedState
,
fullPipelinesResponse
.
data
.
pipelines
[
0
],
);
expect
(
mockedState
.
stages
.
length
).
toBe
(
2
);
expect
(
mockedState
.
stages
).
toEqual
([
{
id
:
0
,
dropdownPath
:
stages
[
0
].
dropdown_path
,
name
:
stages
[
0
].
name
,
status
:
stages
[
0
].
status
,
isCollapsed
:
false
,
isLoading
:
false
,
jobs
:
[],
},
{
id
:
1
,
dropdownPath
:
stages
[
1
].
dropdown_path
,
name
:
stages
[
1
].
name
,
status
:
stages
[
1
].
status
,
isCollapsed
:
false
,
isLoading
:
false
,
jobs
:
[],
},
]);
});
});
describe
(
types
.
REQUEST_JOBS
,
()
=>
{
it
(
'
sets jobs loading to true
'
,
()
=>
{
mutations
[
types
.
REQUEST_JOBS
](
mockedState
);
beforeEach
(()
=>
{
mockedState
.
stages
=
stages
.
map
((
stage
,
i
)
=>
({
...
stage
,
id
:
i
,
}));
});
it
(
'
sets isLoading on stage
'
,
()
=>
{
mutations
[
types
.
REQUEST_JOBS
](
mockedState
,
mockedState
.
stages
[
0
].
id
);
expect
(
mockedState
.
isLoadingJobs
).
toBe
(
true
);
expect
(
mockedState
.
stages
[
0
].
isLoading
).
toBe
(
true
);
});
});
describe
(
types
.
RECEIVE_JOBS_ERROR
,
()
=>
{
it
(
'
sets jobs loading to false
'
,
()
=>
{
mutations
[
types
.
RECEIVE_JOBS_ERROR
](
mockedState
);
beforeEach
(()
=>
{
mockedState
.
stages
=
stages
.
map
((
stage
,
i
)
=>
({
...
stage
,
id
:
i
,
}));
});
it
(
'
sets isLoading on stage after error
'
,
()
=>
{
mutations
[
types
.
RECEIVE_JOBS_ERROR
](
mockedState
,
mockedState
.
stages
[
0
].
id
);
expect
(
mockedState
.
isLoadingJobs
).
toBe
(
false
);
expect
(
mockedState
.
stages
[
0
].
isLoading
).
toBe
(
false
);
});
});
describe
(
types
.
RECEIVE_JOBS_SUCCESS
,
()
=>
{
it
(
'
sets jobs loading to false on success
'
,
()
=>
{
mutations
[
types
.
RECEIVE_JOBS_SUCCESS
](
mockedState
,
jobs
);
let
data
;
expect
(
mockedState
.
isLoadingJobs
).
toBe
(
false
);
beforeEach
(()
=>
{
mockedState
.
stages
=
stages
.
map
((
stage
,
i
)
=>
({
...
stage
,
id
:
i
,
}));
data
=
{
latest_statuses
:
[...
jobs
],
};
});
it
(
'
sets stages
'
,
()
=>
{
mutations
[
types
.
RECEIVE_JOBS_SUCCESS
](
mockedState
,
jobs
);
it
(
'
updates loading
'
,
()
=>
{
mutations
[
types
.
RECEIVE_JOBS_SUCCESS
](
mockedState
,
{
id
:
mockedState
.
stages
[
0
].
id
,
data
}
);
expect
(
mockedState
.
stages
.
length
).
toBe
(
2
);
expect
(
mockedState
.
stages
).
toEqual
([
{
title
:
'
test
'
,
jobs
:
jasmine
.
anything
(),
},
{
title
:
'
build
'
,
jobs
:
jasmine
.
anything
(),
},
]);
expect
(
mockedState
.
stages
[
0
].
isLoading
).
toBe
(
false
);
});
it
(
'
sets jobs in stages
'
,
()
=>
{
mutations
[
types
.
RECEIVE_JOBS_SUCCESS
](
mockedState
,
jobs
);
it
(
'
sets jobs on stage
'
,
()
=>
{
mutations
[
types
.
RECEIVE_JOBS_SUCCESS
](
mockedState
,
{
id
:
mockedState
.
stages
[
0
].
id
,
data
});
expect
(
mockedState
.
stages
[
0
].
jobs
.
length
).
toBe
(
jobs
.
length
);
expect
(
mockedState
.
stages
[
0
].
jobs
).
toEqual
(
jobs
.
map
(
job
=>
({
id
:
job
.
id
,
name
:
job
.
name
,
status
:
job
.
status
,
path
:
job
.
build_path
,
})),
);
});
});
expect
(
mockedState
.
stages
[
0
].
jobs
.
length
).
toBe
(
3
);
expect
(
mockedState
.
stages
[
1
].
jobs
.
length
).
toBe
(
1
);
expect
(
mockedState
.
stages
).
toEqual
([
{
title
:
jasmine
.
anything
(),
jobs
:
jobs
.
filter
(
job
=>
job
.
stage
===
'
test
'
).
map
(
job
=>
({
id
:
job
.
id
,
name
:
job
.
name
,
status
:
job
.
status
,
stage
:
job
.
stage
,
duration
:
job
.
duration
,
})),
},
{
title
:
jasmine
.
anything
(),
jobs
:
jobs
.
filter
(
job
=>
job
.
stage
===
'
build
'
).
map
(
job
=>
({
id
:
job
.
id
,
name
:
job
.
name
,
status
:
job
.
status
,
stage
:
job
.
stage
,
duration
:
job
.
duration
,
})),
},
]);
describe
(
types
.
TOGGLE_STAGE_COLLAPSE
,
()
=>
{
beforeEach
(()
=>
{
mockedState
.
stages
=
stages
.
map
((
stage
,
i
)
=>
({
...
stage
,
id
:
i
,
isCollapsed
:
false
,
}));
});
it
(
'
toggles collapsed state
'
,
()
=>
{
mutations
[
types
.
TOGGLE_STAGE_COLLAPSE
](
mockedState
,
mockedState
.
stages
[
0
].
id
);
expect
(
mockedState
.
stages
[
0
].
isCollapsed
).
toBe
(
true
);
mutations
[
types
.
TOGGLE_STAGE_COLLAPSE
](
mockedState
,
mockedState
.
stages
[
0
].
id
);
expect
(
mockedState
.
stages
[
0
].
isCollapsed
).
toBe
(
false
);
});
});
});
spec/javascripts/ide/stores/mutations/branch_spec.js
View file @
fc5537c3
...
...
@@ -37,40 +37,4 @@ describe('Multi-file store branch mutations', () => {
expect
(
localState
.
projects
.
Example
.
branches
.
master
.
commit
.
title
).
toBe
(
'
Example commit
'
);
});
});
describe
(
'
SET_LAST_COMMIT_PIPELINE
'
,
()
=>
{
it
(
'
sets the pipeline for the last commit on current project
'
,
()
=>
{
localState
.
projects
=
{
Example
:
{
branches
:
{
master
:
{
commit
:
{},
},
},
},
};
mutations
.
SET_LAST_COMMIT_PIPELINE
(
localState
,
{
projectId
:
'
Example
'
,
branchId
:
'
master
'
,
pipeline
:
{
id
:
'
50
'
,
details
:
{
status
:
{
icon
:
'
status_passed
'
,
text
:
'
passed
'
,
},
},
},
});
expect
(
localState
.
projects
.
Example
.
branches
.
master
.
commit
.
pipeline
.
id
).
toBe
(
'
50
'
);
expect
(
localState
.
projects
.
Example
.
branches
.
master
.
commit
.
pipeline
.
details
.
status
.
text
).
toBe
(
'
passed
'
,
);
expect
(
localState
.
projects
.
Example
.
branches
.
master
.
commit
.
pipeline
.
details
.
status
.
icon
).
toBe
(
'
status_passed
'
,
);
});
});
});
spec/javascripts/vue_shared/components/tabs/tab_spec.js
0 → 100644
View file @
fc5537c3
import
Vue
from
'
vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
Tab
from
'
~/vue_shared/components/tabs/tab.vue
'
;
describe
(
'
Tab component
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
Tab
);
let
vm
;
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
);
});
it
(
'
sets localActive to equal active
'
,
done
=>
{
vm
.
active
=
true
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
localActive
).
toBe
(
true
);
done
();
});
});
it
(
'
sets active class
'
,
done
=>
{
vm
.
active
=
true
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
classList
).
toContain
(
'
active
'
);
done
();
});
});
});
spec/javascripts/vue_shared/components/tabs/tabs_spec.js
0 → 100644
View file @
fc5537c3
import
Vue
from
'
vue
'
;
import
Tabs
from
'
~/vue_shared/components/tabs/tabs
'
;
import
Tab
from
'
~/vue_shared/components/tabs/tab.vue
'
;
describe
(
'
Tabs component
'
,
()
=>
{
let
vm
;
beforeEach
(
done
=>
{
vm
=
new
Vue
({
components
:
{
Tabs
,
Tab
,
},
template
:
`
<div>
<tabs>
<tab title="Testing" active>
First tab
</tab>
<tab>
<template slot="title">Test slot</template>
Second tab
</tab>
</tabs>
</div>
`
,
}).
$mount
();
setTimeout
(
done
);
});
describe
(
'
tab links
'
,
()
=>
{
it
(
'
renders links for tabs
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
a
'
).
length
).
toBe
(
2
);
});
it
(
'
renders link titles from props
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
textContent
).
toContain
(
'
Testing
'
);
});
it
(
'
renders link titles from slot
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
a
'
)[
1
].
textContent
).
toContain
(
'
Test slot
'
);
});
it
(
'
renders active class
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
classList
).
toContain
(
'
active
'
);
});
it
(
'
updates active class on click
'
,
done
=>
{
vm
.
$el
.
querySelectorAll
(
'
a
'
)[
1
].
click
();
setTimeout
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
a
'
).
classList
).
not
.
toContain
(
'
active
'
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
a
'
)[
1
].
classList
).
toContain
(
'
active
'
);
done
();
});
});
});
describe
(
'
content
'
,
()
=>
{
it
(
'
renders content panes
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.tab-pane
'
).
length
).
toBe
(
2
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.tab-pane
'
)[
0
].
textContent
).
toContain
(
'
First tab
'
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.tab-pane
'
)[
1
].
textContent
).
toContain
(
'
Second tab
'
);
});
});
});
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