Commit e31d5711 authored by Miguel Rincon's avatar Miguel Rincon

Have variables form support mobile

In preparation for improvements of the pipeline variables form, this MR
adds support for smallers screens and improves the component so new
variables can be added programatically.
parent 7e6fd918
<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;
}
}
...@@ -5097,6 +5097,9 @@ msgstr "" ...@@ -5097,6 +5097,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