Commit 7b78b65b authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '270470-no-query-new-snippet' into 'master'

Do not attempt to fetch snippet information on the new snippet's creation

See merge request gitlab-org/gitlab!46355
parents 47e87030 8f94bce0
...@@ -16,12 +16,7 @@ import { performanceMarkAndMeasure } from '~/performance_utils'; ...@@ -16,12 +16,7 @@ import { performanceMarkAndMeasure } from '~/performance_utils';
import UpdateSnippetMutation from '../mutations/updateSnippet.mutation.graphql'; import UpdateSnippetMutation from '../mutations/updateSnippet.mutation.graphql';
import CreateSnippetMutation from '../mutations/createSnippet.mutation.graphql'; import CreateSnippetMutation from '../mutations/createSnippet.mutation.graphql';
import { getSnippetMixin } from '../mixins/snippets'; import { getSnippetMixin } from '../mixins/snippets';
import { import { SNIPPET_CREATE_MUTATION_ERROR, SNIPPET_UPDATE_MUTATION_ERROR } from '../constants';
SNIPPET_CREATE_MUTATION_ERROR,
SNIPPET_UPDATE_MUTATION_ERROR,
SNIPPET_VISIBILITY_PRIVATE,
} from '../constants';
import defaultVisibilityQuery from '../queries/snippet_visibility.query.graphql';
import { markBlobPerformance } from '../utils/blob'; import { markBlobPerformance } from '../utils/blob';
import SnippetBlobActionsEdit from './snippet_blob_actions_edit.vue'; import SnippetBlobActionsEdit from './snippet_blob_actions_edit.vue';
...@@ -41,15 +36,7 @@ export default { ...@@ -41,15 +36,7 @@ export default {
GlLoadingIcon, GlLoadingIcon,
}, },
mixins: [getSnippetMixin], mixins: [getSnippetMixin],
apollo: { inject: ['selectedLevel'],
defaultVisibility: {
query: defaultVisibilityQuery,
manual: true,
result({ data: { selectedLevel } }) {
this.selectedLevelDefault = selectedLevel;
},
},
},
props: { props: {
markdownPreviewPath: { markdownPreviewPath: {
type: String, type: String,
...@@ -73,9 +60,12 @@ export default { ...@@ -73,9 +60,12 @@ export default {
data() { data() {
return { return {
isUpdating: false, isUpdating: false,
newSnippet: false,
actions: [], actions: [],
selectedLevelDefault: SNIPPET_VISIBILITY_PRIVATE, snippet: {
title: '',
description: '',
visibilityLevel: this.selectedLevel,
},
}; };
}, },
computed: { computed: {
...@@ -112,13 +102,6 @@ export default { ...@@ -112,13 +102,6 @@ export default {
} }
return this.snippet.webUrl; return this.snippet.webUrl;
}, },
newSnippetSchema() {
return {
title: '',
description: '',
visibilityLevel: this.selectedLevelDefault,
};
},
}, },
beforeCreate() { beforeCreate() {
performanceMarkAndMeasure({ mark: SNIPPET_MARK_EDIT_APP_START }); performanceMarkAndMeasure({ mark: SNIPPET_MARK_EDIT_APP_START });
...@@ -145,20 +128,6 @@ export default { ...@@ -145,20 +128,6 @@ export default {
Flash(sprintf(defaultErrorMsg, { err })); Flash(sprintf(defaultErrorMsg, { err }));
this.isUpdating = false; this.isUpdating = false;
}, },
onNewSnippetFetched() {
this.newSnippet = true;
this.snippet = this.newSnippetSchema;
},
onExistingSnippetFetched() {
this.newSnippet = false;
},
onSnippetFetch(snippetRes) {
if (snippetRes.data.snippets.nodes.length === 0) {
this.onNewSnippetFetched();
} else {
this.onExistingSnippetFetched();
}
},
getAttachedFiles() { getAttachedFiles() {
const fileInputs = Array.from(this.$el.querySelectorAll('[name="files[]"]')); const fileInputs = Array.from(this.$el.querySelectorAll('[name="files[]"]'));
return fileInputs.map(node => node.value); return fileInputs.map(node => node.value);
...@@ -209,7 +178,7 @@ export default { ...@@ -209,7 +178,7 @@ export default {
</script> </script>
<template> <template>
<form <form
class="snippet-form js-requires-input js-quick-submit common-note-form" class="snippet-form js-quick-submit common-note-form"
:data-snippet-type="isProjectSnippet ? 'project' : 'personal'" :data-snippet-type="isProjectSnippet ? 'project' : 'personal'"
data-testid="snippet-edit-form" data-testid="snippet-edit-form"
@submit.prevent="handleFormSubmit" @submit.prevent="handleFormSubmit"
......
<script> <script>
import { GlIcon, GlFormGroup, GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui'; import { GlIcon, GlFormGroup, GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui';
import defaultVisibilityQuery from '../queries/snippet_visibility.query.graphql';
import { defaultSnippetVisibilityLevels } from '../utils/blob'; import { defaultSnippetVisibilityLevels } from '../utils/blob';
import { SNIPPET_LEVELS_RESTRICTED, SNIPPET_LEVELS_DISABLED } from '~/snippets/constants'; import { SNIPPET_LEVELS_RESTRICTED, SNIPPET_LEVELS_DISABLED } from '~/snippets/constants';
...@@ -12,16 +11,7 @@ export default { ...@@ -12,16 +11,7 @@ export default {
GlFormRadioGroup, GlFormRadioGroup,
GlLink, GlLink,
}, },
apollo: { inject: ['visibilityLevels', 'multipleLevelsRestricted'],
defaultVisibility: {
query: defaultVisibilityQuery,
manual: true,
result({ data: { visibilityLevels, multipleLevelsRestricted } }) {
this.visibilityLevels = defaultSnippetVisibilityLevels(visibilityLevels);
this.multipleLevelsRestricted = multipleLevelsRestricted;
},
},
},
props: { props: {
helpLink: { helpLink: {
type: String, type: String,
...@@ -38,11 +28,10 @@ export default { ...@@ -38,11 +28,10 @@ export default {
required: true, required: true,
}, },
}, },
data() { computed: {
return { defaultVisibilityLevels() {
visibilityLevels: [], return defaultSnippetVisibilityLevels(this.visibilityLevels);
multipleLevelsRestricted: false, },
};
}, },
SNIPPET_LEVELS_DISABLED, SNIPPET_LEVELS_DISABLED,
SNIPPET_LEVELS_RESTRICTED, SNIPPET_LEVELS_RESTRICTED,
...@@ -59,7 +48,7 @@ export default { ...@@ -59,7 +48,7 @@ export default {
<gl-form-group id="visibility-level-setting" class="gl-mb-0"> <gl-form-group id="visibility-level-setting" class="gl-mb-0">
<gl-form-radio-group :checked="value" stacked v-bind="$attrs" v-on="$listeners"> <gl-form-radio-group :checked="value" stacked v-bind="$attrs" v-on="$listeners">
<gl-form-radio <gl-form-radio
v-for="option in visibilityLevels" v-for="option in defaultVisibilityLevels"
:key="option.value" :key="option.value"
:value="option.value" :value="option.value"
class="mb-3" class="mb-3"
...@@ -78,7 +67,9 @@ export default { ...@@ -78,7 +67,9 @@ export default {
</gl-form-group> </gl-form-group>
<div class="text-muted" data-testid="restricted-levels-info"> <div class="text-muted" data-testid="restricted-levels-info">
<template v-if="!visibilityLevels.length">{{ $options.SNIPPET_LEVELS_DISABLED }}</template> <template v-if="!defaultVisibilityLevels.length">{{
$options.SNIPPET_LEVELS_DISABLED
}}</template>
<template v-else-if="multipleLevelsRestricted">{{ <template v-else-if="multipleLevelsRestricted">{{
$options.SNIPPET_LEVELS_RESTRICTED $options.SNIPPET_LEVELS_RESTRICTED
}}</template> }}</template>
......
...@@ -24,17 +24,14 @@ export default function appFactory(el, Component) { ...@@ -24,17 +24,14 @@ export default function appFactory(el, Component) {
...restDataset ...restDataset
} = el.dataset; } = el.dataset;
apolloProvider.clients.defaultClient.cache.writeData({ return new Vue({
data: { el,
apolloProvider,
provide: {
visibilityLevels: JSON.parse(visibilityLevels), visibilityLevels: JSON.parse(visibilityLevels),
selectedLevel: SNIPPET_LEVELS_MAP[selectedLevel] ?? SNIPPET_VISIBILITY_PRIVATE, selectedLevel: SNIPPET_LEVELS_MAP[selectedLevel] ?? SNIPPET_VISIBILITY_PRIVATE,
multipleLevelsRestricted: 'multipleLevelsRestricted' in el.dataset, multipleLevelsRestricted: 'multipleLevelsRestricted' in el.dataset,
}, },
});
return new Vue({
el,
apolloProvider,
render(createElement) { render(createElement) {
return createElement(Component, { return createElement(Component, {
props: { props: {
......
...@@ -21,9 +21,9 @@ export const getSnippetMixin = { ...@@ -21,9 +21,9 @@ export const getSnippetMixin = {
}, },
result(res) { result(res) {
this.blobs = res.data.snippets.nodes[0]?.blobs || blobsDefault; this.blobs = res.data.snippets.nodes[0]?.blobs || blobsDefault;
if (this.onSnippetFetch) { },
this.onSnippetFetch(res); skip() {
} return this.newSnippet;
}, },
}, },
}, },
...@@ -36,7 +36,7 @@ export const getSnippetMixin = { ...@@ -36,7 +36,7 @@ export const getSnippetMixin = {
data() { data() {
return { return {
snippet: {}, snippet: {},
newSnippet: false, newSnippet: !this.snippetGid,
blobs: blobsDefault, blobs: blobsDefault,
}; };
}, },
......
query defaultSnippetVisibility {
visibilityLevels @client
selectedLevel @client
multipleLevelsRestricted @client
}
---
title: Do not query snippet infromation on the new snippet's creation
merge_request: 46355
author:
type: fixed
...@@ -2,14 +2,14 @@ import { InMemoryCache } from 'apollo-cache-inmemory'; ...@@ -2,14 +2,14 @@ import { InMemoryCache } from 'apollo-cache-inmemory';
import { createMockClient } from 'mock-apollo-client'; import { createMockClient } from 'mock-apollo-client';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
export default (handlers = []) => { export default (handlers = [], resolvers = {}) => {
const fragmentMatcher = { match: () => true }; const fragmentMatcher = { match: () => true };
const cache = new InMemoryCache({ const cache = new InMemoryCache({
fragmentMatcher, fragmentMatcher,
addTypename: false, addTypename: false,
}); });
const mockClient = createMockClient({ cache }); const mockClient = createMockClient({ cache, resolvers });
if (Array.isArray(handlers)) { if (Array.isArray(handlers)) {
handlers.forEach(([query, value]) => mockClient.setRequestHandler(query, value)); handlers.forEach(([query, value]) => mockClient.setRequestHandler(query, value));
......
import { ApolloMutation } from 'vue-apollo'; import VueApollo, { ApolloMutation } from 'vue-apollo';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'jest/helpers/mock_apollo_helper';
import GetSnippetQuery from 'shared_queries/snippet/snippet.query.graphql';
import { deprecatedCreateFlash as Flash } from '~/flash'; import { deprecatedCreateFlash as Flash } from '~/flash';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import SnippetEditApp from '~/snippets/components/edit.vue'; import SnippetEditApp from '~/snippets/components/edit.vue';
...@@ -10,7 +12,11 @@ import SnippetVisibilityEdit from '~/snippets/components/snippet_visibility_edit ...@@ -10,7 +12,11 @@ import SnippetVisibilityEdit from '~/snippets/components/snippet_visibility_edit
import SnippetBlobActionsEdit from '~/snippets/components/snippet_blob_actions_edit.vue'; import SnippetBlobActionsEdit from '~/snippets/components/snippet_blob_actions_edit.vue';
import TitleField from '~/vue_shared/components/form/title.vue'; import TitleField from '~/vue_shared/components/form/title.vue';
import FormFooterActions from '~/vue_shared/components/form/form_footer_actions.vue'; import FormFooterActions from '~/vue_shared/components/form/form_footer_actions.vue';
import { SNIPPET_VISIBILITY_PRIVATE } from '~/snippets/constants'; import {
SNIPPET_VISIBILITY_PRIVATE,
SNIPPET_VISIBILITY_INTERNAL,
SNIPPET_VISIBILITY_PUBLIC,
} from '~/snippets/constants';
import UpdateSnippetMutation from '~/snippets/mutations/updateSnippet.mutation.graphql'; import UpdateSnippetMutation from '~/snippets/mutations/updateSnippet.mutation.graphql';
import CreateSnippetMutation from '~/snippets/mutations/createSnippet.mutation.graphql'; import CreateSnippetMutation from '~/snippets/mutations/createSnippet.mutation.graphql';
import { testEntries } from '../test_utils'; import { testEntries } from '../test_utils';
...@@ -47,8 +53,12 @@ const createTestSnippet = () => ({ ...@@ -47,8 +53,12 @@ const createTestSnippet = () => ({
describe('Snippet Edit app', () => { describe('Snippet Edit app', () => {
let wrapper; let wrapper;
let fakeApollo;
const relativeUrlRoot = '/foo/'; const relativeUrlRoot = '/foo/';
const originalRelativeUrlRoot = gon.relative_url_root; const originalRelativeUrlRoot = gon.relative_url_root;
const GetSnippetQuerySpy = jest.fn().mockResolvedValue({
data: { snippets: { nodes: [createTestSnippet()] } },
});
const mutationTypes = { const mutationTypes = {
RESOLVE: jest.fn().mockResolvedValue({ RESOLVE: jest.fn().mockResolvedValue({
...@@ -78,12 +88,10 @@ describe('Snippet Edit app', () => { ...@@ -78,12 +88,10 @@ describe('Snippet Edit app', () => {
props = {}, props = {},
loading = false, loading = false,
mutationRes = mutationTypes.RESOLVE, mutationRes = mutationTypes.RESOLVE,
selectedLevel = SNIPPET_VISIBILITY_PRIVATE,
withApollo = false,
} = {}) { } = {}) {
if (wrapper) { let componentData = {
throw new Error('wrapper already exists');
}
wrapper = shallowMount(SnippetEditApp, {
mocks: { mocks: {
$apollo: { $apollo: {
queries: { queries: {
...@@ -92,23 +100,35 @@ describe('Snippet Edit app', () => { ...@@ -92,23 +100,35 @@ describe('Snippet Edit app', () => {
mutate: mutationRes, mutate: mutationRes,
}, },
}, },
};
if (withApollo) {
const localVue = createLocalVue();
localVue.use(VueApollo);
const requestHandlers = [[GetSnippetQuery, GetSnippetQuerySpy]];
fakeApollo = createMockApollo(requestHandlers);
componentData = {
localVue,
apolloProvider: fakeApollo,
};
}
wrapper = shallowMount(SnippetEditApp, {
...componentData,
stubs: { stubs: {
ApolloMutation, ApolloMutation,
FormFooterActions, FormFooterActions,
}, },
provide: {
selectedLevel,
},
propsData: { propsData: {
snippetGid: 'gid://gitlab/PersonalSnippet/42', snippetGid: 'gid://gitlab/PersonalSnippet/42',
markdownPreviewPath: 'http://preview.foo.bar', markdownPreviewPath: 'http://preview.foo.bar',
markdownDocsPath: 'http://docs.foo.bar', markdownDocsPath: 'http://docs.foo.bar',
...props, ...props,
}, },
data() {
return {
snippet: {
visibilityLevel: SNIPPET_VISIBILITY_PRIVATE,
},
};
},
}); });
} }
...@@ -152,16 +172,13 @@ describe('Snippet Edit app', () => { ...@@ -152,16 +172,13 @@ describe('Snippet Edit app', () => {
if (nodes.length) { if (nodes.length) {
wrapper.setData({ wrapper.setData({
snippet: nodes[0], snippet: nodes[0],
newSnippet: false,
});
} else {
wrapper.setData({
newSnippet: true,
}); });
} }
wrapper.vm.onSnippetFetch({
data: {
snippets: {
nodes,
},
},
});
}; };
describe('rendering', () => { describe('rendering', () => {
...@@ -228,6 +245,28 @@ describe('Snippet Edit app', () => { ...@@ -228,6 +245,28 @@ describe('Snippet Edit app', () => {
}); });
describe('functionality', () => { describe('functionality', () => {
it('does not fetch snippet when create a new snippet', async () => {
createComponent({ props: { snippetGid: '' }, withApollo: true });
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
expect(GetSnippetQuerySpy).not.toHaveBeenCalled();
});
describe('default visibility', () => {
it.each([SNIPPET_VISIBILITY_PRIVATE, SNIPPET_VISIBILITY_INTERNAL, SNIPPET_VISIBILITY_PUBLIC])(
'marks %s visibility by default',
async visibility => {
createComponent({
props: { snippetGid: '' },
selectedLevel: visibility,
});
expect(wrapper.vm.snippet.visibilityLevel).toEqual(visibility);
},
);
});
describe('form submission handling', () => { describe('form submission handling', () => {
it.each` it.each`
snippetArg | projectPath | uploadedFiles | input | mutation snippetArg | projectPath | uploadedFiles | input | mutation
......
import { GlFormRadio, GlIcon, GlFormRadioGroup, GlLink } from '@gitlab/ui'; import { GlFormRadio, GlIcon, GlFormRadioGroup, GlLink } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import SnippetVisibilityEdit from '~/snippets/components/snippet_visibility_edit.vue'; import SnippetVisibilityEdit from '~/snippets/components/snippet_visibility_edit.vue';
import { defaultSnippetVisibilityLevels } from '~/snippets/utils/blob';
import { import {
SNIPPET_VISIBILITY, SNIPPET_VISIBILITY,
SNIPPET_VISIBILITY_PRIVATE, SNIPPET_VISIBILITY_PRIVATE,
...@@ -15,36 +14,25 @@ describe('Snippet Visibility Edit component', () => { ...@@ -15,36 +14,25 @@ describe('Snippet Visibility Edit component', () => {
let wrapper; let wrapper;
const defaultHelpLink = '/foo/bar'; const defaultHelpLink = '/foo/bar';
const defaultVisibilityLevel = 'private'; const defaultVisibilityLevel = 'private';
const defaultVisibility = defaultSnippetVisibilityLevels([0, 10, 20]);
function createComponent({ function createComponent({
propsData = {}, propsData = {},
visibilityLevels = defaultVisibility, visibilityLevels = [0, 10, 20],
multipleLevelsRestricted = false, multipleLevelsRestricted = false,
deep = false, deep = false,
} = {}) { } = {}) {
const method = deep ? mount : shallowMount; const method = deep ? mount : shallowMount;
const $apollo = {
queries: {
defaultVisibility: {
loading: false,
},
},
};
wrapper = method.call(this, SnippetVisibilityEdit, { wrapper = method.call(this, SnippetVisibilityEdit, {
mock: { $apollo },
propsData: { propsData: {
helpLink: defaultHelpLink, helpLink: defaultHelpLink,
isProjectSnippet: false, isProjectSnippet: false,
value: defaultVisibilityLevel, value: defaultVisibilityLevel,
...propsData, ...propsData,
}, },
data() { provide: {
return { visibilityLevels,
visibilityLevels, multipleLevelsRestricted,
multipleLevelsRestricted,
};
}, },
}); });
} }
...@@ -108,7 +96,6 @@ describe('Snippet Visibility Edit component', () => { ...@@ -108,7 +96,6 @@ describe('Snippet Visibility Edit component', () => {
it.each` it.each`
levels | resultOptions levels | resultOptions
${undefined} | ${[]}
${''} | ${[]} ${''} | ${[]}
${[]} | ${[]} ${[]} | ${[]}
${[0]} | ${[RESULTING_OPTIONS[0]]} ${[0]} | ${[RESULTING_OPTIONS[0]]}
...@@ -117,7 +104,7 @@ describe('Snippet Visibility Edit component', () => { ...@@ -117,7 +104,7 @@ describe('Snippet Visibility Edit component', () => {
${[0, 20]} | ${[RESULTING_OPTIONS[0], RESULTING_OPTIONS[20]]} ${[0, 20]} | ${[RESULTING_OPTIONS[0], RESULTING_OPTIONS[20]]}
${[10, 20]} | ${[RESULTING_OPTIONS[10], RESULTING_OPTIONS[20]]} ${[10, 20]} | ${[RESULTING_OPTIONS[10], RESULTING_OPTIONS[20]]}
`('renders correct visibility options for $levels', ({ levels, resultOptions }) => { `('renders correct visibility options for $levels', ({ levels, resultOptions }) => {
createComponent({ visibilityLevels: defaultSnippetVisibilityLevels(levels), deep: true }); createComponent({ visibilityLevels: levels, deep: true });
expect(findRadiosData()).toEqual(resultOptions); expect(findRadiosData()).toEqual(resultOptions);
}); });
...@@ -132,7 +119,7 @@ describe('Snippet Visibility Edit component', () => { ...@@ -132,7 +119,7 @@ describe('Snippet Visibility Edit component', () => {
'renders correct information about restricted visibility levels for $levels', 'renders correct information about restricted visibility levels for $levels',
({ levels, levelsRestricted, resultText }) => { ({ levels, levelsRestricted, resultText }) => {
createComponent({ createComponent({
visibilityLevels: defaultSnippetVisibilityLevels(levels), visibilityLevels: levels,
multipleLevelsRestricted: levelsRestricted, multipleLevelsRestricted: levelsRestricted,
}); });
expect(findRestrictedInfo().text()).toBe(resultText); expect(findRestrictedInfo().text()).toBe(resultText);
......
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