Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue')
-rw-r--r--app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue164
1 files changed, 108 insertions, 56 deletions
diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue
index 96dc782964b..21993e2120a 100644
--- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue
+++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue
@@ -1,12 +1,16 @@
<script>
-import { GlAlert, GlLoadingIcon, GlTab, GlTabs } from '@gitlab/ui';
+import { GlAlert, GlLoadingIcon, GlTabs, GlTab } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale';
-import { mergeUrlParams, redirectTo, refreshCurrentPage } from '~/lib/utils/url_utility';
+import { mergeUrlParams, redirectTo } from '~/lib/utils/url_utility';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import httpStatusCodes from '~/lib/utils/http_status';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
+import CiLint from './components/lint/ci_lint.vue';
import CommitForm from './components/commit/commit_form.vue';
+import EditorTab from './components/ui/editor_tab.vue';
import TextEditor from './components/text_editor.vue';
+import ValidationSegment from './components/info/validation_segment.vue';
import commitCiFileMutation from './graphql/mutations/commit_ci_file.mutation.graphql';
import getBlobContent from './graphql/queries/blob_content.graphql';
@@ -17,33 +21,33 @@ const MR_SOURCE_BRANCH = 'merge_request[source_branch]';
const MR_TARGET_BRANCH = 'merge_request[target_branch]';
const COMMIT_FAILURE = 'COMMIT_FAILURE';
+const COMMIT_SUCCESS = 'COMMIT_SUCCESS';
const DEFAULT_FAILURE = 'DEFAULT_FAILURE';
const LOAD_FAILURE_NO_FILE = 'LOAD_FAILURE_NO_FILE';
-const LOAD_FAILURE_NO_REF = 'LOAD_FAILURE_NO_REF';
const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN';
export default {
components: {
+ CiLint,
CommitForm,
+ EditorTab,
GlAlert,
GlLoadingIcon,
- GlTab,
GlTabs,
+ GlTab,
PipelineGraph,
TextEditor,
+ ValidationSegment,
},
mixins: [glFeatureFlagsMixin()],
+ inject: ['projectFullPath'],
props: {
- projectPath: {
- type: String,
- required: true,
- },
defaultBranch: {
type: String,
required: false,
default: null,
},
- commitId: {
+ commitSha: {
type: String,
required: false,
default: null,
@@ -62,12 +66,15 @@ export default {
ciConfigData: {},
content: '',
contentModel: '',
- currentTabIndex: 0,
- editorIsReady: false,
- failureType: null,
- failureReasons: [],
+ lastCommitSha: this.commitSha,
isSaving: false,
+
+ // Success and failure state
+ failureType: null,
showFailureAlert: false,
+ failureReasons: [],
+ successType: null,
+ showSuccessAlert: false,
};
},
apollo: {
@@ -75,7 +82,7 @@ export default {
query: getBlobContent,
variables() {
return {
- projectPath: this.projectPath,
+ projectPath: this.projectFullPath,
path: this.ciConfigPath,
ref: this.defaultBranch,
};
@@ -98,15 +105,16 @@ export default {
},
variables() {
return {
+ projectPath: this.projectFullPath,
content: this.contentModel,
};
},
update(data) {
- const { ciConfigData } = data || {};
- const stageNodes = ciConfigData?.stages?.nodes || [];
+ const { ciConfig } = data || {};
+ const stageNodes = ciConfig?.stages?.nodes || [];
const stages = unwrapStagesWithNeeds(stageNodes);
- return { ...ciConfigData, stages };
+ return { ...ciConfig, stages };
},
error() {
this.reportFailure(LOAD_FAILURE_UNKNOWN);
@@ -117,40 +125,48 @@ export default {
isBlobContentLoading() {
return this.$apollo.queries.content.loading;
},
- isVisualizationTabLoading() {
- return this.$apollo.queries.ciConfigData.loading;
+ isBlobContentError() {
+ return this.failureType === LOAD_FAILURE_NO_FILE;
},
- isVisualizeTabActive() {
- return this.currentTabIndex === 1;
+ isCiConfigDataLoading() {
+ return this.$apollo.queries.ciConfigData.loading;
},
defaultCommitMessage() {
return sprintf(this.$options.i18n.defaultCommitMessage, { sourcePath: this.ciConfigPath });
},
- failure() {
- switch (this.failureType) {
- case LOAD_FAILURE_NO_REF:
+ success() {
+ switch (this.successType) {
+ case COMMIT_SUCCESS:
return {
- text: this.$options.errorTexts[LOAD_FAILURE_NO_REF],
- variant: 'danger',
+ text: this.$options.alertTexts[COMMIT_SUCCESS],
+ variant: 'info',
};
+ default:
+ return null;
+ }
+ },
+ failure() {
+ switch (this.failureType) {
case LOAD_FAILURE_NO_FILE:
return {
- text: this.$options.errorTexts[LOAD_FAILURE_NO_FILE],
+ text: sprintf(this.$options.alertTexts[LOAD_FAILURE_NO_FILE], {
+ filePath: this.ciConfigPath,
+ }),
variant: 'danger',
};
case LOAD_FAILURE_UNKNOWN:
return {
- text: this.$options.errorTexts[LOAD_FAILURE_UNKNOWN],
+ text: this.$options.alertTexts[LOAD_FAILURE_UNKNOWN],
variant: 'danger',
};
case COMMIT_FAILURE:
return {
- text: this.$options.errorTexts[COMMIT_FAILURE],
+ text: this.$options.alertTexts[COMMIT_FAILURE],
variant: 'danger',
};
default:
return {
- text: this.$options.errorTexts[DEFAULT_FAILURE],
+ text: this.$options.alertTexts[DEFAULT_FAILURE],
variant: 'danger',
};
}
@@ -160,30 +176,34 @@ export default {
defaultCommitMessage: __('Update %{sourcePath} file'),
tabEdit: s__('Pipelines|Write pipeline configuration'),
tabGraph: s__('Pipelines|Visualize'),
+ tabLint: s__('Pipelines|Lint'),
},
- errorTexts: {
- [LOAD_FAILURE_NO_REF]: s__(
- 'Pipelines|Repository does not have a default branch, please set one.',
+ alertTexts: {
+ [COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
+ [COMMIT_SUCCESS]: __('Your changes have been successfully committed.'),
+ [DEFAULT_FAILURE]: __('Something went wrong on our end.'),
+ [LOAD_FAILURE_NO_FILE]: s__(
+ 'Pipelines|There is no %{filePath} file in this repository, please add one and visit the Pipeline Editor again.',
),
- [LOAD_FAILURE_NO_FILE]: s__('Pipelines|No CI file found in this repository, please add one.'),
[LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'),
- [COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
},
methods: {
handleBlobContentError(error = {}) {
const { networkError } = error;
const { response } = networkError;
- if (response?.status === 404) {
- // 404 for missing CI file
+ // 404 for missing CI file
+ // 400 for blank projects with no repository
+ if (
+ response?.status === httpStatusCodes.NOT_FOUND ||
+ response?.status === httpStatusCodes.BAD_REQUEST
+ ) {
this.reportFailure(LOAD_FAILURE_NO_FILE);
- } else if (response?.status === 400) {
- // 400 for a missing ref when no default branch is set
- this.reportFailure(LOAD_FAILURE_NO_REF);
} else {
this.reportFailure(LOAD_FAILURE_UNKNOWN);
}
},
+
dismissFailure() {
this.showFailureAlert = false;
},
@@ -192,6 +212,14 @@ export default {
this.failureType = type;
this.failureReasons = reasons;
},
+ dismissSuccess() {
+ this.showSuccessAlert = false;
+ },
+ reportSuccess(type) {
+ this.showSuccessAlert = true;
+ this.successType = type;
+ },
+
redirectToNewMergeRequest(sourceBranch) {
const url = mergeUrlParams(
{
@@ -209,18 +237,18 @@ export default {
try {
const {
data: {
- commitCreate: { errors },
+ commitCreate: { errors, commit },
},
} = await this.$apollo.mutate({
mutation: commitCiFileMutation,
variables: {
- projectPath: this.projectPath,
+ projectPath: this.projectFullPath,
branch,
startBranch: this.defaultBranch,
message,
filePath: this.ciConfigPath,
content: this.contentModel,
- lastCommitId: this.commitId,
+ lastCommitId: this.lastCommitSha,
},
});
@@ -232,8 +260,10 @@ export default {
if (openMergeRequest) {
this.redirectToNewMergeRequest(branch);
} else {
- // Refresh the page to ensure commit is updated
- refreshCurrentPage();
+ this.reportSuccess(COMMIT_SUCCESS);
+
+ // Update latest commit
+ this.lastCommitSha = commit.sha;
}
} catch (error) {
this.reportFailure(COMMIT_FAILURE, [error?.message]);
@@ -251,6 +281,14 @@ export default {
<template>
<div class="gl-mt-4">
<gl-alert
+ v-if="showSuccessAlert"
+ :variant="success.variant"
+ :dismissible="true"
+ @dismiss="dismissSuccess"
+ >
+ {{ success.text }}
+ </gl-alert>
+ <gl-alert
v-if="showFailureAlert"
:variant="failure.variant"
:dismissible="true"
@@ -261,25 +299,39 @@ export default {
<li v-for="reason in failureReasons" :key="reason">{{ reason }}</li>
</ul>
</gl-alert>
- <div class="gl-mt-4">
- <gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" />
- <div v-else class="file-editor gl-mb-3">
- <gl-tabs v-model="currentTabIndex">
- <!-- editor should be mounted when its tab is visible, so the container has a size -->
- <gl-tab :title="$options.i18n.tabEdit" :lazy="!editorIsReady">
- <!-- editor should be mounted only once, when the tab is displayed -->
- <text-editor v-model="contentModel" @editor-ready="editorIsReady = true" />
- </gl-tab>
+ <gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" />
+ <div v-else-if="!isBlobContentError" class="gl-mt-4">
+ <div class="file-editor gl-mb-3">
+ <div class="info-well gl-display-none gl-display-sm-block">
+ <validation-segment
+ class="well-segment"
+ :loading="isCiConfigDataLoading"
+ :ci-config="ciConfigData"
+ />
+ </div>
+ <gl-tabs>
+ <editor-tab :lazy="true" :title="$options.i18n.tabEdit">
+ <text-editor
+ v-model="contentModel"
+ :ci-config-path="ciConfigPath"
+ :commit-sha="lastCommitSha"
+ />
+ </editor-tab>
<gl-tab
v-if="glFeatures.ciConfigVisualizationTab"
+ :lazy="true"
:title="$options.i18n.tabGraph"
- :lazy="!isVisualizeTabActive"
data-testid="visualization-tab"
>
- <gl-loading-icon v-if="isVisualizationTabLoading" size="lg" class="gl-m-3" />
+ <gl-loading-icon v-if="isCiConfigDataLoading" size="lg" class="gl-m-3" />
<pipeline-graph v-else :pipeline-data="ciConfigData" />
</gl-tab>
+
+ <editor-tab :title="$options.i18n.tabLint">
+ <gl-loading-icon v-if="isCiConfigDataLoading" size="lg" class="gl-m-3" />
+ <ci-lint v-else :ci-config="ciConfigData" />
+ </editor-tab>
</gl-tabs>
</div>
<commit-form