summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/ci_variable_list/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/ci_variable_list/components')
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue36
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue90
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue54
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue56
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_autocomplete_tokens.js15
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue503
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue108
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue242
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue298
9 files changed, 0 insertions, 1402 deletions
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue b/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue
deleted file mode 100644
index 719696f682e..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue
+++ /dev/null
@@ -1,36 +0,0 @@
-<script>
-import { ADD_MUTATION_ACTION, DELETE_MUTATION_ACTION, UPDATE_MUTATION_ACTION } from '../constants';
-import getAdminVariables from '../graphql/queries/variables.query.graphql';
-import addAdminVariable from '../graphql/mutations/admin_add_variable.mutation.graphql';
-import deleteAdminVariable from '../graphql/mutations/admin_delete_variable.mutation.graphql';
-import updateAdminVariable from '../graphql/mutations/admin_update_variable.mutation.graphql';
-import CiVariableShared from './ci_variable_shared.vue';
-
-export default {
- components: {
- CiVariableShared,
- },
- mutationData: {
- [ADD_MUTATION_ACTION]: addAdminVariable,
- [UPDATE_MUTATION_ACTION]: updateAdminVariable,
- [DELETE_MUTATION_ACTION]: deleteAdminVariable,
- },
- queryData: {
- ciVariables: {
- lookup: (data) => data?.ciVariables,
- query: getAdminVariables,
- },
- },
-};
-</script>
-
-<template>
- <ci-variable-shared
- :are-scoped-variables-available="false"
- component-name="InstanceVariables"
- :hide-environment-scope="true"
- :mutation-data="$options.mutationData"
- :refetch-after-mutation="true"
- :query-data="$options.queryData"
- />
-</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue b/app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue
deleted file mode 100644
index c9002edc1ab..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue
+++ /dev/null
@@ -1,90 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem, GlDropdownDivider, GlSearchBoxByType } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
-import { convertEnvironmentScope } from '../utils';
-
-export default {
- name: 'CiEnvironmentsDropdown',
- components: {
- GlDropdown,
- GlDropdownItem,
- GlDropdownDivider,
- GlSearchBoxByType,
- },
- props: {
- environments: {
- type: Array,
- required: true,
- },
- selectedEnvironmentScope: {
- type: String,
- required: false,
- default: '',
- },
- },
- data() {
- return {
- searchTerm: '',
- };
- },
- computed: {
- composedCreateButtonLabel() {
- return sprintf(__('Create wildcard: %{searchTerm}'), { searchTerm: this.searchTerm });
- },
- filteredEnvironments() {
- const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
- return this.environments.filter((environment) => {
- return environment.toLowerCase().includes(lowerCasedSearchTerm);
- });
- },
- shouldRenderCreateButton() {
- return this.searchTerm && !this.environments.includes(this.searchTerm);
- },
- environmentScopeLabel() {
- return convertEnvironmentScope(this.selectedEnvironmentScope);
- },
- },
- methods: {
- selectEnvironment(selected) {
- this.$emit('select-environment', selected);
- this.clearSearch();
- },
- convertEnvironmentScopeValue(scope) {
- return convertEnvironmentScope(scope);
- },
- createEnvironmentScope() {
- this.$emit('create-environment-scope', this.searchTerm);
- this.selectEnvironment(this.searchTerm);
- },
- isSelected(env) {
- return this.selectedEnvironmentScope === env;
- },
- clearSearch() {
- this.searchTerm = '';
- },
- },
-};
-</script>
-<template>
- <gl-dropdown :text="environmentScopeLabel" @show="clearSearch">
- <gl-search-box-by-type v-model.trim="searchTerm" data-testid="ci-environment-search" />
- <gl-dropdown-item
- v-for="environment in filteredEnvironments"
- :key="environment"
- :is-checked="isSelected(environment)"
- is-check-item
- @click="selectEnvironment(environment)"
- >
- {{ convertEnvironmentScopeValue(environment) }}
- </gl-dropdown-item>
- <gl-dropdown-item v-if="!filteredEnvironments.length" ref="noMatchingResults">{{
- __('No matching results')
- }}</gl-dropdown-item>
- <template v-if="shouldRenderCreateButton">
- <gl-dropdown-divider />
- <gl-dropdown-item data-testid="create-wildcard-button" @click="createEnvironmentScope">
- {{ composedCreateButtonLabel }}
- </gl-dropdown-item>
- </template>
- </gl-dropdown>
-</template>
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
deleted file mode 100644
index 4466a6a8081..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue
+++ /dev/null
@@ -1,54 +0,0 @@
-<script>
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import {
- ADD_MUTATION_ACTION,
- DELETE_MUTATION_ACTION,
- GRAPHQL_GROUP_TYPE,
- UPDATE_MUTATION_ACTION,
-} from '../constants';
-import getGroupVariables from '../graphql/queries/group_variables.query.graphql';
-import addGroupVariable from '../graphql/mutations/group_add_variable.mutation.graphql';
-import deleteGroupVariable from '../graphql/mutations/group_delete_variable.mutation.graphql';
-import updateGroupVariable from '../graphql/mutations/group_update_variable.mutation.graphql';
-import CiVariableShared from './ci_variable_shared.vue';
-
-export default {
- components: {
- CiVariableShared,
- },
- mixins: [glFeatureFlagsMixin()],
- inject: ['groupPath', 'groupId'],
- computed: {
- areScopedVariablesAvailable() {
- return this.glFeatures.groupScopedCiVariables;
- },
- graphqlId() {
- return convertToGraphQLId(GRAPHQL_GROUP_TYPE, this.groupId);
- },
- },
- mutationData: {
- [ADD_MUTATION_ACTION]: addGroupVariable,
- [UPDATE_MUTATION_ACTION]: updateGroupVariable,
- [DELETE_MUTATION_ACTION]: deleteGroupVariable,
- },
- queryData: {
- ciVariables: {
- lookup: (data) => data?.group?.ciVariables,
- query: getGroupVariables,
- },
- },
-};
-</script>
-
-<template>
- <ci-variable-shared
- :id="graphqlId"
- :are-scoped-variables-available="areScopedVariablesAvailable"
- component-name="GroupVariables"
- entity="group"
- :full-path="groupPath"
- :mutation-data="$options.mutationData"
- :query-data="$options.queryData"
- />
-</template>
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
deleted file mode 100644
index 6326940148a..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-<script>
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import {
- ADD_MUTATION_ACTION,
- DELETE_MUTATION_ACTION,
- GRAPHQL_PROJECT_TYPE,
- UPDATE_MUTATION_ACTION,
-} from '../constants';
-import getProjectEnvironments from '../graphql/queries/project_environments.query.graphql';
-import getProjectVariables from '../graphql/queries/project_variables.query.graphql';
-import addProjectVariable from '../graphql/mutations/project_add_variable.mutation.graphql';
-import deleteProjectVariable from '../graphql/mutations/project_delete_variable.mutation.graphql';
-import updateProjectVariable from '../graphql/mutations/project_update_variable.mutation.graphql';
-import CiVariableShared from './ci_variable_shared.vue';
-
-export default {
- components: {
- CiVariableShared,
- },
- mixins: [glFeatureFlagsMixin()],
- inject: ['projectFullPath', 'projectId'],
- computed: {
- graphqlId() {
- return convertToGraphQLId(GRAPHQL_PROJECT_TYPE, this.projectId);
- },
- },
- mutationData: {
- [ADD_MUTATION_ACTION]: addProjectVariable,
- [UPDATE_MUTATION_ACTION]: updateProjectVariable,
- [DELETE_MUTATION_ACTION]: deleteProjectVariable,
- },
- queryData: {
- ciVariables: {
- lookup: (data) => data?.project?.ciVariables,
- query: getProjectVariables,
- },
- environments: {
- lookup: (data) => data?.project?.environments,
- query: getProjectEnvironments,
- },
- },
-};
-</script>
-
-<template>
- <ci-variable-shared
- :id="graphqlId"
- :are-scoped-variables-available="true"
- component-name="ProjectVariables"
- entity="project"
- :full-path="projectFullPath"
- :mutation-data="$options.mutationData"
- :query-data="$options.queryData"
- />
-</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
deleted file mode 100644
index 3f25e3df305..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_autocomplete_tokens.js
+++ /dev/null
@@ -1,15 +0,0 @@
-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,
- },
- [AWS_DEFAULT_REGION]: {
- name: AWS_DEFAULT_REGION,
- },
- [AWS_SECRET_ACCESS_KEY]: {
- name: AWS_SECRET_ACCESS_KEY,
- },
-};
-
-export const awsTokenList = Object.keys(awsTokens);
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
deleted file mode 100644
index 00177539cdc..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
+++ /dev/null
@@ -1,503 +0,0 @@
-<script>
-import {
- GlAlert,
- GlButton,
- GlCollapse,
- GlFormCheckbox,
- GlFormCombobox,
- GlFormGroup,
- GlFormSelect,
- GlFormInput,
- GlFormTextarea,
- GlIcon,
- GlLink,
- GlModal,
- GlSprintf,
-} from '@gitlab/ui';
-import { getCookie, setCookie } from '~/lib/utils/common_utils';
-import { __ } from '~/locale';
-import Tracking from '~/tracking';
-
-import {
- allEnvironments,
- AWS_TOKEN_CONSTANTS,
- ADD_CI_VARIABLE_MODAL_ID,
- AWS_TIP_DISMISSED_COOKIE_NAME,
- AWS_TIP_MESSAGE,
- CONTAINS_VARIABLE_REFERENCE_MESSAGE,
- defaultVariableState,
- ENVIRONMENT_SCOPE_LINK_TITLE,
- EVENT_LABEL,
- EVENT_ACTION,
- EXPANDED_VARIABLES_NOTE,
- EDIT_VARIABLE_ACTION,
- VARIABLE_ACTIONS,
- variableOptions,
-} from '../constants';
-import { createJoinedEnvironments } from '../utils';
-import CiEnvironmentsDropdown from './ci_environments_dropdown.vue';
-import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
-
-const trackingMixin = Tracking.mixin({ label: EVENT_LABEL });
-
-export default {
- modalId: ADD_CI_VARIABLE_MODAL_ID,
- tokens: awsTokens,
- tokenList: awsTokenList,
- awsTipMessage: AWS_TIP_MESSAGE,
- containsVariableReferenceMessage: CONTAINS_VARIABLE_REFERENCE_MESSAGE,
- environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE,
- expandedVariablesNote: EXPANDED_VARIABLES_NOTE,
- components: {
- CiEnvironmentsDropdown,
- GlAlert,
- GlButton,
- GlCollapse,
- GlFormCheckbox,
- GlFormCombobox,
- GlFormGroup,
- GlFormSelect,
- GlFormInput,
- GlFormTextarea,
- GlIcon,
- GlLink,
- GlModal,
- GlSprintf,
- },
- mixins: [trackingMixin],
- inject: [
- 'awsLogoSvgPath',
- 'awsTipCommandsLink',
- 'awsTipDeployLink',
- 'awsTipLearnLink',
- 'containsVariableReferenceLink',
- 'environmentScopeLink',
- 'isProtectedByDefault',
- 'maskedEnvironmentVariablesLink',
- 'maskableRegex',
- 'protectedEnvironmentVariablesLink',
- ],
- props: {
- areScopedVariablesAvailable: {
- type: Boolean,
- required: false,
- default: false,
- },
- environments: {
- type: Array,
- required: false,
- default: () => [],
- },
- hideEnvironmentScope: {
- type: Boolean,
- required: false,
- default: false,
- },
- mode: {
- type: String,
- required: true,
- validator(val) {
- return VARIABLE_ACTIONS.includes(val);
- },
- },
- selectedVariable: {
- type: Object,
- required: false,
- default: () => {},
- },
- variables: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- data() {
- return {
- newEnvironments: [],
- isTipDismissed: getCookie(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
- validationErrorEventProperty: '',
- variable: { ...defaultVariableState, ...this.selectedVariable },
- };
- },
- computed: {
- canMask() {
- const regex = RegExp(this.maskableRegex);
- return regex.test(this.variable.value);
- },
- canSubmit() {
- return this.variableValidationState && this.variable.key !== '' && this.variable.value !== '';
- },
- containsVariableReference() {
- const regex = /\$/;
- return regex.test(this.variable.value) && this.isExpanded;
- },
- displayMaskedError() {
- return !this.canMask && this.variable.masked;
- },
- isEditing() {
- return this.mode === EDIT_VARIABLE_ACTION;
- },
- isExpanded() {
- return !this.variable.raw;
- },
- isTipVisible() {
- return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variable.key);
- },
- joinedEnvironments() {
- return createJoinedEnvironments(this.variables, this.environments, this.newEnvironments);
- },
- maskedFeedback() {
- return this.displayMaskedError ? __('This variable can not be masked.') : '';
- },
- maskedState() {
- if (this.displayMaskedError) {
- return false;
- }
- return true;
- },
- modalActionText() {
- return this.isEditing ? __('Update variable') : __('Add variable');
- },
- tokenValidationFeedback() {
- const tokenSpecificFeedback = this.$options.tokens?.[this.variable.key]?.invalidMessage;
- if (!this.tokenValidationState && tokenSpecificFeedback) {
- return tokenSpecificFeedback;
- }
- return '';
- },
- tokenValidationState() {
- const validator = this.$options.tokens?.[this.variable.key]?.validation;
-
- if (validator) {
- return validator(this.variable.value);
- }
-
- return true;
- },
- variableValidationFeedback() {
- return `${this.tokenValidationFeedback} ${this.maskedFeedback}`;
- },
- variableValidationState() {
- return this.variable.value === '' || (this.tokenValidationState && this.maskedState);
- },
- },
- watch: {
- variable: {
- handler() {
- this.trackVariableValidationErrors();
- },
- deep: true,
- },
- },
- methods: {
- addVariable() {
- this.$emit('add-variable', this.variable);
- },
- createEnvironmentScope(env) {
- this.newEnvironments.push(env);
- },
- deleteVariable() {
- this.$emit('delete-variable', this.variable);
- },
- updateVariable() {
- this.$emit('update-variable', this.variable);
- },
- dismissTip() {
- setCookie(AWS_TIP_DISMISSED_COOKIE_NAME, 'true', { expires: 90 });
- this.isTipDismissed = true;
- },
- deleteVarAndClose() {
- this.deleteVariable();
- this.hideModal();
- },
- hideModal() {
- this.$refs.modal.hide();
- },
- onShow() {
- this.setVariableProtectedByDefault();
- },
- resetModalHandler() {
- this.resetVariableData();
- this.resetValidationErrorEvents();
-
- this.$emit('hideModal');
- },
- resetVariableData() {
- this.variable = { ...defaultVariableState };
- },
- setEnvironmentScope(scope) {
- this.variable = { ...this.variable, environmentScope: scope };
- },
- setVariableRaw(expanded) {
- this.variable = { ...this.variable, raw: !expanded };
- },
- setVariableProtected() {
- this.variable = { ...this.variable, protected: true };
- },
- updateOrAddVariable() {
- if (this.isEditing) {
- this.updateVariable();
- } else {
- this.addVariable();
- }
- this.hideModal();
- },
- setVariableProtectedByDefault() {
- if (this.isProtectedByDefault && !this.isEditing) {
- this.setVariableProtected();
- }
- },
- trackVariableValidationErrors() {
- const property = this.getTrackingErrorProperty();
- if (!this.validationErrorEventProperty && property) {
- this.track(EVENT_ACTION, { property });
- this.validationErrorEventProperty = property;
- }
- },
- getTrackingErrorProperty() {
- let property;
- if (this.variable.value?.length && !property) {
- if (this.displayMaskedError && this.maskableRegex?.length) {
- const supportedChars = this.maskableRegex.replace('^', '').replace(/{(\d,)}\$/, '');
- const regex = new RegExp(supportedChars, 'g');
- property = this.variable.value.replace(regex, '');
- }
- if (this.containsVariableReference) {
- property = '$';
- }
- }
-
- return property;
- },
- resetValidationErrorEvents() {
- this.validationErrorEventProperty = '';
- },
- },
- defaultScope: allEnvironments.text,
- variableOptions,
-};
-</script>
-
-<template>
- <gl-modal
- ref="modal"
- :modal-id="$options.modalId"
- :title="modalActionText"
- static
- lazy
- @hidden="resetModalHandler"
- @shown="onShow"
- >
- <form>
- <gl-form-combobox
- v-model="variable.key"
- :token-list="$options.tokenList"
- :label-text="__('Key')"
- data-testid="pipeline-form-ci-variable-key"
- data-qa-selector="ci_variable_key_field"
- />
-
- <gl-form-group
- :label="__('Value')"
- label-for="ci-variable-value"
- :state="variableValidationState"
- :invalid-feedback="variableValidationFeedback"
- >
- <gl-form-textarea
- id="ci-variable-value"
- ref="valueField"
- v-model="variable.value"
- :state="variableValidationState"
- rows="3"
- max-rows="10"
- data-testid="pipeline-form-ci-variable-value"
- data-qa-selector="ci_variable_value_field"
- 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">
- <gl-form-group :label="__('Type')" label-for="ci-variable-type" class="gl-w-half gl-mr-5">
- <gl-form-select
- id="ci-variable-type"
- v-model="variable.variableType"
- :options="$options.variableOptions"
- />
- </gl-form-group>
-
- <template v-if="!hideEnvironmentScope">
- <gl-form-group
- label-for="ci-variable-env"
- class="gl-w-half"
- data-testid="environment-scope"
- >
- <template #label>
- {{ __('Environment scope') }}
- <gl-link
- :title="$options.environmentScopeLinkTitle"
- :href="environmentScopeLink"
- target="_blank"
- data-testid="environment-scope-link"
- >
- <gl-icon name="question" :size="12" />
- </gl-link>
- </template>
- <ci-environments-dropdown
- v-if="areScopedVariablesAvailable"
- class="gl-w-full"
- :selected-environment-scope="variable.environmentScope"
- :environments="joinedEnvironments"
- @select-environment="setEnvironmentScope"
- @create-environment-scope="createEnvironmentScope"
- />
-
- <gl-form-input v-else :value="$options.defaultScope" class="gl-w-full" readonly />
- </gl-form-group>
- </template>
- </div>
-
- <gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
- <gl-form-checkbox
- v-model="variable.protected"
- class="gl-mb-0"
- data-testid="ci-variable-protected-checkbox"
- :data-is-protected-checked="variable.protected"
- >
- {{ __('Protect variable') }}
- <gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
- <gl-icon name="question" :size="12" />
- </gl-link>
- <p class="gl-mt-2 text-secondary">
- {{ __('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"
- data-testid="ci-variable-masked-checkbox"
- >
- {{ __('Mask variable') }}
- <gl-link target="_blank" :href="maskedEnvironmentVariablesLink">
- <gl-icon name="question" :size="12" />
- </gl-link>
- <p class="gl-mt-2 text-secondary">
- {{ __('Variable will be masked in job logs.') }}
- <span
- :class="{
- 'bold text-plain': displayMaskedError,
- }"
- >
- {{ __('Requires values to meet regular expression requirements.') }}</span
- >
- <gl-link target="_blank" :href="maskedEnvironmentVariablesLink">{{
- __('More information')
- }}</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">
- <gl-alert
- :title="__('Deploying to AWS is easy with GitLab')"
- variant="tip"
- data-testid="aws-guidance-tip"
- @dismiss="dismissTip"
- >
- <div class="gl-display-flex gl-flex-direction-row gl-flex-wrap-wrap gl-md-flex-wrap-nowrap">
- <div>
- <p>
- <gl-sprintf :message="$options.awsTipMessage">
- <template #deployLink="{ content }">
- <gl-link :href="awsTipDeployLink" target="_blank">{{ content }}</gl-link>
- </template>
- <template #commandsLink="{ content }">
- <gl-link :href="awsTipCommandsLink" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- <p>
- <gl-button
- :href="awsTipLearnLink"
- target="_blank"
- category="secondary"
- variant="confirm"
- class="gl-overflow-wrap-break"
- >{{ __('Learn more about deploying to AWS') }}</gl-button
- >
- </p>
- </div>
- <img
- class="gl-mt-3"
- :alt="__('Amazon Web Services Logo')"
- :src="awsLogoSvgPath"
- height="32"
- />
- </div>
- </gl-alert>
- </gl-collapse>
- <gl-alert
- v-if="containsVariableReference"
- :title="__('Value might contain a variable reference')"
- :dismissible="false"
- variant="warning"
- data-testid="contains-variable-reference"
- >
- <gl-sprintf :message="$options.containsVariableReferenceMessage">
- <template #code="{ content }">
- <code>{{ content }}</code>
- </template>
- <template #docsLink="{ content }">
- <gl-link :href="containsVariableReferenceLink" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </gl-alert>
- <template #modal-footer>
- <gl-button @click="hideModal">{{ __('Cancel') }}</gl-button>
- <gl-button
- v-if="isEditing"
- ref="deleteCiVariable"
- variant="danger"
- category="secondary"
- data-qa-selector="ci_variable_delete_button"
- @click="deleteVarAndClose"
- >{{ __('Delete variable') }}</gl-button
- >
- <gl-button
- ref="updateOrAddVariable"
- :disabled="!canSubmit"
- variant="confirm"
- category="primary"
- data-testid="ciUpdateOrAddVariableBtn"
- data-qa-selector="ci_variable_save_button"
- @click="updateOrAddVariable"
- >{{ modalActionText }}
- </gl-button>
- </template>
- </gl-modal>
-</template>
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
deleted file mode 100644
index 3c6114b38ce..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue
+++ /dev/null
@@ -1,108 +0,0 @@
-<script>
-import { ADD_VARIABLE_ACTION, EDIT_VARIABLE_ACTION, VARIABLE_ACTIONS } from '../constants';
-import CiVariableTable from './ci_variable_table.vue';
-import CiVariableModal from './ci_variable_modal.vue';
-
-export default {
- components: {
- CiVariableTable,
- CiVariableModal,
- },
- props: {
- areScopedVariablesAvailable: {
- type: Boolean,
- required: false,
- default: false,
- },
- entity: {
- type: String,
- required: false,
- default: '',
- },
- environments: {
- type: Array,
- required: false,
- default: () => [],
- },
- hideEnvironmentScope: {
- type: Boolean,
- required: false,
- default: false,
- },
- isLoading: {
- type: Boolean,
- required: false,
- },
- maxVariableLimit: {
- type: Number,
- required: false,
- default: 0,
- },
- variables: {
- type: Array,
- required: true,
- },
- },
- data() {
- return {
- selectedVariable: {},
- mode: null,
- };
- },
- computed: {
- showModal() {
- return VARIABLE_ACTIONS.includes(this.mode);
- },
- },
- methods: {
- addVariable(variable) {
- this.$emit('add-variable', variable);
- },
- deleteVariable(variable) {
- this.$emit('delete-variable', variable);
- },
- updateVariable(variable) {
- this.$emit('update-variable', variable);
- },
- hideModal() {
- this.mode = null;
- },
- setSelectedVariable(variable = null) {
- if (!variable) {
- this.selectedVariable = {};
- this.mode = ADD_VARIABLE_ACTION;
- } else {
- this.selectedVariable = variable;
- this.mode = EDIT_VARIABLE_ACTION;
- }
- },
- },
-};
-</script>
-
-<template>
- <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"
- />
- <ci-variable-modal
- v-if="showModal"
- :are-scoped-variables-available="areScopedVariablesAvailable"
- :environments="environments"
- :hide-environment-scope="hideEnvironmentScope"
- :variables="variables"
- :mode="mode"
- :selected-variable="selectedVariable"
- @add-variable="addVariable"
- @delete-variable="deleteVariable"
- @hideModal="hideModal"
- @update-variable="updateVariable"
- />
- </div>
- </div>
-</template>
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
deleted file mode 100644
index 6e39bda0b07..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue
+++ /dev/null
@@ -1,242 +0,0 @@
-<script>
-import { createAlert } from '~/flash';
-import { __ } from '~/locale';
-import { mapEnvironmentNames, reportMessageToSentry } from '../utils';
-import {
- ADD_MUTATION_ACTION,
- DELETE_MUTATION_ACTION,
- UPDATE_MUTATION_ACTION,
- environmentFetchErrorText,
- genericMutationErrorText,
- variableFetchErrorText,
-} from '../constants';
-import CiVariableSettings from './ci_variable_settings.vue';
-
-export default {
- components: {
- CiVariableSettings,
- },
- inject: ['endpoint'],
- props: {
- areScopedVariablesAvailable: {
- required: true,
- type: Boolean,
- },
- componentName: {
- required: true,
- type: String,
- },
- entity: {
- required: false,
- type: String,
- default: '',
- },
- fullPath: {
- required: false,
- type: String,
- default: null,
- },
- hideEnvironmentScope: {
- type: Boolean,
- required: false,
- default: false,
- },
- id: {
- required: false,
- type: String,
- default: null,
- },
- mutationData: {
- required: true,
- type: Object,
- validator: (obj) => {
- const hasValidKeys = Object.keys(obj).includes(
- ADD_MUTATION_ACTION,
- UPDATE_MUTATION_ACTION,
- DELETE_MUTATION_ACTION,
- );
-
- const hasValidValues = Object.values(obj).reduce((acc, val) => {
- return acc && typeof val === 'object';
- }, true);
-
- return hasValidKeys && hasValidValues;
- },
- },
- refetchAfterMutation: {
- required: false,
- type: Boolean,
- default: false,
- },
- queryData: {
- required: true,
- type: Object,
- validator: (obj) => {
- const { ciVariables, environments } = obj;
- const hasCiVariablesKey = Boolean(ciVariables);
- let hasCorrectEnvData = true;
-
- const hasCorrectVariablesData =
- typeof ciVariables?.lookup === 'function' && typeof ciVariables.query === 'object';
-
- if (environments) {
- hasCorrectEnvData =
- typeof environments?.lookup === 'function' && typeof environments.query === 'object';
- }
-
- return hasCiVariablesKey && hasCorrectVariablesData && hasCorrectEnvData;
- },
- },
- },
- data() {
- return {
- ciVariables: [],
- hasNextPage: false,
- isInitialLoading: true,
- isLoadingMoreItems: false,
- loadingCounter: 0,
- maxVariableLimit: 0,
- pageInfo: {},
- };
- },
- apollo: {
- ciVariables: {
- query() {
- return this.queryData.ciVariables.query;
- },
- variables() {
- return {
- fullPath: this.fullPath || undefined,
- };
- },
- update(data) {
- 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;
-
- // Because graphQL has a limit of 100 items,
- // we batch load all the variables by making successive queries
- // to keep the same UX. As a safeguard, we make sure that we cannot go over
- // 20 consecutive API calls, which means 2000 variables loaded maximum.
- if (!this.hasNextPage) {
- this.isLoadingMoreItems = false;
- } else if (this.loadingCounter < 20) {
- this.hasNextPage = false;
- this.fetchMoreVariables();
- this.loadingCounter += 1;
- } else {
- createAlert({ message: this.$options.tooManyCallsError });
- reportMessageToSentry(this.componentName, this.$options.tooManyCallsError, {});
- }
- },
- error() {
- this.isLoadingMoreItems = false;
- this.hasNextPage = false;
- createAlert({ message: variableFetchErrorText });
- },
- watchLoading(flag) {
- if (!flag) {
- this.isInitialLoading = false;
- }
- },
- },
- environments: {
- query() {
- return this.queryData?.environments?.query || {};
- },
- skip() {
- return !this.queryData?.environments?.query;
- },
- variables() {
- return {
- fullPath: this.fullPath,
- };
- },
- update(data) {
- return mapEnvironmentNames(this.queryData.environments.lookup(data)?.nodes);
- },
- error() {
- createAlert({ message: environmentFetchErrorText });
- },
- },
- },
- computed: {
- isLoading() {
- return (
- (this.$apollo.queries.ciVariables.loading && this.isInitialLoading) ||
- this.$apollo.queries.environments.loading ||
- this.isLoadingMoreItems
- );
- },
- },
- methods: {
- addVariable(variable) {
- this.variableMutation(ADD_MUTATION_ACTION, variable);
- },
- deleteVariable(variable) {
- this.variableMutation(DELETE_MUTATION_ACTION, variable);
- },
- fetchMoreVariables() {
- this.isLoadingMoreItems = true;
-
- this.$apollo.queries.ciVariables.fetchMore({
- variables: {
- after: this.pageInfo.endCursor,
- },
- });
- },
- updateVariable(variable) {
- this.variableMutation(UPDATE_MUTATION_ACTION, variable);
- },
- async variableMutation(mutationAction, variable) {
- try {
- const currentMutation = this.mutationData[mutationAction];
-
- const { data } = await this.$apollo.mutate({
- mutation: currentMutation,
- variables: {
- endpoint: this.endpoint,
- fullPath: this.fullPath || undefined,
- id: this.id || undefined,
- variable,
- },
- });
-
- if (data.ciVariableMutation?.errors?.length) {
- const { errors } = data.ciVariableMutation;
- createAlert({ message: errors[0] });
- } else if (this.refetchAfterMutation) {
- // The writing to cache for admin variable is not working
- // because there is no ID in the cache at the top level.
- // We therefore need to manually refetch.
- this.$apollo.queries.ciVariables.refetch();
- }
- } catch (e) {
- createAlert({ message: genericMutationErrorText });
- }
- },
- },
- i18n: {
- tooManyCallsError: __('Maximum number of variables loaded (2000)'),
- },
-};
-</script>
-
-<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"
- @update-variable="updateVariable"
- />
-</template>
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
deleted file mode 100644
index 345a8def49d..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
+++ /dev/null
@@ -1,298 +0,0 @@
-<script>
-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,
- DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT,
- EXCEEDS_VARIABLE_LIMIT_TEXT,
- MAXIMUM_VARIABLE_LIMIT_REACHED,
- variableText,
-} from '../constants';
-import { convertEnvironmentScope } from '../utils';
-
-export default {
- modalId: ADD_CI_VARIABLE_MODAL_ID,
- fields: [
- {
- key: 'variableType',
- label: s__('CiVariables|Type'),
- thClass: 'gl-w-10p',
- },
- {
- key: 'key',
- label: s__('CiVariables|Key'),
- tdClass: 'text-plain',
- sortable: true,
- },
- {
- key: 'value',
- label: s__('CiVariables|Value'),
- thClass: 'gl-w-15p',
- },
- {
- key: 'options',
- label: s__('CiVariables|Options'),
- thClass: 'gl-w-10p',
- },
- {
- key: 'environmentScope',
- label: s__('CiVariables|Environments'),
- },
- {
- key: 'actions',
- label: '',
- tdClass: 'text-right',
- thClass: 'gl-w-5p',
- },
- ],
- components: {
- GlAlert,
- GlButton,
- GlLoadingIcon,
- GlTable,
- },
- directives: {
- GlModalDirective,
- GlTooltip: GlTooltipDirective,
- },
- mixins: [glFeatureFlagsMixin()],
- props: {
- entity: {
- type: String,
- required: false,
- default: '',
- },
- isLoading: {
- type: Boolean,
- required: true,
- },
- maxVariableLimit: {
- type: Number,
- required: true,
- },
- variables: {
- type: Array,
- required: true,
- },
- },
- data() {
- return {
- areValuesHidden: true,
- };
- },
- 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');
- },
- isTableEmpty() {
- return !this.variables || this.variables.length === 0;
- },
- fields() {
- return this.$options.fields;
- },
- variablesWithOptions() {
- return this.variables?.map((item, index) => ({
- ...item,
- options: this.getOptions(item),
- index,
- }));
- },
- },
- methods: {
- convertEnvironmentScopeValue(env) {
- return convertEnvironmentScope(env);
- },
- generateTypeText(item) {
- return variableText[item.variableType];
- },
- toggleHiddenState() {
- this.areValuesHidden = !this.areValuesHidden;
- },
- setSelectedVariable(index = -1) {
- this.$emit('set-selected-variable', this.variables[index] ?? null);
- },
- getOptions(item) {
- const options = [];
- if (item.protected) {
- options.push(s__('CiVariables|Protected'));
- }
- 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-if="!isLoading"
- :fields="fields"
- :items="variablesWithOptions"
- tbody-tr-class="js-ci-variable-row"
- data-qa-selector="ci_variable_table_content"
- sort-by="key"
- sort-direction="asc"
- stacked="lg"
- table-class="text-secondary"
- fixed
- show-empty
- sort-icon-left
- no-sort-reset
- >
- <template #table-colgroup="scope">
- <col v-for="field in scope.fields" :key="field.key" :style="field.customStyle" />
- </template>
- <template #cell(variableType)="{ item }">
- {{ generateTypeText(item) }}
- </template>
- <template #cell(key)="{ item }">
- <div
- class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
- >
- <span
- :id="`ci-variable-key-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-word-break-word"
- >{{ item.key }}</span
- >
- <gl-button
- v-gl-tooltip
- category="tertiary"
- icon="copy-to-clipboard"
- class="gl-my-n3 gl-ml-2"
- :title="__('Copy key')"
- :data-clipboard-text="item.key"
- :aria-label="__('Copy to clipboard')"
- />
- </div>
- </template>
- <template #cell(value)="{ item }">
- <div
- class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
- >
- <span v-if="areValuesHidden" data-testid="hiddenValue">*****</span>
- <span
- v-else
- :id="`ci-variable-value-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- data-testid="revealedValue"
- >{{ item.value }}</span
- >
- <gl-button
- v-gl-tooltip
- category="tertiary"
- icon="copy-to-clipboard"
- class="gl-my-n3 gl-ml-2"
- :title="__('Copy value')"
- :data-clipboard-text="item.value"
- :aria-label="__('Copy to clipboard')"
- />
- </div>
- </template>
- <template #cell(options)="{ item }">
- <span data-testid="ci-variable-table-row-options">{{ item.options }}</span>
- </template>
- <template #cell(environmentScope)="{ item }">
- <div
- class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
- >
- <span
- :id="`ci-variable-env-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-word-break-word"
- >{{ convertEnvironmentScopeValue(item.environmentScope) }}</span
- >
- <gl-button
- v-gl-tooltip
- category="tertiary"
- icon="copy-to-clipboard"
- class="gl-my-n3 gl-ml-2"
- :title="__('Copy environment')"
- :data-clipboard-text="convertEnvironmentScopeValue(item.environmentScope)"
- :aria-label="__('Copy to clipboard')"
- />
- </div>
- </template>
- <template #cell(actions)="{ item }">
- <gl-button
- v-gl-modal-directive="$options.modalId"
- icon="pencil"
- :aria-label="__('Edit')"
- data-qa-selector="edit_ci_variable_button"
- @click="setSelectedVariable(item.index)"
- />
- </template>
- <template #empty>
- <p class="gl-text-center gl-py-6 gl-text-black-normal gl-mb-0">
- {{ __('There are no variables yet.') }}
- </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"
- class="gl-mr-3"
- data-qa-selector="add_ci_variable_button"
- variant="confirm"
- category="primary"
- :aria-label="__('Add')"
- :disabled="exceedsVariableLimit"
- @click="setSelectedVariable()"
- >{{ __('Add variable') }}</gl-button
- >
- <gl-button
- v-if="!isTableEmpty"
- data-qa-selector="reveal_ci_variable_value_button"
- @click="toggleHiddenState"
- >{{ valuesButtonText }}</gl-button
- >
- </div>
- </div>
-</template>