Commit 66e78450 authored by David Pisek's avatar David Pisek Committed by Savas Vedova

Make sec training provider mutation optimistic

This commit adds an optimistic response to the mutation that
updates the provider setting for a security training provider.

This helps makes the UI respond more quickly to the user.
parent 174311a0
...@@ -10,6 +10,7 @@ import { ...@@ -10,6 +10,7 @@ import {
TRACK_PROVIDER_LEARN_MORE_CLICK_LABEL, TRACK_PROVIDER_LEARN_MORE_CLICK_LABEL,
} from '~/security_configuration/constants'; } from '~/security_configuration/constants';
import dismissUserCalloutMutation from '~/graphql_shared/mutations/dismiss_user_callout.mutation.graphql'; import dismissUserCalloutMutation from '~/graphql_shared/mutations/dismiss_user_callout.mutation.graphql';
import { updateSecurityTrainingOptimisticResponse } from '~/security_configuration/graphql/utils/optimistic_response';
import securityTrainingProvidersQuery from '../graphql/security_training_providers.query.graphql'; import securityTrainingProvidersQuery from '../graphql/security_training_providers.query.graphql';
import configureSecurityTrainingProvidersMutation from '../graphql/configure_security_training_providers.mutation.graphql'; import configureSecurityTrainingProvidersMutation from '../graphql/configure_security_training_providers.mutation.graphql';
...@@ -51,7 +52,6 @@ export default { ...@@ -51,7 +52,6 @@ export default {
data() { data() {
return { return {
errorMessage: '', errorMessage: '',
providerLoadingId: null,
securityTrainingProviders: [], securityTrainingProviders: [],
hasTouchedConfiguration: false, hasTouchedConfiguration: false,
}; };
...@@ -99,8 +99,6 @@ export default { ...@@ -99,8 +99,6 @@ export default {
this.storeProvider({ ...provider, isEnabled: toggledIsEnabled }); this.storeProvider({ ...provider, isEnabled: toggledIsEnabled });
}, },
async storeProvider({ id, isEnabled, isPrimary }) { async storeProvider({ id, isEnabled, isPrimary }) {
this.providerLoadingId = id;
try { try {
const { const {
data: { data: {
...@@ -116,6 +114,11 @@ export default { ...@@ -116,6 +114,11 @@ export default {
isPrimary, isPrimary,
}, },
}, },
optimisticResponse: updateSecurityTrainingOptimisticResponse({
id,
isEnabled,
isPrimary,
}),
}); });
if (errors.length > 0) { if (errors.length > 0) {
...@@ -126,8 +129,6 @@ export default { ...@@ -126,8 +129,6 @@ export default {
this.hasTouchedConfiguration = true; this.hasTouchedConfiguration = true;
} catch { } catch {
this.errorMessage = this.$options.i18n.configMutationErrorMessage; this.errorMessage = this.$options.i18n.configMutationErrorMessage;
} finally {
this.providerLoadingId = null;
} }
}, },
trackProviderToggle(providerId, providerIsEnabled) { trackProviderToggle(providerId, providerIsEnabled) {
...@@ -173,7 +174,6 @@ export default { ...@@ -173,7 +174,6 @@ export default {
:value="provider.isEnabled" :value="provider.isEnabled"
:label="__('Training mode')" :label="__('Training mode')"
label-position="hidden" label-position="hidden"
:is-loading="providerLoadingId === provider.id"
@change="toggleProvider(provider)" @change="toggleProvider(provider)"
/> />
<div class="gl-ml-5"> <div class="gl-ml-5">
......
export const updateSecurityTrainingOptimisticResponse = (changes) => ({
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Mutation',
securityTrainingUpdate: {
__typename: 'SecurityTrainingUpdatePayload',
training: {
__typename: 'ProjectSecurityTraining',
...changes,
},
errors: [],
},
});
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
TRACK_PROVIDER_LEARN_MORE_CLICK_LABEL, TRACK_PROVIDER_LEARN_MORE_CLICK_LABEL,
} from '~/security_configuration/constants'; } from '~/security_configuration/constants';
import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue'; import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue';
import { updateSecurityTrainingOptimisticResponse } from '~/security_configuration/graphql/utils/optimistic_response';
import securityTrainingProvidersQuery from '~/security_configuration/graphql/security_training_providers.query.graphql'; import securityTrainingProvidersQuery from '~/security_configuration/graphql/security_training_providers.query.graphql';
import configureSecurityTrainingProvidersMutation from '~/security_configuration/graphql/configure_security_training_providers.mutation.graphql'; import configureSecurityTrainingProvidersMutation from '~/security_configuration/graphql/configure_security_training_providers.mutation.graphql';
import dismissUserCalloutMutation from '~/graphql_shared/mutations/dismiss_user_callout.mutation.graphql'; import dismissUserCalloutMutation from '~/graphql_shared/mutations/dismiss_user_callout.mutation.graphql';
...@@ -159,17 +160,6 @@ describe('TrainingProviderList component', () => { ...@@ -159,17 +160,6 @@ describe('TrainingProviderList component', () => {
await toggleFirstProvider(); await toggleFirstProvider();
}); });
it.each`
loading | wait | desc
${true} | ${false} | ${'enables loading of GlToggle when mutation is called'}
${false} | ${true} | ${'disables loading of GlToggle when mutation is complete'}
`('$desc', async ({ loading, wait }) => {
if (wait) {
await waitForMutationToBeLoaded();
}
expect(findFirstToggle().props('isLoading')).toBe(loading);
});
it('calls mutation when toggle is changed', () => { it('calls mutation when toggle is changed', () => {
expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith( expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
...@@ -186,6 +176,20 @@ describe('TrainingProviderList component', () => { ...@@ -186,6 +176,20 @@ describe('TrainingProviderList component', () => {
); );
}); });
it('returns an optimistic response when calling the mutation', () => {
const optimisticResponse = updateSecurityTrainingOptimisticResponse({
id: securityTrainingProviders[0].id,
isEnabled: true,
isPrimary: false,
});
expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith(
expect.objectContaining({
optimisticResponse,
}),
);
});
it('dismisses the callout when the feature gets first enabled', async () => { it('dismisses the callout when the feature gets first enabled', async () => {
// wait for configuration update mutation to complete // wait for configuration update mutation to complete
await waitForMutationToBeLoaded(); await waitForMutationToBeLoaded();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment