Commit 5fd724f7 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '13426-graphql-fe' into 'master'

Reflect design collection copy state on frontend

See merge request gitlab-org/gitlab!42548
parents 6c530fec c805e676
...@@ -6,6 +6,7 @@ query getDesignList($fullPath: ID!, $iid: String!, $atVersion: ID) { ...@@ -6,6 +6,7 @@ query getDesignList($fullPath: ID!, $iid: String!, $atVersion: ID) {
id id
issue(iid: $iid) { issue(iid: $iid) {
designCollection { designCollection {
copyState
designs(atVersion: $atVersion) { designs(atVersion: $atVersion) {
nodes { nodes {
...DesignListItem ...DesignListItem
......
...@@ -8,7 +8,7 @@ import { DESIGNS_ROUTE_NAME } from '../router/constants'; ...@@ -8,7 +8,7 @@ import { DESIGNS_ROUTE_NAME } from '../router/constants';
export default { export default {
mixins: [allVersionsMixin], mixins: [allVersionsMixin],
apollo: { apollo: {
designs: { designCollection: {
query: getDesignListQuery, query: getDesignListQuery,
variables() { variables() {
return { return {
...@@ -25,10 +25,11 @@ export default { ...@@ -25,10 +25,11 @@ export default {
'designs', 'designs',
'nodes', 'nodes',
]); ]);
if (designNodes) { const copyState = propertyOf(data)(['project', 'issue', 'designCollection', 'copyState']);
return designNodes; return {
} designs: designNodes,
return []; copyState,
};
}, },
error() { error() {
this.error = true; this.error = true;
...@@ -42,13 +43,26 @@ export default { ...@@ -42,13 +43,26 @@ export default {
); );
this.$router.replace({ name: DESIGNS_ROUTE_NAME, query: { version: undefined } }); this.$router.replace({ name: DESIGNS_ROUTE_NAME, query: { version: undefined } });
} }
if (this.designCollection.copyState === 'ERROR') {
createFlash(
s__(
'DesignManagement|There was an error moving your designs. Please upload your designs below.',
),
'warning',
);
}
}, },
}, },
}, },
data() { data() {
return { return {
designs: [], designCollection: null,
error: false, error: false,
}; };
}, },
computed: {
designs() {
return this.designCollection?.designs || [];
},
},
}; };
...@@ -76,7 +76,9 @@ export default { ...@@ -76,7 +76,9 @@ export default {
}, },
computed: { computed: {
isLoading() { isLoading() {
return this.$apollo.queries.designs.loading || this.$apollo.queries.permissions.loading; return (
this.$apollo.queries.designCollection.loading || this.$apollo.queries.permissions.loading
);
}, },
isSaving() { isSaving() {
return this.filesToBeSaved.length > 0; return this.filesToBeSaved.length > 0;
...@@ -110,6 +112,11 @@ export default { ...@@ -110,6 +112,11 @@ export default {
isDesignListEmpty() { isDesignListEmpty() {
return !this.isSaving && !this.hasDesigns; return !this.isSaving && !this.hasDesigns;
}, },
isDesignCollectionCopying() {
return (
this.designCollection && ['PENDING', 'COPYING'].includes(this.designCollection.copyState)
);
},
designDropzoneWrapperClass() { designDropzoneWrapperClass() {
return this.isDesignListEmpty return this.isDesignListEmpty
? 'col-12' ? 'col-12'
...@@ -360,6 +367,21 @@ export default { ...@@ -360,6 +367,21 @@ export default {
<gl-alert v-else-if="error" variant="danger" :dismissible="false"> <gl-alert v-else-if="error" variant="danger" :dismissible="false">
{{ __('An error occurred while loading designs. Please try again.') }} {{ __('An error occurred while loading designs. Please try again.') }}
</gl-alert> </gl-alert>
<header
v-else-if="isDesignCollectionCopying"
class="card gl-p-3"
data-testid="design-collection-is-copying"
>
<div class="card-header design-card-header border-bottom-0">
<div class="card-title gl-my-0 gl-h-7">
{{
s__(
'DesignManagement|Your designs are being copied and are on their way… Please refresh to update.',
)
}}
</div>
</div>
</header>
<vue-draggable <vue-draggable
v-else v-else
:value="designs" :value="designs"
......
...@@ -155,6 +155,7 @@ const addNewDesignToStore = (store, designManagementUpload, query) => { ...@@ -155,6 +155,7 @@ const addNewDesignToStore = (store, designManagementUpload, query) => {
const updatedDesigns = { const updatedDesigns = {
__typename: 'DesignCollection', __typename: 'DesignCollection',
copyState: 'READY',
designs: { designs: {
__typename: 'DesignConnection', __typename: 'DesignConnection',
nodes: newDesigns, nodes: newDesigns,
......
...@@ -65,6 +65,10 @@ export const designUploadOptimisticResponse = files => { ...@@ -65,6 +65,10 @@ export const designUploadOptimisticResponse = files => {
fullPath: '', fullPath: '',
notesCount: 0, notesCount: 0,
event: 'NONE', event: 'NONE',
currentUserTodos: {
__typename: 'TodoConnection',
nodes: [],
},
diffRefs: { diffRefs: {
__typename: 'DiffRefs', __typename: 'DiffRefs',
baseSha: '', baseSha: '',
......
...@@ -152,6 +152,10 @@ ...@@ -152,6 +152,10 @@
} }
} }
.design-card-header {
background: transparent;
}
.design-dropzone-border { .design-dropzone-border {
border: 2px dashed $gray-100; border: 2px dashed $gray-100;
} }
......
---
title: Copy designs to issue when an issue with designs is moved
merge_request: 42548
author:
type: fixed
...@@ -8,6 +8,8 @@ msgid "" ...@@ -8,6 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gitlab 1.0.0\n" "Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-18 11:00+1200\n"
"PO-Revision-Date: 2020-09-18 11:00+1200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n" "Language: \n"
...@@ -8853,6 +8855,9 @@ msgstr "" ...@@ -8853,6 +8855,9 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again." msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr "" msgstr ""
msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
msgstr ""
msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}" msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr "" msgstr ""
...@@ -8865,6 +8870,9 @@ msgstr "" ...@@ -8865,6 +8870,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped." msgid "DesignManagement|Upload skipped."
msgstr "" msgstr ""
msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
msgstr ""
msgid "DesignManagement|and %{moreCount} more." msgid "DesignManagement|and %{moreCount} more."
msgstr "" msgstr ""
......
...@@ -43,7 +43,7 @@ describe('Design management pagination component', () => { ...@@ -43,7 +43,7 @@ describe('Design management pagination component', () => {
it('renders navigation buttons', () => { it('renders navigation buttons', () => {
wrapper.setData({ wrapper.setData({
designs: [{ id: '1' }, { id: '2' }], designCollection: { designs: [{ id: '1' }, { id: '2' }] },
}); });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
...@@ -54,7 +54,7 @@ describe('Design management pagination component', () => { ...@@ -54,7 +54,7 @@ describe('Design management pagination component', () => {
describe('keyboard buttons navigation', () => { describe('keyboard buttons navigation', () => {
beforeEach(() => { beforeEach(() => {
wrapper.setData({ wrapper.setData({
designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }], designCollection: { designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }] },
}); });
}); });
......
...@@ -4,6 +4,7 @@ export const designListQueryResponse = { ...@@ -4,6 +4,7 @@ export const designListQueryResponse = {
id: '1', id: '1',
issue: { issue: {
designCollection: { designCollection: {
copyState: 'READY',
designs: { designs: {
nodes: [ nodes: [
{ {
......
...@@ -92,6 +92,8 @@ describe('Design management index page', () => { ...@@ -92,6 +92,8 @@ describe('Design management index page', () => {
const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox'); const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
const findSelectAllButton = () => wrapper.find('.js-select-all'); const findSelectAllButton = () => wrapper.find('.js-select-all');
const findToolbar = () => wrapper.find('.qa-selector-toolbar'); const findToolbar = () => wrapper.find('.qa-selector-toolbar');
const findDesignCollectionIsCopying = () =>
wrapper.find('[data-testid="design-collection-is-copying"');
const findDeleteButton = () => wrapper.find(DeleteButton); const findDeleteButton = () => wrapper.find(DeleteButton);
const findDropzone = () => wrapper.findAll(DesignDropzone).at(0); const findDropzone = () => wrapper.findAll(DesignDropzone).at(0);
const dropzoneClasses = () => findDropzone().classes(); const dropzoneClasses = () => findDropzone().classes();
...@@ -116,8 +118,8 @@ describe('Design management index page', () => { ...@@ -116,8 +118,8 @@ describe('Design management index page', () => {
function createComponent({ function createComponent({
loading = false, loading = false,
designs = [],
allVersions = [], allVersions = [],
designCollection = { designs: mockDesigns, copyState: 'READY' },
createDesign = true, createDesign = true,
stubs = {}, stubs = {},
mockMutate = jest.fn().mockResolvedValue(), mockMutate = jest.fn().mockResolvedValue(),
...@@ -125,7 +127,7 @@ describe('Design management index page', () => { ...@@ -125,7 +127,7 @@ describe('Design management index page', () => {
mutate = mockMutate; mutate = mockMutate;
const $apollo = { const $apollo = {
queries: { queries: {
designs: { designCollection: {
loading, loading,
}, },
permissions: { permissions: {
...@@ -138,8 +140,8 @@ describe('Design management index page', () => { ...@@ -138,8 +140,8 @@ describe('Design management index page', () => {
wrapper = shallowMount(Index, { wrapper = shallowMount(Index, {
data() { data() {
return { return {
designs,
allVersions, allVersions,
designCollection,
permissions: { permissions: {
createDesign, createDesign,
}, },
...@@ -201,13 +203,13 @@ describe('Design management index page', () => { ...@@ -201,13 +203,13 @@ describe('Design management index page', () => {
}); });
it('renders a toolbar with buttons when there are designs', () => { it('renders a toolbar with buttons when there are designs', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] }); createComponent({ allVersions: [mockVersion] });
expect(findToolbar().exists()).toBe(true); expect(findToolbar().exists()).toBe(true);
}); });
it('renders designs list and header with upload button', () => { it('renders designs list and header with upload button', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] }); createComponent({ allVersions: [mockVersion] });
expect(wrapper.element).toMatchSnapshot(); expect(wrapper.element).toMatchSnapshot();
}); });
...@@ -237,7 +239,7 @@ describe('Design management index page', () => { ...@@ -237,7 +239,7 @@ describe('Design management index page', () => {
describe('when has no designs', () => { describe('when has no designs', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent({ designCollection: { designs: [], copyState: 'READY' } });
}); });
it('renders design dropzone', () => it('renders design dropzone', () =>
...@@ -260,6 +262,21 @@ describe('Design management index page', () => { ...@@ -260,6 +262,21 @@ describe('Design management index page', () => {
})); }));
}); });
describe('handling design collection copy state', () => {
it.each`
copyState | isRendered | description
${'COPYING'} | ${true} | ${'renders'}
${'READY'} | ${false} | ${'does not render'}
${'ERROR'} | ${false} | ${'does not render'}
`(
'$description the copying message if design collection copyState is $copyState',
({ copyState, isRendered }) => {
createComponent({ designCollection: { designs: [], copyState } });
expect(findDesignCollectionIsCopying().exists()).toBe(isRendered);
},
);
});
describe('uploading designs', () => { describe('uploading designs', () => {
it('calls mutation on upload', () => { it('calls mutation on upload', () => {
createComponent({ stubs: { GlEmptyState } }); createComponent({ stubs: { GlEmptyState } });
...@@ -283,6 +300,10 @@ describe('Design management index page', () => { ...@@ -283,6 +300,10 @@ describe('Design management index page', () => {
{ {
__typename: 'Design', __typename: 'Design',
id: expect.anything(), id: expect.anything(),
currentUserTodos: {
__typename: 'TodoConnection',
nodes: [],
},
image: '', image: '',
imageV432x230: '', imageV432x230: '',
filename: 'test', filename: 'test',
...@@ -532,13 +553,16 @@ describe('Design management index page', () => { ...@@ -532,13 +553,16 @@ describe('Design management index page', () => {
}); });
it('on latest version when has no designs toolbar buttons are invisible', () => { it('on latest version when has no designs toolbar buttons are invisible', () => {
createComponent({ designs: [], allVersions: [mockVersion] }); createComponent({
designCollection: { designs: [], copyState: 'READY' },
allVersions: [mockVersion],
});
expect(findToolbar().isVisible()).toBe(false); expect(findToolbar().isVisible()).toBe(false);
}); });
describe('on non-latest version', () => { describe('on non-latest version', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] }); createComponent({ allVersions: [mockVersion] });
}); });
it('does not render design checkboxes', async () => { it('does not render design checkboxes', async () => {
......
...@@ -25,7 +25,7 @@ function factory(routeArg) { ...@@ -25,7 +25,7 @@ function factory(routeArg) {
mocks: { mocks: {
$apollo: { $apollo: {
queries: { queries: {
designs: { loading: true }, designCollection: { loading: true },
design: { loading: true }, design: { loading: true },
permissions: { loading: true }, permissions: { loading: true },
}, },
......
...@@ -93,6 +93,10 @@ describe('optimistic responses', () => { ...@@ -93,6 +93,10 @@ describe('optimistic responses', () => {
fullPath: '', fullPath: '',
notesCount: 0, notesCount: 0,
event: 'NONE', event: 'NONE',
currentUserTodos: {
__typename: 'TodoConnection',
nodes: [],
},
diffRefs: { __typename: 'DiffRefs', baseSha: '', startSha: '', headSha: '' }, diffRefs: { __typename: 'DiffRefs', baseSha: '', startSha: '', headSha: '' },
discussions: { __typename: 'DesignDiscussion', nodes: [] }, discussions: { __typename: 'DesignDiscussion', nodes: [] },
versions: { versions: {
......
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