debian-mirror-gitlab/app/assets/javascripts/pipeline_wizard/components/wrapper.vue

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

239 lines
6.5 KiB
Vue
Raw Normal View History

2022-05-07 20:08:51 +05:30
<script>
import { GlProgressBar } from '@gitlab/ui';
import { Document } from 'yaml';
2022-06-21 17:19:12 +05:30
import { uniqueId } from 'lodash';
2022-05-07 20:08:51 +05:30
import { merge } from '~/lib/utils/yaml';
import { __ } from '~/locale';
import { isValidStepSeq } from '~/pipeline_wizard/validators';
2022-10-11 01:57:18 +05:30
import Tracking from '~/tracking';
2022-05-07 20:08:51 +05:30
import YamlEditor from './editor.vue';
import WizardStep from './step.vue';
import CommitStep from './commit.vue';
export const i18n = {
stepNofN: __('Step %{currentStep} of %{stepCount}'),
draft: __('Draft: %{filename}'),
overlayMessage: __(`Start inputting changes and we will generate a
YAML-file for you to add to your repository`),
};
2022-10-11 01:57:18 +05:30
const trackingMixin = Tracking.mixin();
2022-05-07 20:08:51 +05:30
export default {
name: 'PipelineWizardWrapper',
i18n,
components: {
GlProgressBar,
YamlEditor,
WizardStep,
CommitStep,
},
2022-10-11 01:57:18 +05:30
mixins: [trackingMixin],
2022-05-07 20:08:51 +05:30
props: {
steps: {
type: Object,
required: true,
validator: isValidStepSeq,
},
projectPath: {
type: String,
required: true,
},
defaultBranch: {
type: String,
required: true,
},
filename: {
type: String,
required: true,
},
2022-10-11 01:57:18 +05:30
templateId: {
type: String,
required: false,
default: null,
},
2022-05-07 20:08:51 +05:30
},
data() {
return {
highlightPath: null,
currentStepIndex: 0,
// TODO: In order to support updating existing pipelines, the below
// should contain a parsed version of an existing .gitlab-ci.yml.
// See https://gitlab.com/gitlab-org/gitlab/-/issues/355306
compiled: new Document({}),
showPlaceholder: true,
pipelineBlob: null,
placeholder: this.getPlaceholder(),
};
},
computed: {
currentStep() {
return this.currentStepIndex + 1;
},
stepCount() {
return this.steps.items.length + 1;
},
progress() {
return Math.ceil((this.currentStep / (this.stepCount + 1)) * 100);
},
isLastStep() {
return this.currentStep === this.stepCount;
},
2022-06-21 17:19:12 +05:30
stepList() {
return this.steps.items.map((_, i) => ({
id: uniqueId(),
inputs: this.steps.get(i).get('inputs').toJSON(),
template: this.steps.get(i).get('template', true),
}));
},
2022-10-11 01:57:18 +05:30
tracking() {
return {
category: `pipeline_wizard:${this.templateId}`,
};
},
2022-05-07 20:08:51 +05:30
},
watch: {
isLastStep(value) {
if (value) this.resetHighlight();
},
},
methods: {
resetHighlight() {
this.highlightPath = null;
},
onUpdate() {
this.showPlaceholder = false;
},
onEditorUpdate(blob) {
// TODO: In a later iteration, we could add a loopback allowing for
// changes from the editor to flow back into the model
// see https://gitlab.com/gitlab-org/gitlab/-/issues/355312
this.pipelineBlob = blob;
},
getPlaceholder() {
const doc = new Document({});
this.steps.items.forEach((tpl) => {
merge(doc, tpl.get('template').clone());
});
return doc;
},
2022-10-11 01:57:18 +05:30
onBack() {
this.currentStepIndex -= 1;
this.track('click_button', {
property: 'back',
label: 'pipeline_wizard_navigation',
extra: {
fromStep: this.currentStepIndex + 1,
toStep: this.currentStepIndex,
},
});
},
onNext() {
this.currentStepIndex += 1;
this.track('click_button', {
property: 'next',
label: 'pipeline_wizard_navigation',
extra: {
fromStep: this.currentStepIndex - 1,
toStep: this.currentStepIndex,
},
});
},
onDone() {
this.$emit('done');
this.track('click_button', {
label: 'pipeline_wizard_commit',
property: 'commit',
});
},
onEditorTouched() {
this.track('edit', {
label: 'pipeline_wizard_editor_interaction',
extra: {
currentStep: this.currentStepIndex,
},
});
},
2022-05-07 20:08:51 +05:30
},
};
</script>
<template>
<div class="row gl-mt-8">
<main class="col-md-6 gl-pr-8">
<header class="gl-mb-5">
<h3 class="text-secondary gl-mt-0" data-testid="step-count">
{{ sprintf($options.i18n.stepNofN, { currentStep, stepCount }) }}
</h3>
<gl-progress-bar :value="progress" variant="success" />
</header>
<section class="gl-mb-4">
<commit-step
2022-06-21 17:19:12 +05:30
v-show="isLastStep"
data-testid="step"
2022-05-07 20:08:51 +05:30
:default-branch="defaultBranch"
:file-content="pipelineBlob"
:filename="filename"
:project-path="projectPath"
2022-10-11 01:57:18 +05:30
@back="onBack"
@done="onDone"
2022-05-07 20:08:51 +05:30
/>
<wizard-step
2022-06-21 17:19:12 +05:30
v-for="(step, i) in stepList"
v-show="i === currentStepIndex"
:key="step.id"
data-testid="step"
2022-05-07 20:08:51 +05:30
:compiled.sync="compiled"
2022-06-21 17:19:12 +05:30
:has-next-step="i < steps.items.length"
:has-previous-step="i > 0"
2022-05-07 20:08:51 +05:30
:highlight.sync="highlightPath"
2022-06-21 17:19:12 +05:30
:inputs="step.inputs"
:template="step.template"
2022-10-11 01:57:18 +05:30
@back="onBack"
@next="onNext"
2022-05-07 20:08:51 +05:30
@update:compiled="onUpdate"
/>
</section>
</main>
<aside class="col-md-6 gl-pt-3">
<div
class="gl-border-1 gl-border-gray-100 gl-border-solid border-radius-default gl-bg-gray-10"
>
<h6 class="gl-p-2 gl-px-4 text-secondary" data-testid="editor-header">
{{ sprintf($options.i18n.draft, { filename }) }}
</h6>
<div class="gl-relative gl-overflow-hidden">
<yaml-editor
:aria-hidden="showPlaceholder"
:doc="showPlaceholder ? placeholder : compiled"
:filename="filename"
:highlight="highlightPath"
class="gl-w-full"
@update:yaml="onEditorUpdate"
2022-10-11 01:57:18 +05:30
@touch.once="onEditorTouched"
2022-05-07 20:08:51 +05:30
/>
<div
v-if="showPlaceholder"
class="gl-absolute gl-top-0 gl-right-0 gl-bottom-0 gl-left-0 gl-filter-blur-1"
data-testid="placeholder-overlay"
>
<div
class="gl-absolute gl-top-0 gl-right-0 gl-bottom-0 gl-left-0 bg-white gl-opacity-5 gl-z-index-2"
></div>
<div
class="gl-relative gl-h-full gl-display-flex gl-align-items-center gl-justify-content-center gl-z-index-3"
>
<div class="gl-max-w-34">
<h4 data-testid="filename">{{ filename }}</h4>
<p data-testid="description">
{{ $options.i18n.overlayMessage }}
</p>
</div>
</div>
</div>
</div>
</div>
</aside>
</div>
</template>