diff options
Diffstat (limited to 'app/assets/javascripts/packages_and_registries/settings/group')
8 files changed, 332 insertions, 1 deletions
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/bundle.js b/app/assets/javascripts/packages_and_registries/settings/group/bundle.js index a3d507180c6..5cd8261ac23 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/bundle.js +++ b/app/assets/javascripts/packages_and_registries/settings/group/bundle.js @@ -1,9 +1,13 @@ +import { GlToast } from '@gitlab/ui'; import Vue from 'vue'; + +import { parseBoolean } from '~/lib/utils/common_utils'; import Translate from '~/vue_shared/translate'; import SettingsApp from './components/group_settings_app.vue'; import { apolloProvider } from './graphql'; Vue.use(Translate); +Vue.use(GlToast); export default () => { const el = document.getElementById('js-packages-and-registries-settings'); @@ -13,6 +17,10 @@ export default () => { return new Vue({ el, apolloProvider, + provide: { + defaultExpanded: parseBoolean(el.dataset.defaultExpanded), + groupPath: el.dataset.groupPath, + }, render(createElement) { return createElement(SettingsApp); }, diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue index 6bcecf43a13..933cbeaedce 100644 --- a/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue +++ b/app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue @@ -1,9 +1,138 @@ <script> +import { GlSprintf, GlLink, GlAlert } from '@gitlab/ui'; +import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue'; + +import { + PACKAGE_SETTINGS_HEADER, + PACKAGE_SETTINGS_DESCRIPTION, + PACKAGES_DOCS_PATH, + ERROR_UPDATING_SETTINGS, + SUCCESS_UPDATING_SETTINGS, +} from '~/packages_and_registries/settings/group/constants'; +import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql'; +import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql'; +import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update'; +import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses'; +import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; + export default { name: 'GroupSettingsApp', + i18n: { + PACKAGE_SETTINGS_HEADER, + PACKAGE_SETTINGS_DESCRIPTION, + }, + links: { + PACKAGES_DOCS_PATH, + }, + components: { + GlAlert, + GlSprintf, + GlLink, + SettingsBlock, + MavenSettings, + }, + inject: ['defaultExpanded', 'groupPath'], + apollo: { + packageSettings: { + query: getGroupPackagesSettingsQuery, + variables() { + return { + fullPath: this.groupPath, + }; + }, + update(data) { + return data.group?.packageSettings; + }, + }, + }, + data() { + return { + packageSettings: {}, + errors: {}, + alertMessage: null, + }; + }, + computed: { + isLoading() { + return this.$apollo.queries.packageSettings.loading; + }, + }, + methods: { + dismissAlert() { + this.alertMessage = null; + }, + updateSettings(payload) { + this.errors = {}; + return this.$apollo + .mutate({ + mutation: updateNamespacePackageSettings, + variables: { + input: { + namespacePath: this.groupPath, + ...payload, + }, + }, + update: updateGroupPackageSettings(this.groupPath), + optimisticResponse: updateGroupPackagesSettingsOptimisticResponse({ + ...this.packageSettings, + ...payload, + }), + }) + .then(({ data }) => { + if (data.updateNamespacePackageSettings?.errors?.length > 0) { + this.alertMessage = ERROR_UPDATING_SETTINGS; + } else { + this.dismissAlert(); + this.$toast.show(SUCCESS_UPDATING_SETTINGS, { type: 'success' }); + } + }) + .catch((e) => { + if (e.graphQLErrors) { + e.graphQLErrors.forEach((error) => { + const [ + { + path: [key], + message, + }, + ] = error.extensions.problems; + this.errors = { ...this.errors, [key]: message }; + }); + } + this.alertMessage = ERROR_UPDATING_SETTINGS; + }); + }, + }, }; </script> <template> - <section></section> + <div> + <gl-alert v-if="alertMessage" variant="warning" class="gl-mt-4" @dismiss="dismissAlert"> + {{ alertMessage }} + </gl-alert> + + <settings-block :default-expanded="defaultExpanded"> + <template #title> {{ $options.i18n.PACKAGE_SETTINGS_HEADER }}</template> + <template #description> + <span data-testid="description"> + <gl-sprintf :message="$options.i18n.PACKAGE_SETTINGS_DESCRIPTION"> + <template #link="{ content }"> + <gl-link :href="$options.links.PACKAGES_DOCS_PATH" target="_blank">{{ + content + }}</gl-link> + </template> + </gl-sprintf> + </span> + </template> + <template #default> + <maven-settings + :maven-duplicates-allowed="packageSettings.mavenDuplicatesAllowed" + :maven-duplicate-exception-regex="packageSettings.mavenDuplicateExceptionRegex" + :maven-duplicate-exception-regex-error="errors.mavenDuplicateExceptionRegex" + :loading="isLoading" + @update="updateSettings" + /> + </template> + </settings-block> + </div> </template> diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/maven_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/maven_settings.vue new file mode 100644 index 00000000000..aa7c6e9d8d6 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/group/components/maven_settings.vue @@ -0,0 +1,113 @@ +<script> +import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui'; + +import { + MAVEN_TITLE, + MAVEN_SETTINGS_SUBTITLE, + MAVEN_DUPLICATES_ALLOWED_DISABLED, + MAVEN_DUPLICATES_ALLOWED_ENABLED, + MAVEN_SETTING_EXCEPTION_TITLE, + MAVEN_SETTINGS_EXCEPTION_LEGEND, + MAVEN_DUPLICATES_ALLOWED, + MAVEN_DUPLICATE_EXCEPTION_REGEX, +} from '~/packages_and_registries/settings/group/constants'; + +export default { + name: 'MavenSettings', + i18n: { + MAVEN_TITLE, + MAVEN_SETTINGS_SUBTITLE, + MAVEN_SETTING_EXCEPTION_TITLE, + MAVEN_SETTINGS_EXCEPTION_LEGEND, + }, + modelNames: { + MAVEN_DUPLICATES_ALLOWED, + MAVEN_DUPLICATE_EXCEPTION_REGEX, + }, + components: { + GlSprintf, + GlToggle, + GlFormGroup, + GlFormInput, + }, + props: { + loading: { + type: Boolean, + required: false, + default: false, + }, + mavenDuplicatesAllowed: { + type: Boolean, + default: false, + required: true, + }, + mavenDuplicateExceptionRegex: { + type: String, + default: '', + required: true, + }, + mavenDuplicateExceptionRegexError: { + type: String, + default: '', + required: false, + }, + }, + computed: { + enabledButtonLabel() { + return this.mavenDuplicatesAllowed + ? MAVEN_DUPLICATES_ALLOWED_ENABLED + : MAVEN_DUPLICATES_ALLOWED_DISABLED; + }, + isMavenDuplicateExceptionRegexValid() { + return !this.mavenDuplicateExceptionRegexError; + }, + }, + methods: { + update(type, value) { + this.$emit('update', { [type]: value }); + }, + }, +}; +</script> + +<template> + <div> + <h5 class="gl-border-b-solid gl-border-b-1 gl-border-gray-200"> + {{ $options.i18n.MAVEN_TITLE }} + </h5> + <p>{{ $options.i18n.MAVEN_SETTINGS_SUBTITLE }}</p> + <form> + <div class="gl-display-flex"> + <gl-toggle + :value="mavenDuplicatesAllowed" + @change="update($options.modelNames.MAVEN_DUPLICATES_ALLOWED, $event)" + /> + <div class="gl-ml-5"> + <div data-testid="toggle-label"> + <gl-sprintf :message="enabledButtonLabel"> + <template #bold="{ content }"> + <strong>{{ content }}</strong> + </template> + </gl-sprintf> + </div> + <gl-form-group + v-if="!mavenDuplicatesAllowed" + class="gl-mt-4" + :label="$options.i18n.MAVEN_SETTING_EXCEPTION_TITLE" + label-size="sm" + :state="isMavenDuplicateExceptionRegexValid" + :invalid-feedback="mavenDuplicateExceptionRegexError" + :description="$options.i18n.MAVEN_SETTINGS_EXCEPTION_LEGEND" + label-for="maven-duplicated-settings-regex-input" + > + <gl-form-input + id="maven-duplicated-settings-regex-input" + :value="mavenDuplicateExceptionRegex" + @change="update($options.modelNames.MAVEN_DUPLICATE_EXCEPTION_REGEX, $event)" + /> + </gl-form-group> + </div> + </div> + </form> + </div> +</template> diff --git a/app/assets/javascripts/packages_and_registries/settings/group/constants.js b/app/assets/javascripts/packages_and_registries/settings/group/constants.js new file mode 100644 index 00000000000..72bec74060c --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/group/constants.js @@ -0,0 +1,31 @@ +import { helpPagePath } from '~/helpers/help_page_helper'; +import { s__, __ } from '~/locale'; + +export const PACKAGE_SETTINGS_HEADER = s__('PackageRegistry|Package Registry'); +export const PACKAGE_SETTINGS_DESCRIPTION = s__( + 'PackageRegistry|GitLab Packages allows organizations to utilize GitLab as a private repository for a variety of common package formats. %{linkStart}More Information%{linkEnd}', +); + +export const MAVEN_TITLE = s__('PackageRegistry|Maven'); +export const MAVEN_SETTINGS_SUBTITLE = s__('PackageRegistry|Settings for Maven packages'); +export const MAVEN_DUPLICATES_ALLOWED_DISABLED = s__( + 'PackageRegistry|%{boldStart}Do not allow duplicates%{boldEnd} - Packages with the same name and version are rejected.', +); +export const MAVEN_DUPLICATES_ALLOWED_ENABLED = s__( + 'PackageRegistry|%{boldStart}Allow duplicates%{boldEnd} - Packages with the same name and version are accepted.', +); +export const MAVEN_SETTING_EXCEPTION_TITLE = __('Exceptions'); +export const MAVEN_SETTINGS_EXCEPTION_LEGEND = s__( + 'PackageRegistry|Packages can be published if their name or version matches this regex', +); + +export const SUCCESS_UPDATING_SETTINGS = s__('PackageRegistry|Settings saved successfully'); +export const ERROR_UPDATING_SETTINGS = s__( + 'PackageRegistry|An error occurred while saving the settings', +); + +// Parameters + +export const PACKAGES_DOCS_PATH = helpPagePath('user/packages'); +export const MAVEN_DUPLICATES_ALLOWED = 'mavenDuplicatesAllowed'; +export const MAVEN_DUPLICATE_EXCEPTION_REGEX = 'mavenDuplicateExceptionRegex'; diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql b/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql new file mode 100644 index 00000000000..1fc59bd3496 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql @@ -0,0 +1,9 @@ +mutation updateNamespacePackageSettings($input: UpdateNamespacePackageSettingsInput!) { + updateNamespacePackageSettings(input: $input) { + packageSettings { + mavenDuplicatesAllowed + mavenDuplicateExceptionRegex + } + errors + } +} diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql b/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql new file mode 100644 index 00000000000..2011659887d --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql @@ -0,0 +1,8 @@ +query getGroupPackagesSettings($fullPath: ID!) { + group(fullPath: $fullPath) { + packageSettings { + mavenDuplicatesAllowed + mavenDuplicateExceptionRegex + } + } +} diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/utils/cache_update.js b/app/assets/javascripts/packages_and_registries/settings/group/graphql/utils/cache_update.js new file mode 100644 index 00000000000..06b57fe013f --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/utils/cache_update.js @@ -0,0 +1,22 @@ +import { produce } from 'immer'; +import getGroupPackagesSettingsQuery from '../queries/get_group_packages_settings.query.graphql'; + +export const updateGroupPackageSettings = (fullPath) => (client, { data: updatedData }) => { + const queryAndParams = { + query: getGroupPackagesSettingsQuery, + variables: { fullPath }, + }; + const sourceData = client.readQuery(queryAndParams); + + const data = produce(sourceData, (draftState) => { + // eslint-disable-next-line no-param-reassign + draftState.group.packageSettings = { + ...updatedData.updateNamespacePackageSettings.packageSettings, + }; + }); + + client.writeQuery({ + ...queryAndParams, + data, + }); +}; diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/utils/optimistic_responses.js b/app/assets/javascripts/packages_and_registries/settings/group/graphql/utils/optimistic_responses.js new file mode 100644 index 00000000000..f2c8de85bf8 --- /dev/null +++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/utils/optimistic_responses.js @@ -0,0 +1,11 @@ +export const updateGroupPackagesSettingsOptimisticResponse = (changes) => ({ + // eslint-disable-next-line @gitlab/require-i18n-strings + __typename: 'Mutation', + updateNamespacePackageSettings: { + __typename: 'UpdateNamespacePackageSettingsPayload', + errors: [], + packageSettings: { + ...changes, + }, + }, +}); |