Commit 52dd6d61 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch '30101-run-pipeline-form-mobile' into 'master'

Add mobile support for "Run pipeline" variables form

See merge request gitlab-org/gitlab!43388
parents 92a40178 e31d5711
<script> <script>
import Vue from 'vue';
import { uniqueId } from 'lodash'; import { uniqueId } from 'lodash';
import { import {
GlAlert, GlAlert,
GlIcon,
GlButton, GlButton,
GlForm, GlForm,
GlFormGroup, GlFormGroup,
...@@ -27,12 +27,13 @@ export default { ...@@ -27,12 +27,13 @@ export default {
variablesDescription: s__( variablesDescription: s__(
'Pipeline|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used by default.', 'Pipeline|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used by default.',
), ),
formElementClasses: 'gl-mr-3 gl-mb-3 table-section section-15', formElementClasses: 'gl-mr-3 gl-mb-3 gl-flex-basis-quarter gl-flex-shrink-0 gl-flex-grow-0',
errorTitle: __('The form contains the following error:'), errorTitle: __('The form contains the following error:'),
warningTitle: __('The form contains the following warning:'), warningTitle: __('The form contains the following warning:'),
maxWarningsSummary: __('%{total} warnings found: showing first %{warningsDisplayed}'), maxWarningsSummary: __('%{total} warnings found: showing first %{warningsDisplayed}'),
components: { components: {
GlAlert, GlAlert,
GlIcon,
GlButton, GlButton,
GlForm, GlForm,
GlFormGroup, GlFormGroup,
...@@ -85,7 +86,7 @@ export default { ...@@ -85,7 +86,7 @@ export default {
return { return {
searchTerm: '', searchTerm: '',
refValue: this.refParam, refValue: this.refParam,
variables: {}, variables: [],
error: null, error: null,
warnings: [], warnings: [],
totalWarnings: 0, totalWarnings: 0,
...@@ -97,9 +98,6 @@ export default { ...@@ -97,9 +98,6 @@ export default {
const lowerCasedSearchTerm = this.searchTerm.toLowerCase(); const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
return this.refs.filter(ref => ref.toLowerCase().includes(lowerCasedSearchTerm)); return this.refs.filter(ref => ref.toLowerCase().includes(lowerCasedSearchTerm));
}, },
variablesLength() {
return Object.keys(this.variables).length;
},
overMaxWarningsLimit() { overMaxWarningsLimit() {
return this.totalWarnings > this.maxWarnings; return this.totalWarnings > this.maxWarnings;
}, },
...@@ -114,6 +112,8 @@ export default { ...@@ -114,6 +112,8 @@ export default {
}, },
}, },
created() { created() {
this.addEmptyVariable();
if (this.variableParams) { if (this.variableParams) {
this.setVariableParams(VARIABLE_TYPE, this.variableParams); this.setVariableParams(VARIABLE_TYPE, this.variableParams);
} }
...@@ -121,24 +121,26 @@ export default { ...@@ -121,24 +121,26 @@ export default {
if (this.fileParams) { if (this.fileParams) {
this.setVariableParams(FILE_TYPE, this.fileParams); this.setVariableParams(FILE_TYPE, this.fileParams);
} }
this.addEmptyVariable();
}, },
methods: { methods: {
addEmptyVariable() { setVariable(type, key, value) {
this.variables[uniqueId('var')] = { const variable = this.variables.find(v => v.key === key);
variable_type: VARIABLE_TYPE, if (variable) {
key: '', variable.type = type;
value: '', variable.value = value;
}; } else {
}, // insert before the empty variable
setVariableParams(type, paramsObj) { this.variables.splice(this.variables.length - 1, 0, {
Object.entries(paramsObj).forEach(([key, value]) => { uniqueId: uniqueId('var'),
this.variables[uniqueId('var')] = {
key, key,
value, value,
variable_type: type, variable_type: type,
}; });
}
},
setVariableParams(type, paramsObj) {
Object.entries(paramsObj).forEach(([key, value]) => {
this.setVariable(type, key, value);
}); });
}, },
setRefSelected(ref) { setRefSelected(ref) {
...@@ -147,24 +149,29 @@ export default { ...@@ -147,24 +149,29 @@ export default {
isSelected(ref) { isSelected(ref) {
return ref === this.refValue; return ref === this.refValue;
}, },
insertNewVariable() { addEmptyVariable() {
Vue.set(this.variables, uniqueId('var'), { this.variables.push({
uniqueId: uniqueId('var'),
variable_type: VARIABLE_TYPE, variable_type: VARIABLE_TYPE,
key: '', key: '',
value: '', value: '',
}); });
}, },
removeVariable(key) { removeVariable(index) {
Vue.delete(this.variables, key); this.variables.splice(index, 1);
}, },
canRemove(index) { canRemove(index) {
return index < this.variablesLength - 1; return index < this.variables.length - 1;
}, },
createPipeline() { createPipeline() {
const filteredVariables = Object.values(this.variables).filter( const filteredVariables = this.variables
({ key, value }) => key !== '' && value !== '', .filter(({ key, value }) => key !== '' && value !== '')
); .map(({ variable_type, key, value }) => ({
variable_type,
key,
value,
}));
return axios return axios
.post(this.pipelinesPath, { .post(this.pipelinesPath, {
...@@ -253,35 +260,47 @@ export default { ...@@ -253,35 +260,47 @@ export default {
<gl-form-group :label="s__('Pipeline|Variables')"> <gl-form-group :label="s__('Pipeline|Variables')">
<div <div
v-for="(value, key, index) in variables" v-for="(variable, index) in variables"
:key="key" :key="variable.uniqueId"
class="gl-display-flex gl-align-items-center gl-mb-4 gl-pb-2 gl-border-b-solid gl-border-gray-200 gl-border-b-1 gl-flex-direction-column gl-md-flex-direction-row" class="gl-display-flex gl-align-items-stretch gl-align-items-center gl-mb-4 gl-ml-n3 gl-pb-2 gl-border-b-solid gl-border-gray-200 gl-border-b-1 gl-flex-direction-column gl-md-flex-direction-row"
data-testid="ci-variable-row" data-testid="ci-variable-row"
> >
<gl-form-select <gl-form-select
v-model="variables[key].variable_type" v-model="variable.variable_type"
:class="$options.formElementClasses" :class="$options.formElementClasses"
:options="$options.typeOptions" :options="$options.typeOptions"
/> />
<gl-form-input <gl-form-input
v-model="variables[key].key" v-model="variable.key"
:placeholder="s__('CiVariables|Input variable key')" :placeholder="s__('CiVariables|Input variable key')"
:class="$options.formElementClasses" :class="$options.formElementClasses"
data-testid="pipeline-form-ci-variable-key" data-testid="pipeline-form-ci-variable-key"
@change.once="insertNewVariable()" @change.once="addEmptyVariable()"
/> />
<gl-form-input <gl-form-input
v-model="variables[key].value" v-model="variable.value"
:placeholder="s__('CiVariables|Input variable value')" :placeholder="s__('CiVariables|Input variable value')"
class="gl-mr-5 gl-mb-3 table-section section-15"
/>
<gl-button
v-if="canRemove(index)"
icon="issue-close"
class="gl-mb-3" class="gl-mb-3"
data-testid="remove-ci-variable-row"
@click="removeVariable(key)"
/> />
<template v-if="variables.length > 1">
<gl-button
v-if="canRemove(index)"
class="gl-md-ml-3 gl-mb-3"
data-testid="remove-ci-variable-row"
variant="danger"
category="secondary"
@click="removeVariable(index)"
>
<gl-icon class="gl-mr-0! gl-display-none gl-display-md-block" name="clear" />
<span class="gl-display-md-none">{{ s__('CiVariables|Remove variable') }}</span>
</gl-button>
<gl-button
v-else
class="gl-md-ml-3 gl-mb-3 gl-display-none gl-display-md-block gl-visibility-hidden"
icon="clear"
/>
</template>
</div> </div>
<template #description <template #description
......
...@@ -161,3 +161,13 @@ ...@@ -161,3 +161,13 @@
.gl-z-dropdown-menu\! { .gl-z-dropdown-menu\! {
z-index: 300 !important; z-index: 300 !important;
} }
.gl-flex-basis-quarter {
flex-basis: 25%;
}
.gl-md-ml-3 {
@media (min-width: $breakpoint-md) {
margin-left: $gl-spacing-scale-3;
}
}
...@@ -5099,6 +5099,9 @@ msgstr "" ...@@ -5099,6 +5099,9 @@ msgstr ""
msgid "CiVariables|Protected" msgid "CiVariables|Protected"
msgstr "" msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
msgid "CiVariables|Remove variable row" msgid "CiVariables|Remove variable row"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment