Commit 3c6b8f8d authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'design-management-empty-state' into 'master'

Added design management empty state

See merge request gitlab-org/gitlab-ee!10599
parents f59e53f1 61b83522
<script>
import UploadButton from './upload/button.vue';
export default {
components: {
UploadButton,
},
props: {
canUploadDesign: {
type: Boolean,
required: true,
},
isSaving: {
type: Boolean,
required: true,
},
},
methods: {
onFileUploadChange(files) {
this.$emit('upload', files);
},
},
};
</script>
<template>
<div class="empty-state row">
<div class="col-12">
<div class="text-content">
<h4 class="center">
{{ s__('DesignManagement|The one place for your designs') }}
</h4>
<p>
{{
s__(`DesignManagement|Upload and view the latest designs for this issue.
Consistent and easy to find, so everyone is up to date.`)
}}
</p>
<div v-if="canUploadDesign" class="center">
<upload-button :is-saving="isSaving" @upload="onFileUploadChange" />
</div>
</div>
</div>
</div>
</template>
<script>
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
GlButton,
GlLoadingIcon,
},
props: {
isSaving: {
type: Boolean,
required: true,
},
isInverted: {
type: Boolean,
required: false,
default: false,
},
},
methods: {
openFileUpload() {
this.$refs.fileUpload.click();
},
onFileUploadChange() {
this.$emit('upload', this.$refs.fileUpload.files);
},
},
};
</script>
<template>
<div>
<gl-button
:disabled="isSaving"
:class="{
'btn-inverted': isInverted,
}"
variant="primary"
@click="openFileUpload"
>
{{ s__('DesignManagement|Upload designs') }}
<gl-loading-icon v-if="isSaving" inline class="ml-1" />
</gl-button>
<input
ref="fileUpload"
type="file"
name="design_file"
accept="image/*"
class="hide"
multiple
@change="onFileUploadChange"
/>
</div>
</template>
<script> <script>
import { GlButton, GlLoadingIcon } from '@gitlab/ui'; import UploadButton from './button.vue';
export default { export default {
components: { components: {
GlButton, UploadButton,
GlLoadingIcon,
}, },
props: { props: {
isSaving: { isSaving: {
...@@ -17,11 +16,8 @@ export default { ...@@ -17,11 +16,8 @@ export default {
}, },
}, },
methods: { methods: {
openFileUpload() { onFileUploadChange(files) {
this.$refs.fileUpload.click(); this.$emit('upload', files);
},
onFileUploadChange() {
this.$emit('upload', this.$refs.fileUpload.files);
}, },
}, },
}; };
...@@ -30,24 +26,11 @@ export default { ...@@ -30,24 +26,11 @@ export default {
<template> <template>
<header class="row-content-block border-top-0 p-2 d-flex"> <header class="row-content-block border-top-0 p-2 d-flex">
<div> <div>
<gl-button <upload-button
v-if="canUploadDesign" v-if="canUploadDesign"
:disabled="isSaving" :is-saving="isSaving"
variant="primary" :is-inverted="true"
class="btn-inverted" @upload="onFileUploadChange"
@click="openFileUpload"
>
{{ s__('DesignManagement|Upload designs') }}
<gl-loading-icon v-if="isSaving" inline class="ml-1" />
</gl-button>
<input
ref="fileUpload"
type="file"
name="design_file"
accept="image/*"
class="hide"
multiple
@change="onFileUploadChange"
/> />
</div> </div>
</header> </header>
......
...@@ -4,6 +4,7 @@ import createFlash from '~/flash'; ...@@ -4,6 +4,7 @@ import createFlash from '~/flash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import DesignList from '../components/list/index.vue'; import DesignList from '../components/list/index.vue';
import UploadForm from '../components/upload/form.vue'; import UploadForm from '../components/upload/form.vue';
import EmptyState from '../components/empty_state.vue';
import allDesignsQuery from '../queries/allDesigns.graphql'; import allDesignsQuery from '../queries/allDesigns.graphql';
import uploadDesignQuery from '../queries/uploadDesign.graphql'; import uploadDesignQuery from '../queries/uploadDesign.graphql';
import appDataQuery from '../queries/appData.graphql'; import appDataQuery from '../queries/appData.graphql';
...@@ -14,6 +15,7 @@ export default { ...@@ -14,6 +15,7 @@ export default {
GlLoadingIcon, GlLoadingIcon,
DesignList, DesignList,
UploadForm, UploadForm,
EmptyState,
}, },
apollo: { apollo: {
appData: { appData: {
...@@ -44,7 +46,9 @@ export default { ...@@ -44,7 +46,9 @@ export default {
data() { data() {
return { return {
designs: [], designs: [],
permissions: {}, permissions: {
createDesign: false,
},
error: false, error: false,
isSaving: false, isSaving: false,
projectPath: '', projectPath: '',
...@@ -53,11 +57,17 @@ export default { ...@@ -53,11 +57,17 @@ export default {
}, },
computed: { computed: {
isLoading() { isLoading() {
return this.$apollo.queries.designs.loading && this.$apollo.queries.permissions.loading; return this.$apollo.queries.designs.loading || this.$apollo.queries.permissions.loading;
}, },
canCreateDesign() { canCreateDesign() {
return this.permissions.createDesign; return this.permissions.createDesign;
}, },
showUploadForm() {
return this.canCreateDesign && this.hasDesigns;
},
hasDesigns() {
return this.designs.length > 0;
},
}, },
methods: { methods: {
onUploadDesign(files) { onUploadDesign(files) {
...@@ -110,7 +120,7 @@ export default { ...@@ -110,7 +120,7 @@ export default {
<template> <template>
<div> <div>
<upload-form <upload-form
v-if="canCreateDesign" v-if="showUploadForm"
:can-upload-design="canCreateDesign" :can-upload-design="canCreateDesign"
:is-saving="isSaving" :is-saving="isSaving"
@upload="onUploadDesign" @upload="onUploadDesign"
...@@ -120,8 +130,13 @@ export default { ...@@ -120,8 +130,13 @@ export default {
<div v-else-if="error" class="alert alert-danger"> <div v-else-if="error" class="alert alert-danger">
{{ __('An error occurred while loading designs. Please try again.') }} {{ __('An error occurred while loading designs. Please try again.') }}
</div> </div>
<design-list v-else-if="designs.length" :designs="designs" /> <design-list v-else-if="hasDesigns" :designs="designs" />
<div v-else>{{ __('No designs found.') }}</div> <empty-state
v-else
:can-upload-design="canCreateDesign"
:is-saving="isSaving"
@upload="onUploadDesign"
/>
</div> </div>
<router-view /> <router-view />
</div> </div>
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Design management upload button component renders inverted upload design button 1`] = `
<div>
<glbutton-stub
class="btn-inverted"
variant="primary"
>
Upload designs
<!---->
</glbutton-stub>
<input
accept="image/*"
class="hide"
multiple="multiple"
name="design_file"
type="file"
/>
</div>
`;
exports[`Design management upload button component renders loading icon 1`] = `
<div>
<glbutton-stub
class=""
disabled="true"
variant="primary"
>
Upload designs
<glloadingicon-stub
class="ml-1"
color="orange"
inline="true"
label="Loading"
size="sm"
/>
</glbutton-stub>
<input
accept="image/*"
class="hide"
multiple="multiple"
name="design_file"
type="file"
/>
</div>
`;
exports[`Design management upload button component renders upload design button 1`] = `
<div>
<glbutton-stub
class=""
variant="primary"
>
Upload designs
<!---->
</glbutton-stub>
<input
accept="image/*"
class="hide"
multiple="multiple"
name="design_file"
type="file"
/>
</div>
`;
...@@ -6,47 +6,6 @@ exports[`Design management upload form component hides button if cant upload 1`] ...@@ -6,47 +6,6 @@ exports[`Design management upload form component hides button if cant upload 1`]
> >
<div> <div>
<!----> <!---->
<input
accept="image/*"
class="hide"
multiple="multiple"
name="design_file"
type="file"
/>
</div>
</header>
`;
exports[`Design management upload form component renders loading icon 1`] = `
<header
class="row-content-block border-top-0 p-2 d-flex"
>
<div>
<glbutton-stub
class="btn-inverted"
disabled="true"
variant="primary"
>
Upload designs
<glloadingicon-stub
class="ml-1"
color="orange"
inline="true"
label="Loading"
size="sm"
/>
</glbutton-stub>
<input
accept="image/*"
class="hide"
multiple="multiple"
name="design_file"
type="file"
/>
</div> </div>
</header> </header>
`; `;
...@@ -56,22 +15,8 @@ exports[`Design management upload form component renders upload design button 1` ...@@ -56,22 +15,8 @@ exports[`Design management upload form component renders upload design button 1`
class="row-content-block border-top-0 p-2 d-flex" class="row-content-block border-top-0 p-2 d-flex"
> >
<div> <div>
<glbutton-stub <uploadbutton-stub
class="btn-inverted" isinverted="true"
variant="primary"
>
Upload designs
<!---->
</glbutton-stub>
<input
accept="image/*"
class="hide"
multiple="multiple"
name="design_file"
type="file"
/> />
</div> </div>
</header> </header>
......
import { shallowMount } from '@vue/test-utils';
import UploadButton from 'ee/design_management/components/upload/button.vue';
describe('Design management upload button component', () => {
let vm;
function createComponent(isSaving = false, isInverted = false) {
vm = shallowMount(UploadButton, {
propsData: {
isSaving,
isInverted,
},
});
}
afterEach(() => {
vm.destroy();
});
it('renders upload design button', () => {
createComponent();
expect(vm.element).toMatchSnapshot();
});
it('renders inverted upload design button', () => {
createComponent(false, true);
expect(vm.element).toMatchSnapshot();
});
it('renders loading icon', () => {
createComponent(true);
expect(vm.element).toMatchSnapshot();
});
describe('onFileUploadChange', () => {
it('emits upload event', () => {
createComponent();
jest.spyOn(vm.find({ ref: 'fileUpload' }).element, 'files', 'get').mockReturnValue('test');
vm.vm.onFileUploadChange('test');
expect(vm.emitted().upload[0]).toEqual(['test']);
});
});
describe('openFileUpload', () => {
it('triggers click on input', () => {
createComponent();
const clickSpy = jest.spyOn(vm.find({ ref: 'fileUpload' }).element, 'click');
vm.vm.openFileUpload();
expect(clickSpy).toHaveBeenCalled();
});
});
});
...@@ -13,14 +13,12 @@ describe('Design management upload form component', () => { ...@@ -13,14 +13,12 @@ describe('Design management upload form component', () => {
}); });
} }
it('renders upload design button', () => { afterEach(() => {
createComponent(); vm.destroy();
expect(vm.element).toMatchSnapshot();
}); });
it('renders loading icon', () => { it('renders upload design button', () => {
createComponent(true); createComponent();
expect(vm.element).toMatchSnapshot(); expect(vm.element).toMatchSnapshot();
}); });
...@@ -35,23 +33,9 @@ describe('Design management upload form component', () => { ...@@ -35,23 +33,9 @@ describe('Design management upload form component', () => {
it('emits upload event', () => { it('emits upload event', () => {
createComponent(); createComponent();
jest.spyOn(vm.find({ ref: 'fileUpload' }).element, 'files', 'get').mockReturnValue('test'); vm.vm.onFileUploadChange('test');
vm.vm.onFileUploadChange();
expect(vm.emitted().upload[0]).toEqual(['test']); expect(vm.emitted().upload[0]).toEqual(['test']);
}); });
}); });
describe('openFileUpload', () => {
it('triggers click on input', () => {
createComponent();
const clickSpy = jest.spyOn(vm.find({ ref: 'fileUpload' }).element, 'click');
vm.vm.openFileUpload();
expect(clickSpy).toHaveBeenCalled();
});
});
}); });
...@@ -20,16 +20,14 @@ exports[`Design management index page designs renders designs list 1`] = ` ...@@ -20,16 +20,14 @@ exports[`Design management index page designs renders designs list 1`] = `
exports[`Design management index page designs renders empty text 1`] = ` exports[`Design management index page designs renders empty text 1`] = `
<div> <div>
<uploadform-stub <!---->
canuploaddesign="true"
/>
<div <div
class="mt-4" class="mt-4"
> >
<div> <emptystate-stub
No designs found. canuploaddesign="true"
</div> />
</div> </div>
<router-view-stub /> <router-view-stub />
...@@ -38,9 +36,7 @@ exports[`Design management index page designs renders empty text 1`] = ` ...@@ -38,9 +36,7 @@ exports[`Design management index page designs renders empty text 1`] = `
exports[`Design management index page designs renders error 1`] = ` exports[`Design management index page designs renders error 1`] = `
<div> <div>
<uploadform-stub <!---->
canuploaddesign="true"
/>
<div <div
class="mt-4" class="mt-4"
...@@ -60,9 +56,7 @@ exports[`Design management index page designs renders error 1`] = ` ...@@ -60,9 +56,7 @@ exports[`Design management index page designs renders error 1`] = `
exports[`Design management index page designs renders loading icon 1`] = ` exports[`Design management index page designs renders loading icon 1`] = `
<div> <div>
<uploadform-stub <!---->
canuploaddesign="true"
/>
<div <div
class="mt-4" class="mt-4"
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Index from 'ee/design_management/pages/index.vue'; import Index from 'ee/design_management/pages/index.vue';
import UploadForm from 'ee/design_management/components/upload/form.vue';
import uploadDesignQuery from 'ee/design_management/queries/uploadDesign.graphql'; import uploadDesignQuery from 'ee/design_management/queries/uploadDesign.graphql';
describe('Design management index page', () => { describe('Design management index page', () => {
let mutate; let mutate;
let vm; let vm;
function createComponent(loading = false) { function createComponent(loading = false, designs = []) {
mutate = jest.fn(() => Promise.resolve()); mutate = jest.fn(() => Promise.resolve());
const $apollo = { const $apollo = {
queries: { queries: {
...@@ -26,12 +27,17 @@ describe('Design management index page', () => { ...@@ -26,12 +27,17 @@ describe('Design management index page', () => {
}); });
vm.setData({ vm.setData({
designs,
permissions: { permissions: {
createDesign: true, createDesign: true,
}, },
}); });
} }
afterEach(() => {
vm.destroy();
});
describe('designs', () => { describe('designs', () => {
it('renders loading icon', () => { it('renders loading icon', () => {
createComponent(true); createComponent(true);
...@@ -54,11 +60,23 @@ describe('Design management index page', () => { ...@@ -54,11 +60,23 @@ describe('Design management index page', () => {
}); });
it('renders designs list', () => { it('renders designs list', () => {
createComponent(false, ['design']);
expect(vm.element).toMatchSnapshot();
});
});
describe('upload form', () => {
it('hides upload form', () => {
createComponent(); createComponent();
vm.setData({ designs: ['design'] }); expect(vm.find(UploadForm).exists()).toBe(false);
});
expect(vm.element).toMatchSnapshot(); it('renders upload form', () => {
createComponent(false, ['design']);
expect(vm.find(UploadForm).exists()).toBe(true);
}); });
}); });
......
...@@ -3667,6 +3667,12 @@ msgstr "" ...@@ -3667,6 +3667,12 @@ msgstr ""
msgid "DesignManagement|Go to previous design" msgid "DesignManagement|Go to previous design"
msgstr "" msgstr ""
msgid "DesignManagement|The one place for your designs"
msgstr ""
msgid "DesignManagement|Upload and view the latest designs for this issue. Consistent and easy to find, so everyone is up to date."
msgstr ""
msgid "DesignManagement|Upload designs" msgid "DesignManagement|Upload designs"
msgstr "" msgstr ""
...@@ -7372,9 +7378,6 @@ msgstr "" ...@@ -7372,9 +7378,6 @@ msgstr ""
msgid "No credit card required." msgid "No credit card required."
msgstr "" msgstr ""
msgid "No designs found."
msgstr ""
msgid "No details available" msgid "No details available"
msgstr "" msgstr ""
......
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