diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-20 02:18:09 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-20 02:18:09 +0300 |
commit | 6ed4ec3e0b1340f96b7c043ef51d1b33bbe85fde (patch) | |
tree | dc4d20fe6064752c0bd323187252c77e0a89144b /app/assets/javascripts/ci_variable_list | |
parent | 9868dae7fc0655bd7ce4a6887d4e6d487690eeed (diff) |
Add latest changes from gitlab-org/gitlab@15-4-stable-eev15.4.0-rc42
Diffstat (limited to 'app/assets/javascripts/ci_variable_list')
14 files changed, 322 insertions, 20 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 index 83bad9eb518..59ddf4b19d8 100644 --- a/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue +++ b/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue @@ -11,11 +11,11 @@ import { 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 ciVariableSettings from './ci_variable_settings.vue'; +import CiVariableSettings from './ci_variable_settings.vue'; export default { components: { - ciVariableSettings, + CiVariableSettings, }, inject: ['endpoint'], data() { 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 3af83ffa8ed..3522243e3e7 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 @@ -14,11 +14,11 @@ import { 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 ciVariableSettings from './ci_variable_settings.vue'; +import CiVariableSettings from './ci_variable_settings.vue'; export default { components: { - ciVariableSettings, + CiVariableSettings, }, mixins: [glFeatureFlagsMixin()], inject: ['endpoint', 'groupPath', 'groupId'], 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 new file mode 100644 index 00000000000..29db02a3c59 --- /dev/null +++ b/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue @@ -0,0 +1,120 @@ +<script> +import createFlash from '~/flash'; +import { convertToGraphQLId } from '~/graphql_shared/utils'; +import getProjectEnvironments from '../graphql/queries/project_environments.query.graphql'; +import getProjectVariables from '../graphql/queries/project_variables.query.graphql'; +import { mapEnvironmentNames } from '../utils'; +import { + ADD_MUTATION_ACTION, + DELETE_MUTATION_ACTION, + GRAPHQL_PROJECT_TYPE, + UPDATE_MUTATION_ACTION, + environmentFetchErrorText, + genericMutationErrorText, + variableFetchErrorText, +} from '../constants'; +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 CiVariableSettings from './ci_variable_settings.vue'; + +export default { + components: { + CiVariableSettings, + }, + inject: ['endpoint', 'projectFullPath', 'projectId'], + data() { + return { + projectEnvironments: [], + projectVariables: [], + }; + }, + apollo: { + projectEnvironments: { + query: getProjectEnvironments, + variables() { + return { + fullPath: this.projectFullPath, + }; + }, + update(data) { + return mapEnvironmentNames(data?.project?.environments?.nodes); + }, + error() { + createFlash({ message: environmentFetchErrorText }); + }, + }, + projectVariables: { + query: getProjectVariables, + variables() { + return { + fullPath: this.projectFullPath, + }; + }, + update(data) { + return data?.project?.ciVariables?.nodes || []; + }, + error() { + createFlash({ message: variableFetchErrorText }); + }, + }, + }, + computed: { + isLoading() { + return ( + this.$apollo.queries.projectVariables.loading || + this.$apollo.queries.projectEnvironments.loading + ); + }, + }, + methods: { + addVariable(variable) { + this.variableMutation(ADD_MUTATION_ACTION, variable); + }, + deleteVariable(variable) { + this.variableMutation(DELETE_MUTATION_ACTION, variable); + }, + updateVariable(variable) { + this.variableMutation(UPDATE_MUTATION_ACTION, variable); + }, + async variableMutation(mutationAction, variable) { + try { + const currentMutation = this.$options.mutationData[mutationAction]; + const { data } = await this.$apollo.mutate({ + mutation: currentMutation.action, + variables: { + endpoint: this.endpoint, + fullPath: this.projectFullPath, + projectId: convertToGraphQLId(GRAPHQL_PROJECT_TYPE, this.projectId), + variable, + }, + }); + + const { errors } = data[currentMutation.name]; + if (errors.length > 0) { + createFlash({ message: errors[0] }); + } + } catch (e) { + createFlash({ message: genericMutationErrorText }); + } + }, + }, + mutationData: { + [ADD_MUTATION_ACTION]: { action: addProjectVariable, name: 'addProjectVariable' }, + [UPDATE_MUTATION_ACTION]: { action: updateProjectVariable, name: 'updateProjectVariable' }, + [DELETE_MUTATION_ACTION]: { action: deleteProjectVariable, name: 'deleteProjectVariable' }, + }, +}; +</script> + +<template> + <ci-variable-settings + :are-scoped-variables-available="true" + :environments="projectEnvironments" + :is-loading="isLoading" + :variables="projectVariables" + @add-variable="addVariable" + @delete-variable="deleteVariable" + @update-variable="updateVariable" + /> +</template> 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 5ba63de8c96..56c1804910a 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 @@ -108,7 +108,6 @@ export default { return { newEnvironments: [], isTipDismissed: getCookie(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true', - typeOptions: variableOptions, validationErrorEventProperty: '', variable: { ...defaultVariableState, ...this.selectedVariable }, }; @@ -259,6 +258,7 @@ export default { }, }, defaultScope: allEnvironments.text, + variableOptions, }; </script> @@ -277,6 +277,7 @@ export default { 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" /> @@ -293,21 +294,26 @@ export default { :state="variableValidationState" rows="3" max-rows="6" + data-testid="pipeline-form-ci-variable-value" data-qa-selector="ci_variable_value_field" class="gl-font-monospace!" /> </gl-form-group> - <div class="d-flex"> - <gl-form-group :label="__('Type')" label-for="ci-variable-type" class="w-50 gl-mr-5"> + <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="typeOptions" + :options="$options.variableOptions" /> </gl-form-group> - <gl-form-group label-for="ci-variable-env" class="w-50" data-testid="environment-scope"> + <gl-form-group + label-for="ci-variable-env" + class="gl-w-half" + data-testid="environment-scope" + > <template #label> {{ __('Environment scope') }} <gl-link @@ -380,7 +386,7 @@ export default { data-testid="aws-guidance-tip" @dismiss="dismissTip" > - <div class="gl-display-flex gl-flex-direction-row"> + <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"> diff --git a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue index cebb7eb85ac..1fbe52388c9 100644 --- a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue +++ b/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue @@ -255,6 +255,7 @@ export default { v-model="key" :token-list="$options.tokenList" :label-text="__('Key')" + data-testid="pipeline-form-ci-variable-key" data-qa-selector="ci_variable_key_field" /> @@ -271,6 +272,7 @@ export default { :state="variableValidationState" rows="3" max-rows="6" + data-testid="pipeline-form-ci-variable-value" data-qa-selector="ci_variable_value_field" class="gl-font-monospace!" /> diff --git a/app/assets/javascripts/ci_variable_list/constants.js b/app/assets/javascripts/ci_variable_list/constants.js index 5d22974ffbb..e2dd28cdaa1 100644 --- a/app/assets/javascripts/ci_variable_list/constants.js +++ b/app/assets/javascripts/ci_variable_list/constants.js @@ -10,7 +10,7 @@ export const displayText = { }; export const variableTypes = { - variableType: 'ENV_VAR', + envType: 'ENV_VAR', fileType: 'FILE', }; @@ -29,13 +29,13 @@ export const allEnvironments = { export const variableText = { [types.variableType]: __('Variable'), [types.fileType]: __('File'), - [variableTypes.variableType]: __('Variable'), + [variableTypes.envType]: __('Variable'), [variableTypes.fileType]: __('File'), }; export const variableOptions = [ - { value: types.variableType, text: variableText[types.variableType] }, - { value: types.fileType, text: variableText[types.fileType] }, + { value: variableTypes.envType, text: variableText[variableTypes.envType] }, + { value: variableTypes.fileType, text: variableText[variableTypes.fileType] }, ]; export const defaultVariableState = { @@ -44,7 +44,7 @@ export const defaultVariableState = { masked: false, protected: false, value: '', - variableType: types.variableType, + variableType: variableTypes.envType, }; // eslint-disable-next-line @gitlab/require-i18n-strings diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/client/add_project_environment.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/client/add_project_environment.mutation.graphql new file mode 100644 index 00000000000..45109762e80 --- /dev/null +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/client/add_project_environment.mutation.graphql @@ -0,0 +1,3 @@ +mutation addProjectEnvironment($environment: CiEnvironment, $fullPath: ID!) { + addProjectEnvironment(environment: $environment, fullPath: $fullPath) @client +} 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 new file mode 100644 index 00000000000..ab3a46da854 --- /dev/null +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql @@ -0,0 +1,30 @@ +#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql" + +mutation addProjectVariable( + $variable: CiVariable! + $endpoint: String! + $fullPath: ID! + $projectId: ID! +) { + addProjectVariable( + variable: $variable + endpoint: $endpoint + fullPath: $fullPath + projectId: $projectId + ) @client { + project { + id + ciVariables { + nodes { + ...BaseCiVariable + ... on CiProjectVariable { + environmentScope + masked + protected + } + } + } + } + errors + } +} 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 new file mode 100644 index 00000000000..e83dc9a5e5e --- /dev/null +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql @@ -0,0 +1,30 @@ +#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql" + +mutation deleteProjectVariable( + $variable: CiVariable! + $endpoint: String! + $fullPath: ID! + $projectId: ID! +) { + deleteProjectVariable( + variable: $variable + endpoint: $endpoint + fullPath: $fullPath + projectId: $projectId + ) @client { + project { + id + ciVariables { + nodes { + ...BaseCiVariable + ... on CiProjectVariable { + environmentScope + masked + protected + } + } + } + } + errors + } +} 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 new file mode 100644 index 00000000000..4788911431b --- /dev/null +++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql @@ -0,0 +1,30 @@ +#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql" + +mutation updateProjectVariable( + $variable: CiVariable! + $endpoint: String! + $fullPath: ID! + $projectId: ID! +) { + updateProjectVariable( + variable: $variable + endpoint: $endpoint + fullPath: $fullPath + projectId: $projectId + ) @client { + project { + id + ciVariables { + nodes { + ...BaseCiVariable + ... on CiProjectVariable { + environmentScope + masked + protected + } + } + } + } + errors + } +} diff --git a/app/assets/javascripts/ci_variable_list/graphql/queries/project_environments.query.graphql b/app/assets/javascripts/ci_variable_list/graphql/queries/project_environments.query.graphql new file mode 100644 index 00000000000..921e0ca25b9 --- /dev/null +++ b/app/assets/javascripts/ci_variable_list/graphql/queries/project_environments.query.graphql @@ -0,0 +1,11 @@ +query getProjectEnvironments($fullPath: ID!) { + project(fullPath: $fullPath) { + id + environments { + nodes { + id + name + } + } + } +} 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 new file mode 100644 index 00000000000..a60a50e4bc4 --- /dev/null +++ b/app/assets/javascripts/ci_variable_list/graphql/queries/project_variables.query.graphql @@ -0,0 +1,15 @@ +#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql" + +query getProjectVariables($fullPath: ID!) { + project(fullPath: $fullPath) { + id + ciVariables { + nodes { + ...BaseCiVariable + environmentScope + masked + protected + } + } + } +} diff --git a/app/assets/javascripts/ci_variable_list/graphql/resolvers.js b/app/assets/javascripts/ci_variable_list/graphql/resolvers.js index be7e3f88cfd..c041531ae30 100644 --- a/app/assets/javascripts/ci_variable_list/graphql/resolvers.js +++ b/app/assets/javascripts/ci_variable_list/graphql/resolvers.js @@ -4,9 +4,16 @@ import { convertObjectPropsToSnakeCase, } from '../../lib/utils/common_utils'; import { getIdFromGraphQLId } from '../../graphql_shared/utils'; -import { GRAPHQL_GROUP_TYPE, groupString, instanceString } from '../constants'; -import getAdminVariables from './queries/variables.query.graphql'; +import { + GRAPHQL_GROUP_TYPE, + GRAPHQL_PROJECT_TYPE, + groupString, + instanceString, + projectString, +} from '../constants'; +import getProjectVariables from './queries/project_variables.query.graphql'; import getGroupVariables from './queries/group_variables.query.graphql'; +import getAdminVariables from './queries/variables.query.graphql'; const prepareVariableForApi = ({ variable, destroy = false }) => { return { @@ -28,6 +35,20 @@ const mapVariableTypes = (variables = [], kind) => { }); }; +const prepareProjectGraphQLResponse = ({ data, projectId, errors = [] }) => { + return { + errors, + project: { + __typename: GRAPHQL_PROJECT_TYPE, + id: projectId, + ciVariables: { + __typename: 'CiVariableConnection', + nodes: mapVariableTypes(data.variables, projectString), + }, + }, + }; +}; + const prepareGroupGraphQLResponse = ({ data, groupId, errors = [] }) => { return { errors, @@ -52,6 +73,28 @@ const prepareAdminGraphQLResponse = ({ data, errors = [] }) => { }; }; +const callProjectEndpoint = async ({ + endpoint, + fullPath, + variable, + projectId, + cache, + destroy = false, +}) => { + try { + const { data } = await axios.patch(endpoint, { + variables_attributes: [prepareVariableForApi({ variable, destroy })], + }); + return prepareProjectGraphQLResponse({ data, projectId }); + } catch (e) { + return prepareProjectGraphQLResponse({ + data: cache.readQuery({ query: getProjectVariables, variables: { fullPath } }), + projectId, + errors: [...e.response.data], + }); + } +}; + const callGroupEndpoint = async ({ endpoint, fullPath, @@ -91,6 +134,15 @@ const callAdminEndpoint = async ({ endpoint, variable, cache, destroy = false }) export const resolvers = { Mutation: { + addProjectVariable: async (_, { endpoint, fullPath, variable, projectId }, { cache }) => { + return callProjectEndpoint({ endpoint, fullPath, variable, projectId, cache }); + }, + updateProjectVariable: async (_, { endpoint, fullPath, variable, projectId }, { cache }) => { + return callProjectEndpoint({ endpoint, fullPath, variable, projectId, cache }); + }, + deleteProjectVariable: async (_, { endpoint, fullPath, variable, projectId }, { cache }) => { + return callProjectEndpoint({ endpoint, fullPath, variable, projectId, cache, destroy: true }); + }, addGroupVariable: async (_, { endpoint, fullPath, variable, groupId }, { cache }) => { return callGroupEndpoint({ endpoint, fullPath, variable, groupId, cache }); }, diff --git a/app/assets/javascripts/ci_variable_list/index.js b/app/assets/javascripts/ci_variable_list/index.js index a74af8aed12..f5bdd4c7b1e 100644 --- a/app/assets/javascripts/ci_variable_list/index.js +++ b/app/assets/javascripts/ci_variable_list/index.js @@ -4,6 +4,7 @@ import createDefaultClient from '~/lib/graphql'; import { parseBoolean } from '~/lib/utils/common_utils'; import CiAdminVariables from './components/ci_admin_variables.vue'; import CiGroupVariables from './components/ci_group_variables.vue'; +import CiProjectVariables from './components/ci_project_variables.vue'; import LegacyCiVariableSettings from './components/legacy_ci_variable_settings.vue'; import { resolvers } from './graphql/resolvers'; import createStore from './store'; @@ -37,6 +38,8 @@ const mountCiVariableListApp = (containerEl) => { if (parsedIsGroup) { component = CiGroupVariables; + } else if (parsedIsProject) { + component = CiProjectVariables; } Vue.use(VueApollo); @@ -77,7 +80,7 @@ const mountLegacyCiVariableListApp = (containerEl) => { const { endpoint, projectId, - group, + isGroup, maskableRegex, protectedByDefault, awsLogoSvgPath, @@ -89,13 +92,13 @@ const mountLegacyCiVariableListApp = (containerEl) => { maskedEnvironmentVariablesLink, environmentScopeLink, } = containerEl.dataset; - const isGroup = parseBoolean(group); + const parsedIsGroup = parseBoolean(isGroup); const isProtectedByDefault = parseBoolean(protectedByDefault); const store = createStore({ endpoint, projectId, - isGroup, + isGroup: parsedIsGroup, maskableRegex, isProtectedByDefault, awsLogoSvgPath, |