added empty state & YAML error state
This commit is contained in:
parent
b4ef2aad02
commit
782c31a494
10 changed files with 88 additions and 18 deletions
|
@ -1,10 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||||
|
import { sprintf, __ } from '../../../locale';
|
||||||
import LoadingIcon from '../../../vue_shared/components/loading_icon.vue';
|
import LoadingIcon from '../../../vue_shared/components/loading_icon.vue';
|
||||||
import Icon from '../../../vue_shared/components/icon.vue';
|
import Icon from '../../../vue_shared/components/icon.vue';
|
||||||
import CiIcon from '../../../vue_shared/components/ci_icon.vue';
|
import CiIcon from '../../../vue_shared/components/ci_icon.vue';
|
||||||
import Tabs from '../../../vue_shared/components/tabs/tabs';
|
import Tabs from '../../../vue_shared/components/tabs/tabs';
|
||||||
import Tab from '../../../vue_shared/components/tabs/tab.vue';
|
import Tab from '../../../vue_shared/components/tabs/tab.vue';
|
||||||
|
import EmptyState from '../../../pipelines/components/empty_state.vue';
|
||||||
import JobsList from '../jobs/list.vue';
|
import JobsList from '../jobs/list.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -15,10 +17,23 @@ export default {
|
||||||
Tabs,
|
Tabs,
|
||||||
Tab,
|
Tab,
|
||||||
JobsList,
|
JobsList,
|
||||||
|
EmptyState,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(['pipelinesEmptyStateSvgPath']),
|
||||||
|
...mapGetters(['currentProject']),
|
||||||
...mapGetters('pipelines', ['jobsCount', 'failedJobsCount', 'failedStages', 'pipelineFailed']),
|
...mapGetters('pipelines', ['jobsCount', 'failedJobsCount', 'failedStages', 'pipelineFailed']),
|
||||||
...mapState('pipelines', ['isLoadingPipeline', 'latestPipeline', 'stages', 'isLoadingJobs']),
|
...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="${this.currentProject.web_url}/-/ci/lint">`,
|
||||||
|
linkEnd: '</a>',
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.fetchLatestPipeline();
|
this.fetchLatestPipeline();
|
||||||
|
@ -32,12 +47,13 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<div class="ide-pipeline">
|
<div class="ide-pipeline">
|
||||||
<loading-icon
|
<loading-icon
|
||||||
v-if="isLoadingPipeline && !latestPipeline"
|
v-if="isLoadingPipeline && latestPipeline === null"
|
||||||
class="prepend-top-default"
|
class="prepend-top-default"
|
||||||
size="2"
|
size="2"
|
||||||
/>
|
/>
|
||||||
<template v-else-if="latestPipeline">
|
<template v-else-if="latestPipeline !== null">
|
||||||
<header
|
<header
|
||||||
|
v-if="latestPipeline"
|
||||||
class="ide-tree-header ide-pipeline-header"
|
class="ide-tree-header ide-pipeline-header"
|
||||||
>
|
>
|
||||||
<ci-icon
|
<ci-icon
|
||||||
|
@ -61,7 +77,31 @@ export default {
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
<tabs class="ide-pipeline-list">
|
<empty-state
|
||||||
|
v-if="latestPipeline === false"
|
||||||
|
help-page-path="a"
|
||||||
|
: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
|
<tab
|
||||||
:active="!pipelineFailed"
|
:active="!pipelineFailed"
|
||||||
>
|
>
|
||||||
|
@ -105,6 +145,7 @@ export default {
|
||||||
.ide-pipeline {
|
.ide-pipeline {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ide-pipeline-list {
|
.ide-pipeline-list {
|
||||||
|
@ -121,4 +162,9 @@ export default {
|
||||||
.ide-pipeline-header .ci-status-icon {
|
.ide-pipeline-header .ci-status-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ide-pipeline .empty-state {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -21,6 +21,7 @@ export function initIde(el) {
|
||||||
emptyStateSvgPath: el.dataset.emptyStateSvgPath,
|
emptyStateSvgPath: el.dataset.emptyStateSvgPath,
|
||||||
noChangesStateSvgPath: el.dataset.noChangesStateSvgPath,
|
noChangesStateSvgPath: el.dataset.noChangesStateSvgPath,
|
||||||
committedStateSvgPath: el.dataset.committedStateSvgPath,
|
committedStateSvgPath: el.dataset.committedStateSvgPath,
|
||||||
|
pipelinesEmptyStateSvgPath: el.dataset.pipelinesEmptyStateSvgPath,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
render(createElement) {
|
render(createElement) {
|
||||||
|
|
|
@ -19,12 +19,14 @@ export const receiveLatestPipelineError = ({ commit, dispatch }) => {
|
||||||
dispatch('stopPipelinePolling');
|
dispatch('stopPipelinePolling');
|
||||||
};
|
};
|
||||||
export const receiveLatestPipelineSuccess = ({ rootGetters, commit }, { pipelines }) => {
|
export const receiveLatestPipelineSuccess = ({ rootGetters, commit }, { pipelines }) => {
|
||||||
|
let lastCommitPipeline = false;
|
||||||
|
|
||||||
if (pipelines && pipelines.length) {
|
if (pipelines && pipelines.length) {
|
||||||
const lastCommitHash = rootGetters.lastCommit && rootGetters.lastCommit.id;
|
const lastCommitHash = rootGetters.lastCommit && rootGetters.lastCommit.id;
|
||||||
const lastCommitPipeline = pipelines.find(pipeline => pipeline.commit.id === lastCommitHash);
|
lastCommitPipeline = pipelines.find(pipeline => pipeline.commit.id === lastCommitHash);
|
||||||
|
}
|
||||||
|
|
||||||
commit(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, lastCommitPipeline);
|
commit(types.RECEIVE_LASTEST_PIPELINE_SUCCESS, lastCommitPipeline);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchLatestPipeline = ({ dispatch, rootGetters }) => {
|
export const fetchLatestPipeline = ({ dispatch, rootGetters }) => {
|
||||||
|
|
|
@ -19,6 +19,7 @@ export default {
|
||||||
details: {
|
details: {
|
||||||
status: pipeline.details.status,
|
status: pipeline.details.status,
|
||||||
},
|
},
|
||||||
|
yamlError: pipeline.yaml_errors,
|
||||||
};
|
};
|
||||||
state.stages = pipeline.details.stages.map((stage, i) => {
|
state.stages = pipeline.details.stages.map((stage, i) => {
|
||||||
const foundStage = state.stages.find(s => s.id === i);
|
const foundStage = state.stages.find(s => s.id === i);
|
||||||
|
@ -32,6 +33,8 @@ export default {
|
||||||
jobs: foundStage ? foundStage.jobs : [],
|
jobs: foundStage ? foundStage.jobs : [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
state.latestPipeline = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[types.REQUEST_JOBS](state, id) {
|
[types.REQUEST_JOBS](state, id) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export default () => ({
|
export default () => ({
|
||||||
isLoadingPipeline: false,
|
isLoadingPipeline: true,
|
||||||
isLoadingJobs: false,
|
isLoadingJobs: false,
|
||||||
latestPipeline: null,
|
latestPipeline: null,
|
||||||
stages: [],
|
stages: [],
|
||||||
|
|
|
@ -114,12 +114,13 @@ export default {
|
||||||
},
|
},
|
||||||
[types.SET_EMPTY_STATE_SVGS](
|
[types.SET_EMPTY_STATE_SVGS](
|
||||||
state,
|
state,
|
||||||
{ emptyStateSvgPath, noChangesStateSvgPath, committedStateSvgPath },
|
{ emptyStateSvgPath, noChangesStateSvgPath, committedStateSvgPath, pipelinesEmptyStateSvgPath },
|
||||||
) {
|
) {
|
||||||
Object.assign(state, {
|
Object.assign(state, {
|
||||||
emptyStateSvgPath,
|
emptyStateSvgPath,
|
||||||
noChangesStateSvgPath,
|
noChangesStateSvgPath,
|
||||||
committedStateSvgPath,
|
committedStateSvgPath,
|
||||||
|
pipelinesEmptyStateSvgPath,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[types.TOGGLE_FILE_FINDER](state, fileFindVisible) {
|
[types.TOGGLE_FILE_FINDER](state, fileFindVisible) {
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#ide.ide-loading{ data: {"empty-state-svg-path" => image_path('illustrations/multi_file_editor_empty.svg'),
|
#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'),
|
"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') } }
|
||||||
.text-center
|
.text-center
|
||||||
= icon('spinner spin 2x')
|
= icon('spinner spin 2x')
|
||||||
%h2.clgray= _('Loading the GitLab IDE...')
|
%h2.clgray= _('Loading the GitLab IDE...')
|
||||||
|
|
|
@ -20,12 +20,14 @@ export const pipelines = [
|
||||||
ref: 'master',
|
ref: 'master',
|
||||||
sha: '123',
|
sha: '123',
|
||||||
status: 'failed',
|
status: 'failed',
|
||||||
|
commit: { id: '123' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
ref: 'master',
|
ref: 'master',
|
||||||
sha: '213',
|
sha: '213',
|
||||||
status: 'success',
|
status: 'success',
|
||||||
|
commit: { id: '213' },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -65,15 +65,28 @@ describe('IDE pipelines actions', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('receiveLatestPipelineSuccess', () => {
|
describe('receiveLatestPipelineSuccess', () => {
|
||||||
it('commits pipeline', done => {
|
const rootGetters = {
|
||||||
testAction(
|
lastCommit: { id: '123' },
|
||||||
receiveLatestPipelineSuccess,
|
};
|
||||||
|
let commit;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
commit = jasmine.createSpy('commit');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('commits pipeline', () => {
|
||||||
|
receiveLatestPipelineSuccess({ rootGetters, commit }, { pipelines });
|
||||||
|
|
||||||
|
expect(commit.calls.argsFor(0)).toEqual([
|
||||||
|
types.RECEIVE_LASTEST_PIPELINE_SUCCESS,
|
||||||
pipelines[0],
|
pipelines[0],
|
||||||
mockedState,
|
]);
|
||||||
[{ type: types.RECEIVE_LASTEST_PIPELINE_SUCCESS, payload: pipelines[0] }],
|
});
|
||||||
[],
|
|
||||||
done,
|
it('commits false when there are no pipelines', () => {
|
||||||
);
|
receiveLatestPipelineSuccess({ rootGetters, commit }, { pipelines: [] });
|
||||||
|
|
||||||
|
expect(commit.calls.argsFor(0)).toEqual([types.RECEIVE_LASTEST_PIPELINE_SUCCESS, false]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,14 @@ describe('IDE pipelines mutations', () => {
|
||||||
path: 'test',
|
path: 'test',
|
||||||
commit: { id: '123' },
|
commit: { id: '123' },
|
||||||
details: { status: jasmine.any(Object) },
|
details: { status: jasmine.any(Object) },
|
||||||
|
yamlError: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not set latest pipeline if pipeline is null', () => {
|
it('does not set latest pipeline if pipeline is null', () => {
|
||||||
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](mockedState, null);
|
mutations[types.RECEIVE_LASTEST_PIPELINE_SUCCESS](mockedState, null);
|
||||||
|
|
||||||
expect(mockedState.latestPipeline).toEqual(null);
|
expect(mockedState.latestPipeline).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets stages', () => {
|
it('sets stages', () => {
|
||||||
|
|
Loading…
Reference in a new issue