Commit 432add1d authored by Phil Hughes's avatar Phil Hughes

Merge branch '217934-snippet-description-files' into 'master'

Include `uploadedFiles` param in the snippet Create mutation request

See merge request gitlab-org/gitlab!34221
parents 80b1aeb9 c2ef26aa
......@@ -137,18 +137,34 @@ export default {
this.onExistingSnippetFetched();
}
},
getAttachedFiles() {
const fileInputs = Array.from(this.$el.querySelectorAll('[name="files[]"]'));
return fileInputs.map(node => node.value);
},
createMutation() {
return {
mutation: CreateSnippetMutation,
variables: {
input: {
...this.apiData,
uploadedFiles: this.getAttachedFiles(),
projectPath: this.projectPath,
},
},
};
},
updateMutation() {
return {
mutation: UpdateSnippetMutation,
variables: {
input: this.apiData,
},
};
},
handleFormSubmit() {
this.isUpdating = true;
this.$apollo
.mutate({
mutation: this.newSnippet ? CreateSnippetMutation : UpdateSnippetMutation,
variables: {
input: {
...this.apiData,
projectPath: this.newSnippet ? this.projectPath : undefined,
},
},
})
.mutate(this.newSnippet ? this.createMutation() : this.updateMutation())
.then(({ data }) => {
const baseObj = this.newSnippet ? data?.createSnippet : data?.updateSnippet;
......@@ -176,6 +192,8 @@ export default {
<form
class="snippet-form js-requires-input js-quick-submit common-note-form"
:data-snippet-type="isProjectSnippet ? 'project' : 'personal'"
data-testid="snippet-edit-form"
@submit.prevent="handleFormSubmit"
>
<gl-loading-icon
v-if="isLoading"
......@@ -211,17 +229,17 @@ export default {
<form-footer-actions>
<template #prepend>
<gl-button
type="submit"
category="primary"
type="submit"
variant="success"
:disabled="updatePrevented"
data-qa-selector="submit_button"
@click.prevent="handleFormSubmit"
data-testid="snippet-submit-btn"
>{{ saveButtonLabel }}</gl-button
>
</template>
<template #append>
<gl-button data-testid="snippet-cancel-btn" :href="cancelButtonHref">{{
<gl-button type="cancel" data-testid="snippet-cancel-btn" :href="cancelButtonHref">{{
__('Cancel')
}}</gl-button>
</template>
......
......@@ -30,7 +30,7 @@ export default {
</script>
<template>
<div class="form-group js-description-input">
<label>{{ s__('Snippets|Description (optional)') }}</label>
<label for="snippet-description">{{ s__('Snippets|Description (optional)') }}</label>
<div class="js-collapsible-input">
<div class="js-collapsed" :class="{ 'd-none': value }">
<gl-form-input
......@@ -46,22 +46,26 @@ export default {
<markdown-field
class="js-expanded"
:class="{ 'd-none': !value }"
:add-spacing-classes="false"
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
>
<textarea
slot="textarea"
class="note-textarea js-gfm-input js-autosize markdown-area"
dir="auto"
data-qa-selector="snippet_description_field"
data-supports-quick-actions="false"
:value="value"
:aria-label="__('Description')"
:placeholder="__('Write a comment or drag your files here…')"
v-bind="$attrs"
@input="$emit('input', $event.target.value)"
>
</textarea>
<template #textarea>
<textarea
id="snippet-description"
ref="textarea"
:value="value"
class="note-textarea js-gfm-input js-autosize markdown-area"
dir="auto"
data-qa-selector="snippet_description_field"
data-supports-quick-actions="false"
:aria-label="__('Description')"
:placeholder="__('Write a comment or drag your files here…')"
v-bind="$attrs"
@input="$emit('input', $event.target.value)"
>
</textarea>
</template>
</markdown-field>
</div>
</div>
......
---
title: Send information about attached files to the GraphQL mutation
merge_request: 34221
author:
type: fixed
......@@ -4,7 +4,9 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
<div
class="form-group js-description-input"
>
<label>
<label
for="snippet-description"
>
Description (optional)
</label>
......@@ -21,27 +23,67 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
/>
</div>
<markdown-field-stub
addspacingclasses="true"
canattachfile="true"
class="js-expanded"
enableautocomplete="true"
helppagepath=""
markdowndocspath="help/"
markdownpreviewpath="foo/"
note="[object Object]"
quickactionsdocspath=""
textareavalue=""
<div
class="js-vue-markdown-field md-area position-relative js-expanded gfm-form"
>
<textarea
aria-label="Description"
class="note-textarea js-gfm-input js-autosize markdown-area"
data-qa-selector="snippet_description_field"
data-supports-quick-actions="false"
dir="auto"
placeholder="Write a comment or drag your files here…"
<markdown-header-stub
linecontent=""
/>
</markdown-field-stub>
<div
class="md-write-holder"
>
<div
class="zen-backdrop div-dropzone-wrapper"
>
<div
class="div-dropzone js-invalid-dropzone"
>
<textarea
aria-label="Description"
class="note-textarea js-gfm-input js-autosize markdown-area"
data-qa-selector="snippet_description_field"
data-supports-quick-actions="false"
dir="auto"
id="snippet-description"
placeholder="Write a comment or drag your files here…"
style="overflow-x: hidden; word-wrap: break-word; overflow-y: hidden;"
/>
<div
class="div-dropzone-hover"
>
<i
class="fa fa-paperclip div-dropzone-icon"
/>
</div>
</div>
<a
aria-label="Leave zen mode"
class="zen-control zen-control-leave js-zen-leave gl-text-gray-700"
href="#"
>
<icon-stub
name="screen-normal"
size="16"
/>
</a>
<markdown-toolbar-stub
canattachfile="true"
markdowndocspath="help/"
quickactionsdocspath=""
/>
</div>
</div>
<div
class="js-vue-md-preview md md-preview-holder"
style="display: none;"
/>
<!---->
</div>
</div>
</div>
`;
......@@ -40,6 +40,9 @@ const newlyEditedSnippetUrl = 'http://foo.bar';
const apiError = { message: 'Ufff' };
const mutationError = 'Bummer';
const attachedFilePath1 = 'foo/bar';
const attachedFilePath2 = 'alpha/beta';
const defaultProps = {
snippetGid: 'gid://gitlab/PersonalSnippet/42',
markdownPreviewPath: 'http://preview.foo.bar',
......@@ -120,8 +123,9 @@ describe('Snippet Edit app', () => {
wrapper.destroy();
});
const findSubmitButton = () => wrapper.find('[type=submit]');
const findSubmitButton = () => wrapper.find('[data-testid="snippet-submit-btn"]');
const findCancellButton = () => wrapper.find('[data-testid="snippet-cancel-btn"]');
const clickSubmitBtn = () => wrapper.find('[data-testid="snippet-edit-form"]').trigger('submit');
describe('rendering', () => {
it('renders loader while the query is in flight', () => {
......@@ -289,13 +293,15 @@ describe('Snippet Edit app', () => {
},
};
wrapper.vm.handleFormSubmit();
clickSubmitBtn();
expect(resolveMutate).toHaveBeenCalledWith(mutationPayload);
});
it('redirects to snippet view on successful mutation', () => {
createComponent();
wrapper.vm.handleFormSubmit();
clickSubmitBtn();
return waitForPromises().then(() => {
expect(redirectTo).toHaveBeenCalledWith(newlyEditedSnippetUrl);
});
......@@ -322,7 +328,8 @@ describe('Snippet Edit app', () => {
mutationRes: mutationTypes.RESOLVE_WITH_ERRORS,
});
wrapper.vm.handleFormSubmit();
clickSubmitBtn();
return waitForPromises().then(() => {
expect(redirectTo).not.toHaveBeenCalled();
expect(flashSpy).toHaveBeenCalledWith(mutationError);
......@@ -334,7 +341,9 @@ describe('Snippet Edit app', () => {
createComponent({
mutationRes: mutationTypes.REJECT,
});
wrapper.vm.handleFormSubmit();
clickSubmitBtn();
return waitForPromises().then(() => {
expect(redirectTo).not.toHaveBeenCalled();
expect(flashSpy).toHaveBeenCalledWith(apiError);
......@@ -354,12 +363,61 @@ describe('Snippet Edit app', () => {
},
mutationRes: mutationTypes.REJECT,
});
wrapper.vm.handleFormSubmit();
clickSubmitBtn();
return waitForPromises().then(() => {
expect(Flash).toHaveBeenCalledWith(expect.stringContaining(expectation));
});
},
);
});
describe('correctly includes attached files into the mutation', () => {
const createMutationPayload = expectation => {
return expect.objectContaining({
variables: {
input: expect.objectContaining({ uploadedFiles: expectation }),
},
});
};
const updateMutationPayload = () => {
return expect.objectContaining({
variables: {
input: expect.not.objectContaining({ uploadedFiles: expect.anything() }),
},
});
};
it.each`
paths | expectation
${[attachedFilePath1]} | ${[attachedFilePath1]}
${[attachedFilePath1, attachedFilePath2]} | ${[attachedFilePath1, attachedFilePath2]}
${[]} | ${[]}
`(`correctly sends paths for $paths.length files`, ({ paths, expectation }) => {
createComponent({
data: {
newSnippet: true,
},
});
const fixtures = paths.map(path => {
return path ? `<input name="files[]" value="${path}">` : undefined;
});
wrapper.vm.$el.innerHTML += fixtures.join('');
clickSubmitBtn();
expect(resolveMutate).toHaveBeenCalledWith(createMutationPayload(expectation));
});
it(`neither fails nor sends 'uploadedFiles' to update mutation`, () => {
createComponent();
clickSubmitBtn();
expect(resolveMutate).toHaveBeenCalledWith(updateMutationPayload());
});
});
});
});
import SnippetDescriptionEdit from '~/snippets/components/snippet_description_edit.vue';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { shallowMount } from '@vue/test-utils';
describe('Snippet Description Edit component', () => {
......@@ -15,6 +16,9 @@ describe('Snippet Description Edit component', () => {
markdownPreviewPath,
markdownDocsPath,
},
stubs: {
MarkdownField,
},
});
}
......
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