diff options
Diffstat (limited to 'app/assets/javascripts/ci_variable_list')
16 files changed, 156 insertions, 12 deletions
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue b/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue index c8f5ac1736d..4466a6a8081 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue @@ -46,6 +46,7 @@ export default { :id="graphqlId" :are-scoped-variables-available="areScopedVariablesAvailable" component-name="GroupVariables" + entity="group" :full-path="groupPath" :mutation-data="$options.mutationData" :query-data="$options.queryData" diff --git a/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue b/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue index 2c4818e20c1..6326940148a 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue @@ -48,6 +48,7 @@ export default { :id="graphqlId" :are-scoped-variables-available="true" component-name="ProjectVariables" + entity="project" :full-path="projectFullPath" :mutation-data="$options.mutationData" :query-data="$options.queryData" 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 94f8cb9e906..00177539cdc 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 @@ -29,6 +29,7 @@ import { ENVIRONMENT_SCOPE_LINK_TITLE, EVENT_LABEL, EVENT_ACTION, + EXPANDED_VARIABLES_NOTE, EDIT_VARIABLE_ACTION, VARIABLE_ACTIONS, variableOptions, @@ -46,6 +47,7 @@ export default { awsTipMessage: AWS_TIP_MESSAGE, containsVariableReferenceMessage: CONTAINS_VARIABLE_REFERENCE_MESSAGE, environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE, + expandedVariablesNote: EXPANDED_VARIABLES_NOTE, components: { CiEnvironmentsDropdown, GlAlert, @@ -127,7 +129,7 @@ export default { }, containsVariableReference() { const regex = /\$/; - return regex.test(this.variable.value); + return regex.test(this.variable.value) && this.isExpanded; }, displayMaskedError() { return !this.canMask && this.variable.masked; @@ -135,6 +137,9 @@ export default { isEditing() { return this.mode === EDIT_VARIABLE_ACTION; }, + isExpanded() { + return !this.variable.raw; + }, isTipVisible() { return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variable.key); }, @@ -208,6 +213,9 @@ export default { hideModal() { this.$refs.modal.hide(); }, + onShow() { + this.setVariableProtectedByDefault(); + }, resetModalHandler() { this.resetVariableData(); this.resetValidationErrorEvents(); @@ -220,6 +228,9 @@ export default { setEnvironmentScope(scope) { this.variable = { ...this.variable, environmentScope: scope }; }, + setVariableRaw(expanded) { + this.variable = { ...this.variable, raw: !expanded }; + }, setVariableProtected() { this.variable = { ...this.variable, protected: true }; }, @@ -275,7 +286,7 @@ export default { static lazy @hidden="resetModalHandler" - @shown="setVariableProtectedByDefault" + @shown="onShow" > <form> <gl-form-combobox @@ -304,6 +315,13 @@ export default { class="gl-font-monospace!" spellcheck="false" /> + <p + v-if="variable.raw" + class="gl-mt-2 gl-mb-0 text-secondary" + data-testid="raw-variable-tip" + > + {{ __('Variable value will be evaluated as raw string.') }} + </p> </gl-form-group> <div class="gl-display-flex"> @@ -361,7 +379,6 @@ export default { {{ __('Export variable to pipelines running on protected branches and tags only.') }} </p> </gl-form-checkbox> - <gl-form-checkbox ref="masked-ci-variable" v-model="variable.masked" @@ -371,7 +388,7 @@ export default { <gl-link target="_blank" :href="maskedEnvironmentVariablesLink"> <gl-icon name="question" :size="12" /> </gl-link> - <p class="gl-mt-2 gl-mb-0 text-secondary"> + <p class="gl-mt-2 text-secondary"> {{ __('Variable will be masked in job logs.') }} <span :class="{ @@ -385,6 +402,24 @@ export default { }}</gl-link> </p> </gl-form-checkbox> + <gl-form-checkbox + ref="expanded-ci-variable" + :checked="isExpanded" + data-testid="ci-variable-expanded-checkbox" + @change="setVariableRaw" + > + {{ __('Expand variable reference') }} + <gl-link target="_blank" :href="containsVariableReferenceLink"> + <gl-icon name="question" :size="12" /> + </gl-link> + <p class="gl-mt-2 gl-mb-0 gl-text-secondary"> + <gl-sprintf :message="$options.expandedVariablesNote"> + <template #code="{ content }"> + <code>{{ content }}</code> + </template> + </gl-sprintf> + </p> + </gl-form-checkbox> </gl-form-group> </form> <gl-collapse :visible="isTipVisible"> diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue index 94fd6c3892c..3c6114b38ce 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue @@ -14,6 +14,11 @@ export default { required: false, default: false, }, + entity: { + type: String, + required: false, + default: '', + }, environments: { type: Array, required: false, @@ -27,7 +32,11 @@ export default { isLoading: { type: Boolean, required: false, - default: false, + }, + maxVariableLimit: { + type: Number, + required: false, + default: 0, }, variables: { type: Array, @@ -75,7 +84,9 @@ export default { <div class="row"> <div class="col-lg-12"> <ci-variable-table + :entity="entity" :is-loading="isLoading" + :max-variable-limit="maxVariableLimit" :variables="variables" @set-selected-variable="setSelectedVariable" /> diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue index 7ee250cea98..6e39bda0b07 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue @@ -26,6 +26,11 @@ export default { required: true, type: String, }, + entity: { + required: false, + type: String, + default: '', + }, fullPath: { required: false, type: String, @@ -90,6 +95,7 @@ export default { isInitialLoading: true, isLoadingMoreItems: false, loadingCounter: 0, + maxVariableLimit: 0, pageInfo: {}, }; }, @@ -107,6 +113,8 @@ export default { return this.queryData.ciVariables.lookup(data)?.nodes || []; }, result({ data }) { + this.maxVariableLimit = this.queryData.ciVariables.lookup(data)?.limit || 0; + this.pageInfo = this.queryData.ciVariables.lookup(data)?.pageInfo || this.pageInfo; this.hasNextPage = this.pageInfo?.hasNextPage || false; @@ -221,9 +229,11 @@ export default { <template> <ci-variable-settings :are-scoped-variables-available="areScopedVariablesAvailable" + :entity="entity" :hide-environment-scope="hideEnvironmentScope" :is-loading="isLoading" :variables="ciVariables" + :max-variable-limit="maxVariableLimit" :environments="environments" @add-variable="addVariable" @delete-variable="deleteVariable" diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue index 3cdcb68e919..345a8def49d 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue @@ -1,8 +1,21 @@ <script> -import { GlButton, GlLoadingIcon, GlModalDirective, GlTable, GlTooltipDirective } from '@gitlab/ui'; -import { s__, __ } from '~/locale'; +import { + GlAlert, + GlButton, + GlLoadingIcon, + GlModalDirective, + GlTable, + GlTooltipDirective, +} from '@gitlab/ui'; +import { __, s__, sprintf } from '~/locale'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { ADD_CI_VARIABLE_MODAL_ID, variableText } from '../constants'; +import { + ADD_CI_VARIABLE_MODAL_ID, + DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT, + EXCEEDS_VARIABLE_LIMIT_TEXT, + MAXIMUM_VARIABLE_LIMIT_REACHED, + variableText, +} from '../constants'; import { convertEnvironmentScope } from '../utils'; export default { @@ -41,6 +54,7 @@ export default { }, ], components: { + GlAlert, GlButton, GlLoadingIcon, GlTable, @@ -51,10 +65,19 @@ export default { }, mixins: [glFeatureFlagsMixin()], props: { + entity: { + type: String, + required: false, + default: '', + }, isLoading: { type: Boolean, required: true, }, + maxVariableLimit: { + type: Number, + required: true, + }, variables: { type: Array, required: true, @@ -66,6 +89,23 @@ export default { }; }, computed: { + exceedsVariableLimit() { + return this.maxVariableLimit > 0 && this.variables.length >= this.maxVariableLimit; + }, + exceedsVariableLimitText() { + if (this.exceedsVariableLimit && this.entity) { + return sprintf(EXCEEDS_VARIABLE_LIMIT_TEXT, { + entity: this.entity, + currentVariableCount: this.variables.length, + maxVariableLimit: this.maxVariableLimit, + }); + } + + return DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT; + }, + showAlert() { + return !this.isLoading && this.exceedsVariableLimit; + }, valuesButtonText() { return this.areValuesHidden ? __('Reveal values') : __('Hide values'); }, @@ -104,17 +144,29 @@ export default { if (item.masked) { options.push(s__('CiVariables|Masked')); } + if (!item.raw) { + options.push(s__('CiVariables|Expanded')); + } return options.join(', '); }, }, + maximumVariableLimitReached: MAXIMUM_VARIABLE_LIMIT_REACHED, }; </script> <template> <div class="ci-variable-table" data-testid="ci-variable-table"> <gl-loading-icon v-if="isLoading" /> + <gl-alert + v-if="showAlert" + :dismissible="false" + :title="$options.maximumVariableLimitReached" + variant="info" + > + {{ exceedsVariableLimitText }} + </gl-alert> <gl-table - v-else + v-if="!isLoading" :fields="fields" :items="variablesWithOptions" tbody-tr-class="js-ci-variable-row" @@ -178,7 +230,7 @@ export default { </div> </template> <template #cell(options)="{ item }"> - <span>{{ item.options }}</span> + <span data-testid="ci-variable-table-row-options">{{ item.options }}</span> </template> <template #cell(environmentScope)="{ item }"> <div @@ -215,6 +267,14 @@ export default { </p> </template> </gl-table> + <gl-alert + v-if="showAlert" + :dismissible="false" + :title="$options.maximumVariableLimitReached" + variant="info" + > + {{ exceedsVariableLimitText }} + </gl-alert> <div class="ci-variable-actions gl-display-flex gl-mt-5"> <gl-button v-gl-modal-directive="$options.modalId" @@ -223,6 +283,7 @@ export default { variant="confirm" category="primary" :aria-label="__('Add')" + :disabled="exceedsVariableLimit" @click="setSelectedVariable()" >{{ __('Add variable') }}</gl-button > diff --git a/app/assets/javascripts/ci_variable_list/constants.js b/app/assets/javascripts/ci_variable_list/constants.js index ccad08ef8b6..828d0724d93 100644 --- a/app/assets/javascripts/ci_variable_list/constants.js +++ b/app/assets/javascripts/ci_variable_list/constants.js @@ -1,4 +1,4 @@ -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; export const ADD_CI_VARIABLE_MODAL_ID = 'add-ci-variable'; @@ -43,6 +43,7 @@ export const defaultVariableState = { key: '', masked: false, protected: false, + raw: false, value: '', variableType: variableTypes.envType, }; @@ -69,10 +70,19 @@ export const AWS_SECRET_ACCESS_KEY = 'AWS_SECRET_ACCESS_KEY'; export const AWS_TOKEN_CONSTANTS = [AWS_ACCESS_KEY_ID, AWS_DEFAULT_REGION, AWS_SECRET_ACCESS_KEY]; export const CONTAINS_VARIABLE_REFERENCE_MESSAGE = __( - 'Values that contain the %{codeStart}$%{codeEnd} character can be considered a variable reference and expanded. %{docsLinkStart}Learn more.%{docsLinkEnd}', + 'Unselect "Expand variable reference" if you want to use the variable value as a raw string.', ); export const ENVIRONMENT_SCOPE_LINK_TITLE = __('Learn more'); +export const EXCEEDS_VARIABLE_LIMIT_TEXT = s__( + 'CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables.', +); +export const DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT = s__( + 'CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables.', +); +export const MAXIMUM_VARIABLE_LIMIT_REACHED = s__( + 'CiVariables|Maximum number of variables reached.', +); export const ADD_VARIABLE_ACTION = 'ADD_VARIABLE'; export const EDIT_VARIABLE_ACTION = 'EDIT_VARIABLE'; @@ -85,6 +95,10 @@ export const ADD_MUTATION_ACTION = 'add'; export const UPDATE_MUTATION_ACTION = 'update'; export const DELETE_MUTATION_ACTION = 'delete'; +export const EXPANDED_VARIABLES_NOTE = __( + '%{codeStart}$%{codeEnd} will be treated as the start of a reference to another variable.', +); + export const environmentFetchErrorText = __( 'There was an error fetching the environments information.', ); diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql index c44ee2ecc1d..24388637672 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql @@ -16,6 +16,7 @@ mutation addGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPath: environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql index 53e9b411dd2..f7c8e209ccd 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql @@ -16,6 +16,7 @@ mutation deleteGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPa environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql index 2dddca14bd8..757e61a5cd3 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql @@ -16,6 +16,7 @@ mutation updateGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPa environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql index 39504770e33..fa315084d86 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql @@ -16,6 +16,7 @@ mutation addProjectVariable($variable: CiVariable!, $endpoint: String!, $fullPat environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql index f55c255e332..c3358cc35b9 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql @@ -21,6 +21,7 @@ mutation deleteProjectVariable( environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql index fc589e8a939..fde92cef4cb 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql @@ -21,6 +21,7 @@ mutation updateProjectVariable( environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/queries/group_variables.query.graphql b/app/assets/javascripts/ci_variable_list/graphql/queries/group_variables.query.graphql index b5555fe4401..900154cd24d 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/queries/group_variables.query.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/queries/group_variables.query.graphql @@ -5,6 +5,7 @@ query getGroupVariables($after: String, $first: Int = 100, $fullPath: ID!) { group(fullPath: $fullPath) { id ciVariables(after: $after, first: $first) { + limit pageInfo { ...PageInfo } @@ -14,6 +15,7 @@ query getGroupVariables($after: String, $first: Int = 100, $fullPath: ID!) { environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/queries/project_variables.query.graphql b/app/assets/javascripts/ci_variable_list/graphql/queries/project_variables.query.graphql index 08b5bf7af16..ee75eba7547 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/queries/project_variables.query.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/queries/project_variables.query.graphql @@ -5,6 +5,7 @@ query getProjectVariables($after: String, $first: Int = 100, $fullPath: ID!) { project(fullPath: $fullPath) { id ciVariables(after: $after, first: $first) { + limit pageInfo { ...PageInfo } @@ -13,6 +14,7 @@ query getProjectVariables($after: String, $first: Int = 100, $fullPath: ID!) { environmentScope masked protected + raw } } } diff --git a/app/assets/javascripts/ci_variable_list/graphql/queries/variables.query.graphql b/app/assets/javascripts/ci_variable_list/graphql/queries/variables.query.graphql index 2667d6606fe..9b255c3c182 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/queries/variables.query.graphql +++ b/app/assets/javascripts/ci_variable_list/graphql/queries/variables.query.graphql @@ -11,6 +11,7 @@ query getVariables($after: String, $first: Int = 100) { ... on CiInstanceVariable { masked protected + raw } } } |