diff options
Diffstat (limited to 'app/assets/javascripts/security_configuration/components/training_provider_list.vue')
-rw-r--r-- | app/assets/javascripts/security_configuration/components/training_provider_list.vue | 130 |
1 files changed, 101 insertions, 29 deletions
diff --git a/app/assets/javascripts/security_configuration/components/training_provider_list.vue b/app/assets/javascripts/security_configuration/components/training_provider_list.vue index 509377a63e8..ca4596e16b3 100644 --- a/app/assets/javascripts/security_configuration/components/training_provider_list.vue +++ b/app/assets/javascripts/security_configuration/components/training_provider_list.vue @@ -1,21 +1,39 @@ <script> -import { GlCard, GlToggle, GlLink, GlSkeletonLoader } from '@gitlab/ui'; +import { GlAlert, GlCard, GlToggle, GlLink, GlSkeletonLoader } from '@gitlab/ui'; +import { __ } from '~/locale'; import securityTrainingProvidersQuery from '../graphql/security_training_providers.query.graphql'; +import configureSecurityTrainingProvidersMutation from '../graphql/configure_security_training_providers.mutation.graphql'; + +const i18n = { + providerQueryErrorMessage: __( + 'Could not fetch training providers. Please refresh the page, or try again later.', + ), + configMutationErrorMessage: __( + 'Could not save configuration. Please refresh the page, or try again later.', + ), +}; export default { components: { + GlAlert, GlCard, GlToggle, GlLink, GlSkeletonLoader, }, + inject: ['projectPath'], apollo: { securityTrainingProviders: { query: securityTrainingProvidersQuery, + error() { + this.errorMessage = this.$options.i18n.providerQueryErrorMessage; + }, }, }, data() { return { + errorMessage: '', + toggleLoading: false, securityTrainingProviders: [], }; }, @@ -24,38 +42,92 @@ export default { return this.$apollo.queries.securityTrainingProviders.loading; }, }, + methods: { + toggleProvider(selectedProviderId) { + const toggledProviders = this.securityTrainingProviders.map((provider) => ({ + ...provider, + ...(provider.id === selectedProviderId && { isEnabled: !provider.isEnabled }), + })); + + const enabledProviderIds = toggledProviders + .filter(({ isEnabled }) => isEnabled) + .map(({ id }) => id); + + this.storeEnabledProviders(toggledProviders, enabledProviderIds); + }, + async storeEnabledProviders(toggledProviders, enabledProviderIds) { + this.toggleLoading = true; + + try { + const { + data: { + configureSecurityTrainingProviders: { errors = [] }, + }, + } = await this.$apollo.mutate({ + mutation: configureSecurityTrainingProvidersMutation, + variables: { + input: { + enabledProviders: enabledProviderIds, + fullPath: this.projectPath, + }, + }, + }); + + if (errors.length > 0) { + // throwing an error here means we can handle scenarios within the `catch` block below + throw new Error(); + } + } catch { + this.errorMessage = this.$options.i18n.configMutationErrorMessage; + } finally { + this.toggleLoading = false; + } + }, + }, + i18n, }; </script> <template> - <div - v-if="isLoading" - class="gl-bg-white gl-py-6 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100" - > - <gl-skeleton-loader :width="350" :height="44"> - <rect width="200" height="8" x="10" y="0" rx="4" /> - <rect width="300" height="8" x="10" y="15" rx="4" /> - <rect width="100" height="8" x="10" y="35" rx="4" /> - </gl-skeleton-loader> - </div> - <ul v-else class="gl-list-style-none gl-m-0 gl-p-0"> - <li - v-for="{ id, isEnabled, name, description, url } in securityTrainingProviders" - :key="id" - class="gl-mb-6" + <div> + <gl-alert v-if="errorMessage" variant="danger" :dismissible="false" class="gl-mb-6"> + {{ errorMessage }} + </gl-alert> + <div + v-if="isLoading" + class="gl-bg-white gl-py-6 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100" > - <gl-card> - <div class="gl-display-flex"> - <gl-toggle :value="isEnabled" :label="__('Training mode')" label-position="hidden" /> - <div class="gl-ml-5"> - <h3 class="gl-font-lg gl-m-0 gl-mb-2">{{ name }}</h3> - <p> - {{ description }} - <gl-link :href="url" target="_blank">{{ __('Learn more.') }}</gl-link> - </p> + <gl-skeleton-loader :width="350" :height="44"> + <rect width="200" height="8" x="10" y="0" rx="4" /> + <rect width="300" height="8" x="10" y="15" rx="4" /> + <rect width="100" height="8" x="10" y="35" rx="4" /> + </gl-skeleton-loader> + </div> + <ul v-else class="gl-list-style-none gl-m-0 gl-p-0"> + <li + v-for="{ id, isEnabled, name, description, url } in securityTrainingProviders" + :key="id" + class="gl-mb-6" + > + <gl-card> + <div class="gl-display-flex"> + <gl-toggle + :value="isEnabled" + :label="__('Training mode')" + label-position="hidden" + :is-loading="toggleLoading" + @change="toggleProvider(id)" + /> + <div class="gl-ml-5"> + <h3 class="gl-font-lg gl-m-0 gl-mb-2">{{ name }}</h3> + <p> + {{ description }} + <gl-link :href="url" target="_blank">{{ __('Learn more.') }}</gl-link> + </p> + </div> </div> - </div> - </gl-card> - </li> - </ul> + </gl-card> + </li> + </ul> + </div> </template> |