2020-10-30 12:08:44 +00:00
|
|
|
<script>
|
2021-02-03 21:09:17 +00:00
|
|
|
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
|
2021-01-13 15:10:40 +00:00
|
|
|
import httpStatusCodes from '~/lib/utils/http_status';
|
2021-03-01 21:11:09 +00:00
|
|
|
import { __, s__ } from '~/locale';
|
2020-10-30 21:08:52 +00:00
|
|
|
|
2021-02-01 15:08:56 +00:00
|
|
|
import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
|
2021-01-28 21:09:04 +00:00
|
|
|
import ConfirmUnsavedChangesDialog from './components/ui/confirm_unsaved_changes_dialog.vue';
|
2021-03-01 21:11:09 +00:00
|
|
|
import PipelineEditorEmptyState from './components/ui/pipeline_editor_empty_state.vue';
|
|
|
|
import { COMMIT_FAILURE, COMMIT_SUCCESS, DEFAULT_FAILURE, LOAD_FAILURE_UNKNOWN } from './constants';
|
2020-10-30 21:08:52 +00:00
|
|
|
import getBlobContent from './graphql/queries/blob_content.graphql';
|
2020-12-08 21:10:06 +00:00
|
|
|
import getCiConfigData from './graphql/queries/ci_config.graphql';
|
2021-02-03 21:09:17 +00:00
|
|
|
import PipelineEditorHome from './pipeline_editor_home.vue';
|
2020-11-20 21:09:12 +00:00
|
|
|
|
2020-10-30 12:08:44 +00:00
|
|
|
export default {
|
|
|
|
components: {
|
2021-01-28 21:09:04 +00:00
|
|
|
ConfirmUnsavedChangesDialog,
|
2020-10-30 21:08:52 +00:00
|
|
|
GlAlert,
|
2020-11-20 21:09:12 +00:00
|
|
|
GlLoadingIcon,
|
2021-03-01 21:11:09 +00:00
|
|
|
PipelineEditorEmptyState,
|
2021-02-03 21:09:17 +00:00
|
|
|
PipelineEditorHome,
|
2020-10-30 21:08:52 +00:00
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
inject: {
|
|
|
|
ciConfigPath: {
|
|
|
|
default: '',
|
2020-10-30 21:08:52 +00:00
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
defaultBranch: {
|
2020-11-20 21:09:12 +00:00
|
|
|
default: null,
|
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
projectFullPath: {
|
|
|
|
default: '',
|
2020-11-20 21:09:12 +00:00
|
|
|
},
|
2020-10-30 21:08:52 +00:00
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2020-12-08 21:10:06 +00:00
|
|
|
ciConfigData: {},
|
2020-12-23 06:10:22 +00:00
|
|
|
// Success and failure state
|
|
|
|
failureType: null,
|
|
|
|
failureReasons: [],
|
2021-03-01 21:11:09 +00:00
|
|
|
hasNoCiConfigFile: false,
|
2021-02-03 21:09:17 +00:00
|
|
|
initialCiFileContent: '',
|
|
|
|
lastCommittedContent: '',
|
|
|
|
currentCiFileContent: '',
|
|
|
|
showFailureAlert: false,
|
2020-12-23 06:10:22 +00:00
|
|
|
showSuccessAlert: false,
|
2021-02-03 21:09:17 +00:00
|
|
|
successType: null,
|
2020-10-30 21:08:52 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
apollo: {
|
2021-02-03 21:09:17 +00:00
|
|
|
initialCiFileContent: {
|
2020-10-30 21:08:52 +00:00
|
|
|
query: getBlobContent,
|
|
|
|
variables() {
|
|
|
|
return {
|
2021-01-09 00:10:30 +00:00
|
|
|
projectPath: this.projectFullPath,
|
2020-10-30 21:08:52 +00:00
|
|
|
path: this.ciConfigPath,
|
|
|
|
ref: this.defaultBranch,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
update(data) {
|
2021-02-03 21:09:17 +00:00
|
|
|
return data?.blobContent?.rawData;
|
2020-10-30 21:08:52 +00:00
|
|
|
},
|
2020-11-20 21:09:12 +00:00
|
|
|
result({ data }) {
|
2021-02-03 21:09:17 +00:00
|
|
|
const fileContent = data?.blobContent?.rawData ?? '';
|
|
|
|
|
|
|
|
this.lastCommittedContent = fileContent;
|
|
|
|
this.currentCiFileContent = fileContent;
|
2020-11-20 21:09:12 +00:00
|
|
|
},
|
2020-10-30 21:08:52 +00:00
|
|
|
error(error) {
|
2020-11-20 21:09:12 +00:00
|
|
|
this.handleBlobContentError(error);
|
2020-10-30 21:08:52 +00:00
|
|
|
},
|
|
|
|
},
|
2020-12-08 21:10:06 +00:00
|
|
|
ciConfigData: {
|
|
|
|
query: getCiConfigData,
|
|
|
|
// If content is not loaded, we can't lint the data
|
2021-02-03 21:09:17 +00:00
|
|
|
skip: ({ currentCiFileContent }) => {
|
|
|
|
return !currentCiFileContent;
|
2020-12-08 21:10:06 +00:00
|
|
|
},
|
|
|
|
variables() {
|
|
|
|
return {
|
2021-01-09 00:10:30 +00:00
|
|
|
projectPath: this.projectFullPath,
|
2021-02-03 21:09:17 +00:00
|
|
|
content: this.currentCiFileContent,
|
2020-12-08 21:10:06 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
update(data) {
|
2020-12-17 21:09:57 +00:00
|
|
|
const { ciConfig } = data || {};
|
|
|
|
const stageNodes = ciConfig?.stages?.nodes || [];
|
2020-12-15 18:10:06 +00:00
|
|
|
const stages = unwrapStagesWithNeeds(stageNodes);
|
|
|
|
|
2020-12-17 21:09:57 +00:00
|
|
|
return { ...ciConfig, stages };
|
2020-12-08 21:10:06 +00:00
|
|
|
},
|
|
|
|
error() {
|
|
|
|
this.reportFailure(LOAD_FAILURE_UNKNOWN);
|
|
|
|
},
|
|
|
|
},
|
2020-10-30 21:08:52 +00:00
|
|
|
},
|
|
|
|
computed: {
|
2021-01-28 21:09:04 +00:00
|
|
|
hasUnsavedChanges() {
|
2021-02-03 21:09:17 +00:00
|
|
|
return this.lastCommittedContent !== this.currentCiFileContent;
|
2021-01-28 21:09:04 +00:00
|
|
|
},
|
2020-12-08 21:10:06 +00:00
|
|
|
isBlobContentLoading() {
|
2021-02-03 21:09:17 +00:00
|
|
|
return this.$apollo.queries.initialCiFileContent.loading;
|
2020-10-30 21:08:52 +00:00
|
|
|
},
|
2020-12-22 15:09:51 +00:00
|
|
|
isCiConfigDataLoading() {
|
2020-12-16 15:10:18 +00:00
|
|
|
return this.$apollo.queries.ciConfigData.loading;
|
|
|
|
},
|
2020-11-20 21:09:12 +00:00
|
|
|
failure() {
|
|
|
|
switch (this.failureType) {
|
|
|
|
case LOAD_FAILURE_UNKNOWN:
|
|
|
|
return {
|
2021-02-03 21:09:17 +00:00
|
|
|
text: this.$options.errorTexts[LOAD_FAILURE_UNKNOWN],
|
2020-11-20 21:09:12 +00:00
|
|
|
variant: 'danger',
|
|
|
|
};
|
|
|
|
case COMMIT_FAILURE:
|
|
|
|
return {
|
2021-02-03 21:09:17 +00:00
|
|
|
text: this.$options.errorTexts[COMMIT_FAILURE],
|
2020-11-20 21:09:12 +00:00
|
|
|
variant: 'danger',
|
|
|
|
};
|
|
|
|
default:
|
|
|
|
return {
|
2021-02-03 21:09:17 +00:00
|
|
|
text: this.$options.errorTexts[DEFAULT_FAILURE],
|
2020-11-20 21:09:12 +00:00
|
|
|
variant: 'danger',
|
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
success() {
|
|
|
|
switch (this.successType) {
|
|
|
|
case COMMIT_SUCCESS:
|
|
|
|
return {
|
|
|
|
text: this.$options.successTexts[COMMIT_SUCCESS],
|
|
|
|
variant: 'info',
|
|
|
|
};
|
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
},
|
2020-10-30 12:08:44 +00:00
|
|
|
},
|
|
|
|
i18n: {
|
2020-11-03 15:09:05 +00:00
|
|
|
tabEdit: s__('Pipelines|Write pipeline configuration'),
|
|
|
|
tabGraph: s__('Pipelines|Visualize'),
|
2020-12-22 15:09:51 +00:00
|
|
|
tabLint: s__('Pipelines|Lint'),
|
2020-10-30 12:08:44 +00:00
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
errorTexts: {
|
2020-12-23 06:10:22 +00:00
|
|
|
[COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
|
|
|
|
[DEFAULT_FAILURE]: __('Something went wrong on our end.'),
|
2020-11-20 21:09:12 +00:00
|
|
|
[LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'),
|
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
successTexts: {
|
|
|
|
[COMMIT_SUCCESS]: __('Your changes have been successfully committed.'),
|
|
|
|
},
|
2020-11-20 21:09:12 +00:00
|
|
|
methods: {
|
|
|
|
handleBlobContentError(error = {}) {
|
|
|
|
const { networkError } = error;
|
|
|
|
|
|
|
|
const { response } = networkError;
|
2021-01-13 15:10:40 +00:00
|
|
|
// 404 for missing CI file
|
|
|
|
// 400 for blank projects with no repository
|
|
|
|
if (
|
|
|
|
response?.status === httpStatusCodes.NOT_FOUND ||
|
|
|
|
response?.status === httpStatusCodes.BAD_REQUEST
|
|
|
|
) {
|
2021-03-01 21:11:09 +00:00
|
|
|
this.hasNoCiConfigFile = true;
|
2020-11-20 21:09:12 +00:00
|
|
|
} else {
|
|
|
|
this.reportFailure(LOAD_FAILURE_UNKNOWN);
|
|
|
|
}
|
|
|
|
},
|
2020-12-23 06:10:22 +00:00
|
|
|
|
2020-11-20 21:09:12 +00:00
|
|
|
dismissFailure() {
|
|
|
|
this.showFailureAlert = false;
|
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
dismissSuccess() {
|
|
|
|
this.showSuccessAlert = false;
|
|
|
|
},
|
2020-11-20 21:09:12 +00:00
|
|
|
reportFailure(type, reasons = []) {
|
2021-02-23 18:10:40 +00:00
|
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
2020-11-20 21:09:12 +00:00
|
|
|
this.showFailureAlert = true;
|
|
|
|
this.failureType = type;
|
|
|
|
this.failureReasons = reasons;
|
|
|
|
},
|
2020-12-23 06:10:22 +00:00
|
|
|
reportSuccess(type) {
|
2021-02-23 18:10:40 +00:00
|
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
2020-12-23 06:10:22 +00:00
|
|
|
this.showSuccessAlert = true;
|
|
|
|
this.successType = type;
|
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
resetContent() {
|
|
|
|
this.currentCiFileContent = this.lastCommittedContent;
|
2020-11-20 21:09:12 +00:00
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
showErrorAlert({ type, reasons = [] }) {
|
|
|
|
this.reportFailure(type, reasons);
|
2020-11-20 21:09:12 +00:00
|
|
|
},
|
2021-02-03 21:09:17 +00:00
|
|
|
updateCiConfig(ciFileContent) {
|
|
|
|
this.currentCiFileContent = ciFileContent;
|
|
|
|
},
|
|
|
|
updateOnCommit({ type }) {
|
|
|
|
this.reportSuccess(type);
|
|
|
|
// Keep track of the latest commited content to know
|
|
|
|
// if the user has made changes to the file that are unsaved.
|
|
|
|
this.lastCommittedContent = this.currentCiFileContent;
|
2020-11-20 21:09:12 +00:00
|
|
|
},
|
|
|
|
},
|
2020-10-30 12:08:44 +00:00
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2021-03-01 21:11:09 +00:00
|
|
|
<div class="gl-mt-4 gl-relative">
|
2021-01-13 15:10:40 +00:00
|
|
|
<gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" />
|
2021-03-01 21:11:09 +00:00
|
|
|
<pipeline-editor-empty-state v-else-if="hasNoCiConfigFile" />
|
|
|
|
<div v-else>
|
|
|
|
<gl-alert v-if="showSuccessAlert" :variant="success.variant" @dismiss="dismissSuccess">
|
|
|
|
{{ success.text }}
|
|
|
|
</gl-alert>
|
|
|
|
<gl-alert v-if="showFailureAlert" :variant="failure.variant" @dismiss="dismissFailure">
|
|
|
|
{{ failure.text }}
|
|
|
|
<ul v-if="failureReasons.length" class="gl-mb-0">
|
|
|
|
<li v-for="reason in failureReasons" :key="reason">{{ reason }}</li>
|
|
|
|
</ul>
|
|
|
|
</gl-alert>
|
2021-02-03 21:09:17 +00:00
|
|
|
<pipeline-editor-home
|
|
|
|
:is-ci-config-data-loading="isCiConfigDataLoading"
|
|
|
|
:ci-config-data="ciConfigData"
|
|
|
|
:ci-file-content="currentCiFileContent"
|
|
|
|
@commit="updateOnCommit"
|
|
|
|
@resetContent="resetContent"
|
|
|
|
@showError="showErrorAlert"
|
|
|
|
@updateCiConfig="updateCiConfig"
|
2020-11-20 21:09:12 +00:00
|
|
|
/>
|
2021-03-01 21:11:09 +00:00
|
|
|
<confirm-unsaved-changes-dialog :has-unsaved-changes="hasUnsavedChanges" />
|
2020-10-30 21:08:52 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2020-10-30 12:08:44 +00:00
|
|
|
</template>
|