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) {
id
issue(iid: $iid) {
designCollection {
copyState
designs(atVersion: $atVersion) {
nodes {
...DesignListItem
......
......@@ -8,7 +8,7 @@ import { DESIGNS_ROUTE_NAME } from '../router/constants';
export default {
mixins: [allVersionsMixin],
apollo: {
designs: {
designCollection: {
query: getDesignListQuery,
variables() {
return {
......@@ -25,10 +25,11 @@ export default {
'designs',
'nodes',
]);
if (designNodes) {
return designNodes;
}
return [];
const copyState = propertyOf(data)(['project', 'issue', 'designCollection', 'copyState']);
return {
designs: designNodes,
copyState,
};
},
error() {
this.error = true;
......@@ -42,13 +43,26 @@ export default {
);
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() {
return {
designs: [],
designCollection: null,
error: false,
};
},
computed: {
designs() {
return this.designCollection?.designs || [];
},
},
};
......@@ -76,7 +76,9 @@ export default {
},
computed: {
isLoading() {
return this.$apollo.queries.designs.loading || this.$apollo.queries.permissions.loading;
return (
this.$apollo.queries.designCollection.loading || this.$apollo.queries.permissions.loading
);
},
isSaving() {
return this.filesToBeSaved.length > 0;
......@@ -110,6 +112,11 @@ export default {
isDesignListEmpty() {
return !this.isSaving && !this.hasDesigns;
},
isDesignCollectionCopying() {
return (
this.designCollection && ['PENDING', 'COPYING'].includes(this.designCollection.copyState)
);
},
designDropzoneWrapperClass() {
return this.isDesignListEmpty
? 'col-12'
......@@ -360,6 +367,21 @@ export default {
<gl-alert v-else-if="error" variant="danger" :dismissible="false">
{{ __('An error occurred while loading designs. Please try again.') }}
</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
v-else
:value="designs"
......
......@@ -155,6 +155,7 @@ const addNewDesignToStore = (store, designManagementUpload, query) => {
const updatedDesigns = {
__typename: 'DesignCollection',
copyState: 'READY',
designs: {
__typename: 'DesignConnection',
nodes: newDesigns,
......
......@@ -65,6 +65,10 @@ export const designUploadOptimisticResponse = files => {
fullPath: '',
notesCount: 0,
event: 'NONE',
currentUserTodos: {
__typename: 'TodoConnection',
nodes: [],
},
diffRefs: {
__typename: 'DiffRefs',
baseSha: '',
......
......@@ -152,6 +152,10 @@
}
}
.design-card-header {
background: transparent;
}
.design-dropzone-border {
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 ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\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"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -8853,6 +8855,9 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
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}"
msgstr ""
......@@ -8865,6 +8870,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
msgstr ""
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
......
......@@ -43,7 +43,7 @@ describe('Design management pagination component', () => {
it('renders navigation buttons', () => {
wrapper.setData({
designs: [{ id: '1' }, { id: '2' }],
designCollection: { designs: [{ id: '1' }, { id: '2' }] },
});
return wrapper.vm.$nextTick().then(() => {
......@@ -54,7 +54,7 @@ describe('Design management pagination component', () => {
describe('keyboard buttons navigation', () => {
beforeEach(() => {
wrapper.setData({
designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }],
designCollection: { designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }] },
});
});
......
......@@ -4,6 +4,7 @@ export const designListQueryResponse = {
id: '1',
issue: {
designCollection: {
copyState: 'READY',
designs: {
nodes: [
{
......
......@@ -92,6 +92,8 @@ describe('Design management index page', () => {
const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
const findSelectAllButton = () => wrapper.find('.js-select-all');
const findToolbar = () => wrapper.find('.qa-selector-toolbar');
const findDesignCollectionIsCopying = () =>
wrapper.find('[data-testid="design-collection-is-copying"');
const findDeleteButton = () => wrapper.find(DeleteButton);
const findDropzone = () => wrapper.findAll(DesignDropzone).at(0);
const dropzoneClasses = () => findDropzone().classes();
......@@ -116,8 +118,8 @@ describe('Design management index page', () => {
function createComponent({
loading = false,
designs = [],
allVersions = [],
designCollection = { designs: mockDesigns, copyState: 'READY' },
createDesign = true,
stubs = {},
mockMutate = jest.fn().mockResolvedValue(),
......@@ -125,7 +127,7 @@ describe('Design management index page', () => {
mutate = mockMutate;
const $apollo = {
queries: {
designs: {
designCollection: {
loading,
},
permissions: {
......@@ -138,8 +140,8 @@ describe('Design management index page', () => {
wrapper = shallowMount(Index, {
data() {
return {
designs,
allVersions,
designCollection,
permissions: {
createDesign,
},
......@@ -201,13 +203,13 @@ describe('Design management index page', () => {
});
it('renders a toolbar with buttons when there are designs', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
createComponent({ allVersions: [mockVersion] });
expect(findToolbar().exists()).toBe(true);
});
it('renders designs list and header with upload button', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
createComponent({ allVersions: [mockVersion] });
expect(wrapper.element).toMatchSnapshot();
});
......@@ -237,7 +239,7 @@ describe('Design management index page', () => {
describe('when has no designs', () => {
beforeEach(() => {
createComponent();
createComponent({ designCollection: { designs: [], copyState: 'READY' } });
});
it('renders design dropzone', () =>
......@@ -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', () => {
it('calls mutation on upload', () => {
createComponent({ stubs: { GlEmptyState } });
......@@ -283,6 +300,10 @@ describe('Design management index page', () => {
{
__typename: 'Design',
id: expect.anything(),
currentUserTodos: {
__typename: 'TodoConnection',
nodes: [],
},
image: '',
imageV432x230: '',
filename: 'test',
......@@ -532,13 +553,16 @@ describe('Design management index page', () => {
});
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);
});
describe('on non-latest version', () => {
beforeEach(() => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
createComponent({ allVersions: [mockVersion] });
});
it('does not render design checkboxes', async () => {
......
......@@ -25,7 +25,7 @@ function factory(routeArg) {
mocks: {
$apollo: {
queries: {
designs: { loading: true },
designCollection: { loading: true },
design: { loading: true },
permissions: { loading: true },
},
......
......@@ -93,6 +93,10 @@ describe('optimistic responses', () => {
fullPath: '',
notesCount: 0,
event: 'NONE',
currentUserTodos: {
__typename: 'TodoConnection',
nodes: [],
},
diffRefs: { __typename: 'DiffRefs', baseSha: '', startSha: '', headSha: '' },
discussions: { __typename: 'DesignDiscussion', nodes: [] },
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