diff options
Diffstat (limited to 'app/assets/javascripts/jobs/components/manual_variables_form.vue')
-rw-r--r-- | app/assets/javascripts/jobs/components/manual_variables_form.vue | 229 |
1 files changed, 109 insertions, 120 deletions
diff --git a/app/assets/javascripts/jobs/components/manual_variables_form.vue b/app/assets/javascripts/jobs/components/manual_variables_form.vue index 269551ff9aa..7a52a1b0d6b 100644 --- a/app/assets/javascripts/jobs/components/manual_variables_form.vue +++ b/app/assets/javascripts/jobs/components/manual_variables_form.vue @@ -1,5 +1,12 @@ <script> -import { GlButton, GlLink, GlSprintf } from '@gitlab/ui'; +import { + GlFormInputGroup, + GlInputGroupText, + GlFormInput, + GlButton, + GlLink, + GlSprintf, +} from '@gitlab/ui'; import { uniqueId } from 'lodash'; import { mapActions } from 'vuex'; import { helpPagePath } from '~/helpers/help_page_helper'; @@ -8,6 +15,9 @@ import { s__ } from '~/locale'; export default { name: 'ManualVariablesForm', components: { + GlFormInputGroup, + GlInputGroupText, + GlFormInput, GlButton, GlLink, GlSprintf, @@ -32,6 +42,9 @@ export default { value: 'value', }, i18n: { + header: s__('CiVariables|Variables'), + keyLabel: s__('CiVariables|Key'), + valueLabel: s__('CiVariables|Value'), keyPlaceholder: s__('CiVariables|Input variable key'), valuePlaceholder: s__('CiVariables|Input variable value'), formHelpText: s__( @@ -40,9 +53,13 @@ export default { }, data() { return { - variables: [], - key: '', - secretValue: '', + variables: [ + { + key: '', + secretValue: '', + id: uniqueId(), + }, + ], triggerBtnDisabled: false, }; }, @@ -50,40 +67,32 @@ export default { variableSettings() { return helpPagePath('ci/variables/index', { anchor: 'add-a-cicd-variable-to-a-project' }); }, - }, - watch: { - key(newVal) { - this.handleValueChange(newVal, this.$options.inputTypes.key); - }, - secretValue(newVal) { - this.handleValueChange(newVal, this.$options.inputTypes.value); + preparedVariables() { + // we need to ensure no empty variables are passed to the API + // and secretValue should be snake_case when passed to the API + return this.variables + .filter((variable) => variable.key !== '') + .map(({ key, secretValue }) => ({ key, secret_value: secretValue })); }, }, methods: { ...mapActions(['triggerManualJob']), - handleValueChange(newValue, type) { - if (newValue !== '') { - this.createNewVariable(type); - this.resetForm(); - } + canRemove(index) { + return index < this.variables.length - 1; }, - createNewVariable(type) { - const newVariable = { - key: this.key, - secret_value: this.secretValue, - id: uniqueId(), - }; + addEmptyVariable() { + const lastVar = this.variables[this.variables.length - 1]; - this.variables.push(newVariable); + if (lastVar.key === '') { + return; + } - return this.$nextTick().then(() => { - this.$refs[`${this.$options.inputTypes[type]}-${newVariable.id}`][0].focus(); + this.variables.push({ + key: '', + secret_value: '', + id: uniqueId(), }); }, - resetForm() { - this.key = ''; - this.secretValue = ''; - }, deleteVariable(id) { this.variables.splice( this.variables.findIndex((el) => el.id === id), @@ -93,112 +102,92 @@ export default { trigger() { this.triggerBtnDisabled = true; - this.triggerManualJob(this.variables); + this.triggerManualJob(this.preparedVariables); }, }, }; </script> <template> - <div class="col-12" data-testid="manual-vars-form"> - <label>{{ s__('CiVariables|Variables') }}</label> - - <div class="ci-table"> - <div class="gl-responsive-table-row table-row-header pb-0 pt-0 border-0" role="row"> - <div class="table-section section-50" role="rowheader">{{ s__('CiVariables|Key') }}</div> - <div class="table-section section-50" role="rowheader">{{ s__('CiVariables|Value') }}</div> - </div> + <div class="row gl-justify-content-center"> + <div class="col-10" data-testid="manual-vars-form"> + <label>{{ $options.i18n.header }}</label> <div - v-for="variable in variables" + v-for="(variable, index) in variables" :key="variable.id" - class="gl-responsive-table-row" + class="gl-display-flex gl-align-items-center gl-mb-4" data-testid="ci-variable-row" > - <div class="table-section section-50"> - <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div> - <div class="table-mobile-content gl-mr-3"> - <input - :ref="`${$options.inputTypes.key}-${variable.id}`" - v-model="variable.key" - :placeholder="$options.i18n.keyPlaceholder" - class="ci-variable-body-item form-control" - data-testid="ci-variable-key" - /> - </div> - </div> + <gl-form-input-group class="gl-mr-4 gl-flex-grow-1"> + <template #prepend> + <gl-input-group-text> + {{ $options.i18n.keyLabel }} + </gl-input-group-text> + </template> + <gl-form-input + :ref="`${$options.inputTypes.key}-${variable.id}`" + v-model="variable.key" + :placeholder="$options.i18n.keyPlaceholder" + data-testid="ci-variable-key" + @change="addEmptyVariable" + /> + </gl-form-input-group> - <div class="table-section section-50"> - <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div> - <div class="table-mobile-content gl-mr-3"> - <input - :ref="`${$options.inputTypes.value}-${variable.id}`" - v-model="variable.secret_value" - :placeholder="$options.i18n.valuePlaceholder" - class="ci-variable-body-item form-control" - data-testid="ci-variable-value" - /> - </div> - </div> + <gl-form-input-group class="gl-flex-grow-2"> + <template #prepend> + <gl-input-group-text> + {{ $options.i18n.valueLabel }} + </gl-input-group-text> + </template> + <gl-form-input + :ref="`${$options.inputTypes.value}-${variable.id}`" + v-model="variable.secretValue" + :placeholder="$options.i18n.valuePlaceholder" + data-testid="ci-variable-value" + /> + </gl-form-input-group> - <div class="table-section section-10"> - <div class="table-mobile-header" role="rowheader"></div> - <div class="table-mobile-content justify-content-end"> - <gl-button - category="tertiary" - icon="clear" - :aria-label="__('Delete variable')" - data-testid="delete-variable-btn" - @click="deleteVariable(variable.id)" - /> - </div> - </div> + <!-- delete variable button placeholder to not break flex layout --> + <div + v-if="!canRemove(index)" + class="gl-w-7 gl-mr-3" + data-testid="delete-variable-btn-placeholder" + ></div> + + <gl-button + v-if="canRemove(index)" + class="gl-flex-grow-0 gl-flex-basis-0" + category="tertiary" + variant="danger" + icon="clear" + :aria-label="__('Delete variable')" + data-testid="delete-variable-btn" + @click="deleteVariable(variable.id)" + /> </div> - <div class="gl-responsive-table-row"> - <div class="table-section section-50"> - <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div> - <div class="table-mobile-content gl-mr-3"> - <input - ref="inputKey" - v-model="key" - class="js-input-key form-control" - :placeholder="$options.i18n.keyPlaceholder" - /> - </div> - </div> - <div class="table-section section-50"> - <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div> - <div class="table-mobile-content gl-mr-3"> - <input - ref="inputSecretValue" - v-model="secretValue" - class="ci-variable-body-item form-control" - :placeholder="$options.i18n.valuePlaceholder" - /> - </div> - </div> + <div class="gl-text-center gl-mt-5"> + <gl-sprintf :message="$options.i18n.formHelpText"> + <template #link="{ content }"> + <gl-link :href="variableSettings" target="_blank"> + {{ content }} + </gl-link> + </template> + </gl-sprintf> + </div> + <div class="gl-display-flex gl-justify-content-center gl-mt-5"> + <gl-button + class="gl-mt-5" + variant="info" + category="primary" + :aria-label="__('Trigger manual job')" + :disabled="triggerBtnDisabled" + data-testid="trigger-manual-job-btn" + @click="trigger" + > + {{ action.button_title }} + </gl-button> </div> - </div> - <div class="gl-text-center gl-mt-3"> - <gl-sprintf :message="$options.i18n.formHelpText"> - <template #link="{ content }"> - <gl-link :href="variableSettings" target="_blank"> - {{ content }} - </gl-link> - </template> - </gl-sprintf> - </div> - <div class="d-flex justify-content-center"> - <gl-button - variant="info" - category="primary" - :aria-label="__('Trigger manual job')" - :disabled="triggerBtnDisabled" - data-testid="trigger-manual-job-btn" - @click="trigger" - > - {{ action.button_title }} - </gl-button> </div> </div> </template> |