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:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 15:26:25 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 15:26:25 +0300
commita09983ae35713f5a2bbb100981116d31ce99826e (patch)
tree2ee2af7bd104d57086db360a7e6d8c9d5d43667a /app/assets/javascripts/ci_variable_list
parent18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff)
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'app/assets/javascripts/ci_variable_list')
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_key_field.vue169
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_autocomplete_tokens.js14
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue81
-rw-r--r--app/assets/javascripts/ci_variable_list/store/actions.js28
-rw-r--r--app/assets/javascripts/ci_variable_list/store/mutation_types.js6
-rw-r--r--app/assets/javascripts/ci_variable_list/store/mutations.js35
-rw-r--r--app/assets/javascripts/ci_variable_list/store/state.js4
-rw-r--r--app/assets/javascripts/ci_variable_list/store/utils.js4
8 files changed, 102 insertions, 239 deletions
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_key_field.vue b/app/assets/javascripts/ci_variable_list/components/ci_key_field.vue
deleted file mode 100644
index c15d638d92b..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_key_field.vue
+++ /dev/null
@@ -1,169 +0,0 @@
-<script>
-import { uniqueId } from 'lodash';
-import { GlButton, GlFormGroup, GlFormInput } from '@gitlab/ui';
-
-export default {
- name: 'CiKeyField',
- components: {
- GlButton,
- GlFormGroup,
- GlFormInput,
- },
- model: {
- prop: 'value',
- event: 'input',
- },
- props: {
- tokenList: {
- type: Array,
- required: true,
- },
- value: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- results: [],
- arrowCounter: -1,
- userDismissedResults: false,
- suggestionsId: uniqueId('token-suggestions-'),
- };
- },
- computed: {
- showAutocomplete() {
- return this.showSuggestions ? 'off' : 'on';
- },
- showSuggestions() {
- return this.results.length > 0;
- },
- },
- mounted() {
- document.addEventListener('click', this.handleClickOutside);
- },
- destroyed() {
- document.removeEventListener('click', this.handleClickOutside);
- },
- methods: {
- closeSuggestions() {
- this.results = [];
- this.arrowCounter = -1;
- },
- handleClickOutside(event) {
- if (!this.$el.contains(event.target)) {
- this.closeSuggestions();
- }
- },
- onArrowDown() {
- const newCount = this.arrowCounter + 1;
-
- if (newCount >= this.results.length) {
- this.arrowCounter = 0;
- return;
- }
-
- this.arrowCounter = newCount;
- },
- onArrowUp() {
- const newCount = this.arrowCounter - 1;
-
- if (newCount < 0) {
- this.arrowCounter = this.results.length - 1;
- return;
- }
-
- this.arrowCounter = newCount;
- },
- onEnter() {
- const currentToken = this.results[this.arrowCounter] || this.value;
- this.selectToken(currentToken);
- },
- onEsc() {
- if (!this.showSuggestions) {
- this.$emit('input', '');
- }
- this.closeSuggestions();
- this.userDismissedResults = true;
- },
- onEntry(value) {
- this.$emit('input', value);
- this.userDismissedResults = false;
-
- // short circuit so that we don't false match on empty string
- if (value.length < 1) {
- this.closeSuggestions();
- return;
- }
-
- const filteredTokens = this.tokenList.filter(token =>
- token.toLowerCase().includes(value.toLowerCase()),
- );
-
- if (filteredTokens.length) {
- this.openSuggestions(filteredTokens);
- } else {
- this.closeSuggestions();
- }
- },
- openSuggestions(filteredResults) {
- this.results = filteredResults;
- },
- selectToken(value) {
- this.$emit('input', value);
- this.closeSuggestions();
- this.$emit('key-selected');
- },
- },
-};
-</script>
-<template>
- <div>
- <div class="dropdown position-relative" role="combobox" aria-owns="token-suggestions">
- <gl-form-group :label="__('Key')" label-for="ci-variable-key">
- <gl-form-input
- id="ci-variable-key"
- :value="value"
- type="text"
- role="searchbox"
- class="form-control pl-2 js-env-input"
- :autocomplete="showAutocomplete"
- aria-autocomplete="list"
- aria-controls="token-suggestions"
- aria-haspopup="listbox"
- :aria-expanded="showSuggestions"
- data-qa-selector="ci_variable_key_field"
- @input="onEntry"
- @keydown.down="onArrowDown"
- @keydown.up="onArrowUp"
- @keydown.enter.prevent="onEnter"
- @keydown.esc.stop="onEsc"
- @keydown.tab="closeSuggestions"
- />
- </gl-form-group>
-
- <div
- v-show="showSuggestions && !userDismissedResults"
- id="ci-variable-dropdown"
- class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width"
- :class="{ 'd-block': showSuggestions }"
- >
- <div class="dropdown-content">
- <ul :id="suggestionsId">
- <li
- v-for="(result, i) in results"
- :key="i"
- role="option"
- :class="{ 'gl-bg-gray-50': i === arrowCounter }"
- :aria-selected="i === arrowCounter"
- >
- <gl-button tabindex="-1" class="btn-transparent pl-2" @click="selectToken(result)">{{
- result
- }}</gl-button>
- </li>
- </ul>
- </div>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_autocomplete_tokens.js b/app/assets/javascripts/ci_variable_list/components/ci_variable_autocomplete_tokens.js
index 9022bf51514..3f25e3df305 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_autocomplete_tokens.js
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_autocomplete_tokens.js
@@ -1,28 +1,14 @@
-import { __ } from '~/locale';
-
import { AWS_ACCESS_KEY_ID, AWS_DEFAULT_REGION, AWS_SECRET_ACCESS_KEY } from '../constants';
export const awsTokens = {
[AWS_ACCESS_KEY_ID]: {
name: AWS_ACCESS_KEY_ID,
- /* Checks for exactly twenty characters that match key.
- Based on greps suggested by Amazon at:
- https://aws.amazon.com/blogs/security/a-safer-way-to-distribute-aws-credentials-to-ec2/
- */
- validation: val => /^[A-Za-z0-9]{20}$/.test(val),
- invalidMessage: __('This variable does not match the expected pattern.'),
},
[AWS_DEFAULT_REGION]: {
name: AWS_DEFAULT_REGION,
},
[AWS_SECRET_ACCESS_KEY]: {
name: AWS_SECRET_ACCESS_KEY,
- /* Checks for exactly forty characters that match secret.
- Based on greps suggested by Amazon at:
- https://aws.amazon.com/blogs/security/a-safer-way-to-distribute-aws-credentials-to-ec2/
- */
- validation: val => /^[A-Za-z0-9/+=]{40}$/.test(val),
- invalidMessage: __('This variable does not match the expected pattern.'),
},
};
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
index 6531b945212..0ba58430de1 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
@@ -5,6 +5,7 @@ import {
GlCollapse,
GlDeprecatedButton,
GlFormCheckbox,
+ GlFormCombobox,
GlFormGroup,
GlFormInput,
GlFormSelect,
@@ -16,6 +17,7 @@ import {
} from '@gitlab/ui';
import Cookies from 'js-cookie';
import { mapActions, mapState } from 'vuex';
+import { mapComputed } from '~/vuex_shared/bindings';
import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import {
@@ -25,19 +27,21 @@ import {
AWS_TIP_MESSAGE,
} from '../constants';
import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
-import CiKeyField from './ci_key_field.vue';
import CiEnvironmentsDropdown from './ci_environments_dropdown.vue';
export default {
modalId: ADD_CI_VARIABLE_MODAL_ID,
+ tokens: awsTokens,
+ tokenList: awsTokenList,
+ awsTipMessage: AWS_TIP_MESSAGE,
components: {
CiEnvironmentsDropdown,
- CiKeyField,
GlAlert,
GlButton,
GlCollapse,
GlDeprecatedButton,
GlFormCheckbox,
+ GlFormCombobox,
GlFormGroup,
GlFormInput,
GlFormSelect,
@@ -48,9 +52,6 @@ export default {
GlSprintf,
},
mixins: [glFeatureFlagsMixin()],
- tokens: awsTokens,
- tokenList: awsTokenList,
- awsTipMessage: AWS_TIP_MESSAGE,
data() {
return {
isTipDismissed: Cookies.get(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
@@ -74,22 +75,34 @@ export default {
'protectedEnvironmentVariablesLink',
'maskedEnvironmentVariablesLink',
]),
+ ...mapComputed(
+ [
+ { key: 'key', updateFn: 'updateVariableKey' },
+ { key: 'secret_value', updateFn: 'updateVariableValue' },
+ { key: 'variable_type', updateFn: 'updateVariableType' },
+ { key: 'environment_scope', updateFn: 'setEnvironmentScope' },
+ { key: 'protected_variable', updateFn: 'updateVariableProtected' },
+ { key: 'masked', updateFn: 'updateVariableMasked' },
+ ],
+ false,
+ 'variable',
+ ),
isTipVisible() {
- return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variableData.key);
+ return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variable.key);
},
canSubmit() {
return (
this.variableValidationState &&
- this.variableData.key !== '' &&
- this.variableData.secret_value !== ''
+ this.variable.key !== '' &&
+ this.variable.secret_value !== ''
);
},
canMask() {
const regex = RegExp(this.maskableRegex);
- return regex.test(this.variableData.secret_value);
+ return regex.test(this.variable.secret_value);
},
displayMaskedError() {
- return !this.canMask && this.variableData.masked;
+ return !this.canMask && this.variable.masked;
},
maskedState() {
if (this.displayMaskedError) {
@@ -97,9 +110,6 @@ export default {
}
return true;
},
- variableData() {
- return this.variableBeingEdited || this.variable;
- },
modalActionText() {
return this.variableBeingEdited ? __('Update variable') : __('Add variable');
},
@@ -107,7 +117,7 @@ export default {
return this.displayMaskedError ? __('This variable can not be masked.') : '';
},
tokenValidationFeedback() {
- const tokenSpecificFeedback = this.$options.tokens?.[this.variableData.key]?.invalidMessage;
+ const tokenSpecificFeedback = this.$options.tokens?.[this.variable.key]?.invalidMessage;
if (!this.tokenValidationState && tokenSpecificFeedback) {
return tokenSpecificFeedback;
}
@@ -119,10 +129,10 @@ export default {
return true;
}
- const validator = this.$options.tokens?.[this.variableData.key]?.validation;
+ const validator = this.$options.tokens?.[this.variable.key]?.validation;
if (validator) {
- return validator(this.variableData.secret_value);
+ return validator(this.variable.secret_value);
}
return true;
@@ -131,14 +141,7 @@ export default {
return `${this.tokenValidationFeedback} ${this.maskedFeedback}`;
},
variableValidationState() {
- if (
- this.variableData.secret_value === '' ||
- (this.tokenValidationState && this.maskedState)
- ) {
- return true;
- }
-
- return false;
+ return this.variable.secret_value === '' || (this.tokenValidationState && this.maskedState);
},
},
methods: {
@@ -160,7 +163,7 @@ export default {
this.isTipDismissed = true;
},
deleteVarAndClose() {
- this.deleteVariable(this.variableBeingEdited);
+ this.deleteVariable();
this.hideModal();
},
hideModal() {
@@ -169,14 +172,14 @@ export default {
resetModalHandler() {
if (this.variableBeingEdited) {
this.resetEditing();
- } else {
- this.clearModal();
}
+
+ this.clearModal();
this.resetSelectedEnvironment();
},
updateOrAddVariable() {
if (this.variableBeingEdited) {
- this.updateVariable(this.variableBeingEdited);
+ this.updateVariable();
} else {
this.addVariable();
}
@@ -202,16 +205,17 @@ export default {
@shown="setVariableProtectedByDefault"
>
<form>
- <ci-key-field
+ <gl-form-combobox
v-if="glFeatures.ciKeyAutocomplete"
- v-model="variableData.key"
+ v-model="key"
:token-list="$options.tokenList"
+ :label-text="__('Key')"
/>
<gl-form-group v-else :label="__('Key')" label-for="ci-variable-key">
<gl-form-input
id="ci-variable-key"
- v-model="variableData.key"
+ v-model="key"
data-qa-selector="ci_variable_key_field"
/>
</gl-form-group>
@@ -225,11 +229,12 @@ export default {
<gl-form-textarea
id="ci-variable-value"
ref="valueField"
- v-model="variableData.secret_value"
+ v-model="secret_value"
:state="variableValidationState"
rows="3"
max-rows="6"
data-qa-selector="ci_variable_value_field"
+ class="gl-font-monospace!"
/>
</gl-form-group>
@@ -240,11 +245,7 @@ export default {
class="w-50 append-right-15"
:class="{ 'w-100': isGroup }"
>
- <gl-form-select
- id="ci-variable-type"
- v-model="variableData.variable_type"
- :options="typeOptions"
- />
+ <gl-form-select id="ci-variable-type" v-model="variable_type" :options="typeOptions" />
</gl-form-group>
<gl-form-group
@@ -255,7 +256,7 @@ export default {
>
<ci-environments-dropdown
class="w-100"
- :value="variableData.environment_scope"
+ :value="environment_scope"
@selectEnvironment="setEnvironmentScope"
@createClicked="addWildCardScope"
/>
@@ -263,7 +264,7 @@ export default {
</div>
<gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
- <gl-form-checkbox v-model="variableData.protected" class="mb-0">
+ <gl-form-checkbox v-model="protected_variable" class="mb-0">
{{ __('Protect variable') }}
<gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
<gl-icon name="question" :size="12" />
@@ -275,7 +276,7 @@ export default {
<gl-form-checkbox
ref="masked-ci-variable"
- v-model="variableData.masked"
+ v-model="masked"
data-qa-selector="ci_variable_masked_checkbox"
>
{{ __('Mask variable') }}
diff --git a/app/assets/javascripts/ci_variable_list/store/actions.js b/app/assets/javascripts/ci_variable_list/store/actions.js
index d9129c919f8..60c7a480769 100644
--- a/app/assets/javascripts/ci_variable_list/store/actions.js
+++ b/app/assets/javascripts/ci_variable_list/store/actions.js
@@ -65,10 +65,10 @@ export const receiveUpdateVariableError = ({ commit }, error) => {
commit(types.RECEIVE_UPDATE_VARIABLE_ERROR, error);
};
-export const updateVariable = ({ state, dispatch }, variable) => {
+export const updateVariable = ({ state, dispatch }) => {
dispatch('requestUpdateVariable');
- const updatedVariable = prepareDataForApi(variable);
+ const updatedVariable = prepareDataForApi(state.variable);
updatedVariable.secrect_value = updateVariable.value;
return axios
@@ -121,13 +121,13 @@ export const receiveDeleteVariableError = ({ commit }, error) => {
commit(types.RECEIVE_DELETE_VARIABLE_ERROR, error);
};
-export const deleteVariable = ({ dispatch, state }, variable) => {
+export const deleteVariable = ({ dispatch, state }) => {
dispatch('requestDeleteVariable');
const destroy = true;
return axios
- .patch(state.endpoint, { variables_attributes: [prepareDataForApi(variable, destroy)] })
+ .patch(state.endpoint, { variables_attributes: [prepareDataForApi(state.variable, destroy)] })
.then(() => {
dispatch('receiveDeleteVariableSuccess');
dispatch('fetchVariables');
@@ -176,3 +176,23 @@ export const resetSelectedEnvironment = ({ commit }) => {
export const setSelectedEnvironment = ({ commit }, environment) => {
commit(types.SET_SELECTED_ENVIRONMENT, environment);
};
+
+export const updateVariableKey = ({ commit }, { key }) => {
+ commit(types.UPDATE_VARIABLE_KEY, key);
+};
+
+export const updateVariableValue = ({ commit }, { secret_value }) => {
+ commit(types.UPDATE_VARIABLE_VALUE, secret_value);
+};
+
+export const updateVariableType = ({ commit }, { variable_type }) => {
+ commit(types.UPDATE_VARIABLE_TYPE, variable_type);
+};
+
+export const updateVariableProtected = ({ commit }, { protected_variable }) => {
+ commit(types.UPDATE_VARIABLE_PROTECTED, protected_variable);
+};
+
+export const updateVariableMasked = ({ commit }, { masked }) => {
+ commit(types.UPDATE_VARIABLE_MASKED, masked);
+};
diff --git a/app/assets/javascripts/ci_variable_list/store/mutation_types.js b/app/assets/javascripts/ci_variable_list/store/mutation_types.js
index ccf8fbd3cb5..5db8f610192 100644
--- a/app/assets/javascripts/ci_variable_list/store/mutation_types.js
+++ b/app/assets/javascripts/ci_variable_list/store/mutation_types.js
@@ -25,3 +25,9 @@ export const SET_ENVIRONMENT_SCOPE = 'SET_ENVIRONMENT_SCOPE';
export const ADD_WILD_CARD_SCOPE = 'ADD_WILD_CARD_SCOPE';
export const RESET_SELECTED_ENVIRONMENT = 'RESET_SELECTED_ENVIRONMENT';
export const SET_SELECTED_ENVIRONMENT = 'SET_SELECTED_ENVIRONMENT';
+
+export const UPDATE_VARIABLE_KEY = 'UPDATE_VARIABLE_KEY';
+export const UPDATE_VARIABLE_VALUE = 'UPDATE_VARIABLE_VALUE';
+export const UPDATE_VARIABLE_TYPE = 'UPDATE_VARIABLE_TYPE';
+export const UPDATE_VARIABLE_PROTECTED = 'UPDATE_VARIABLE_PROTECTED';
+export const UPDATE_VARIABLE_MASKED = 'UPDATE_VARIABLE_MASKED';
diff --git a/app/assets/javascripts/ci_variable_list/store/mutations.js b/app/assets/javascripts/ci_variable_list/store/mutations.js
index 7d9cd0dd727..961cecee298 100644
--- a/app/assets/javascripts/ci_variable_list/store/mutations.js
+++ b/app/assets/javascripts/ci_variable_list/store/mutations.js
@@ -65,7 +65,8 @@ export default {
},
[types.VARIABLE_BEING_EDITED](state, variable) {
- state.variableBeingEdited = variable;
+ state.variableBeingEdited = true;
+ state.variable = variable;
},
[types.CLEAR_MODAL](state) {
@@ -73,23 +74,19 @@ export default {
variable_type: displayText.variableText,
key: '',
secret_value: '',
- protected: false,
+ protected_variable: false,
masked: false,
environment_scope: displayText.allEnvironmentsText,
};
},
[types.RESET_EDITING](state) {
- state.variableBeingEdited = null;
+ state.variableBeingEdited = false;
state.showInputValue = false;
},
[types.SET_ENVIRONMENT_SCOPE](state, environment) {
- if (state.variableBeingEdited) {
- state.variableBeingEdited.environment_scope = environment;
- } else {
- state.variable.environment_scope = environment;
- }
+ state.variable.environment_scope = environment;
},
[types.ADD_WILD_CARD_SCOPE](state, environment) {
@@ -106,6 +103,26 @@ export default {
},
[types.SET_VARIABLE_PROTECTED](state) {
- state.variable.protected = true;
+ state.variable.protected_variable = true;
+ },
+
+ [types.UPDATE_VARIABLE_KEY](state, key) {
+ state.variable.key = key;
+ },
+
+ [types.UPDATE_VARIABLE_VALUE](state, value) {
+ state.variable.secret_value = value;
+ },
+
+ [types.UPDATE_VARIABLE_TYPE](state, type) {
+ state.variable.variable_type = type;
+ },
+
+ [types.UPDATE_VARIABLE_PROTECTED](state, bool) {
+ state.variable.protected_variable = bool;
+ },
+
+ [types.UPDATE_VARIABLE_MASKED](state, bool) {
+ state.variable.masked = bool;
},
};
diff --git a/app/assets/javascripts/ci_variable_list/store/state.js b/app/assets/javascripts/ci_variable_list/store/state.js
index 2fffd115589..96b27792664 100644
--- a/app/assets/javascripts/ci_variable_list/store/state.js
+++ b/app/assets/javascripts/ci_variable_list/store/state.js
@@ -12,7 +12,7 @@ export default () => ({
variable_type: displayText.variableText,
key: '',
secret_value: '',
- protected: false,
+ protected_variable: false,
masked: false,
environment_scope: displayText.allEnvironmentsText,
},
@@ -21,6 +21,6 @@ export default () => ({
error: null,
environments: [],
typeOptions: [displayText.variableText, displayText.fileText],
- variableBeingEdited: null,
+ variableBeingEdited: false,
selectedEnvironment: '',
});
diff --git a/app/assets/javascripts/ci_variable_list/store/utils.js b/app/assets/javascripts/ci_variable_list/store/utils.js
index 3cd8c85024b..f04530359e7 100644
--- a/app/assets/javascripts/ci_variable_list/store/utils.js
+++ b/app/assets/javascripts/ci_variable_list/store/utils.js
@@ -18,6 +18,7 @@ export const prepareDataForDisplay = variables => {
if (variableCopy.environment_scope === types.allEnvironmentsType) {
variableCopy.environment_scope = displayText.allEnvironmentsText;
}
+ variableCopy.protected_variable = variableCopy.protected;
variablesToDisplay.push(variableCopy);
});
return variablesToDisplay;
@@ -25,7 +26,8 @@ export const prepareDataForDisplay = variables => {
export const prepareDataForApi = (variable, destroy = false) => {
const variableCopy = cloneDeep(variable);
- variableCopy.protected = variableCopy.protected.toString();
+ variableCopy.protected = variableCopy.protected_variable.toString();
+ delete variableCopy.protected_variable;
variableCopy.masked = variableCopy.masked.toString();
variableCopy.variable_type = variableTypeHandler(variableCopy.variable_type);
if (variableCopy.environment_scope === displayText.allEnvironmentsText) {