Skip to content
Snippets Groups Projects
Verified Commit 587f9e4c authored by Rajan Mistry's avatar Rajan Mistry :baby:
Browse files

Move add button to description form to simplify

parent d968a491
No related branches found
No related tags found
No related merge requests found
This commit is part of merge request !148359. Comments created here will be created in the context of that merge request.
...@@ -27,6 +27,7 @@ export default { ...@@ -27,6 +27,7 @@ export default {
i18n: { i18n: {
editDescription: s__('DesignManagement|Edit description'), editDescription: s__('DesignManagement|Edit description'),
descriptionLabel: s__('DesignManagement|Description'), descriptionLabel: s__('DesignManagement|Description'),
addDescriptionLabel: s__('DesignManagement|Add a description'),
}, },
formFieldProps: { formFieldProps: {
id: 'design-description', id: 'design-description',
...@@ -49,16 +50,11 @@ export default { ...@@ -49,16 +50,11 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
initiallyOpen: {
type: Boolean,
required: false,
default: false,
},
}, },
data() { data() {
return { return {
descriptionText: this.design.description || '', descriptionText: this.design.description || '',
showEditor: this.initiallyOpen, showEditor: false,
isSubmitting: false, isSubmitting: false,
errorMessage: '', errorMessage: '',
autosaveKey: `Issue/${getIdFromGraphQLId(this.design.issue.id)}/Design/${getIdFromGraphQLId( autosaveKey: `Issue/${getIdFromGraphQLId(this.design.issue.id)}/Design/${getIdFromGraphQLId(
...@@ -70,6 +66,9 @@ export default { ...@@ -70,6 +66,9 @@ export default {
canUpdate() { canUpdate() {
return this.design.issue?.userPermissions?.updateDesign && !this.showEditor; return this.design.issue?.userPermissions?.updateDesign && !this.showEditor;
}, },
showAddDescriptionButton() {
return this.design.issue?.userPermissions?.updateDesign && !this.design.descriptionHtml;
},
}, },
watch: { watch: {
'design.descriptionHtml': { 'design.descriptionHtml': {
...@@ -86,7 +85,6 @@ export default { ...@@ -86,7 +85,6 @@ export default {
this.showEditor = true; this.showEditor = true;
}, },
closeForm() { closeForm() {
this.$emit('editorClosed');
// If description text is empty on cancel, // If description text is empty on cancel,
// restore the old description // restore the old description
if (!this.descriptionText) { if (!this.descriptionText) {
...@@ -200,7 +198,7 @@ export default { ...@@ -200,7 +198,7 @@ export default {
:loading="isSubmitting" :loading="isSubmitting"
data-testid="save-description" data-testid="save-description"
@click="updateDesignDescription" @click="updateDesignDescription"
>{{ s__('DesignManagement|Save') }} >{{ s__('DesignManagement|Save changes') }}
</gl-button> </gl-button>
<gl-button category="tertiary" class="gl-ml-3" data-testid="cancel" @click="closeForm" <gl-button category="tertiary" class="gl-ml-3" data-testid="cancel" @click="closeForm"
>{{ s__('DesignManagement|Cancel') }} >{{ s__('DesignManagement|Cancel') }}
...@@ -208,34 +206,49 @@ export default { ...@@ -208,34 +206,49 @@ export default {
</div> </div>
</gl-form-group> </gl-form-group>
<div v-else class="design-description-view"> <div v-else class="design-description-view">
<div <gl-button
class="design-description-header gl-display-flex gl-justify-content-space-between gl-mb-2" v-if="showAddDescriptionButton"
class="gl-ml-auto"
size="small"
data-testid="add-design-description"
:aria-label="$options.i18n.addDescriptionLabel"
@click="startEditing"
> >
<h3 class="gl-line-height-20! gl-font-lg gl-m-0"> {{ $options.i18n.addDescriptionLabel }}
{{ $options.i18n.descriptionLabel }} </gl-button>
</h3> <template v-else>
<gl-button
v-if="canUpdate"
v-gl-tooltip
class="gl-ml-auto"
size="small"
category="tertiary"
:aria-label="$options.i18n.editDescription"
:title="$options.i18n.editDescription"
data-testid="edit-description"
icon="pencil"
@click="startEditing"
/>
</div>
<div v-if="design.descriptionHtml" class="design-description js-task-list-container">
<div <div
ref="gfm-content" class="design-description-header gl-display-flex gl-justify-content-space-between gl-mb-2"
v-safe-html="design.descriptionHtml" >
class="md gl-mb-4" <h3 class="gl-line-height-20! gl-font-lg gl-m-0">
data-testid="design-description-content" {{ $options.i18n.descriptionLabel }}
@change="toggleCheckboxes" </h3>
></div> <gl-button
</div> v-if="canUpdate"
v-gl-tooltip
class="gl-ml-auto"
size="small"
category="tertiary"
:aria-label="$options.i18n.editDescription"
:title="$options.i18n.editDescription"
data-testid="edit-description"
icon="pencil"
@click="startEditing"
/>
</div>
<div v-if="design.descriptionHtml" class="design-description js-task-list-container">
<div
ref="gfm-content"
v-safe-html="design.descriptionHtml"
class="md gl-mb-4"
data-testid="design-description-content"
@change="toggleCheckboxes"
></div>
</div>
<div v-else data-testid="design-description-none" class="gl-text-secondary gl-mb-5">
{{ s__('DesignManagement|None') }}
</div>
</template>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { GlAccordion, GlAccordionItem, GlSkeletonLoader, GlEmptyState, GlButton } from '@gitlab/ui'; import { GlAccordion, GlAccordionItem, GlSkeletonLoader, GlEmptyState } from '@gitlab/ui';
import EMPTY_DISCUSSION_URL from '@gitlab/svgs/dist/illustrations/empty-state/empty-activity-md.svg'; import EMPTY_DISCUSSION_URL from '@gitlab/svgs/dist/illustrations/empty-state/empty-activity-md.svg';
import { isLoggedIn } from '~/lib/utils/common_utils'; import { isLoggedIn } from '~/lib/utils/common_utils';
...@@ -21,7 +21,6 @@ export default { ...@@ -21,7 +21,6 @@ export default {
GlAccordionItem, GlAccordionItem,
GlSkeletonLoader, GlSkeletonLoader,
GlEmptyState, GlEmptyState,
GlButton,
DescriptionForm, DescriptionForm,
DesignDisclosure, DesignDisclosure,
}, },
...@@ -71,7 +70,6 @@ export default { ...@@ -71,7 +70,6 @@ export default {
discussionWithOpenForm: '', discussionWithOpenForm: '',
isLoggedIn: isLoggedIn(), isLoggedIn: isLoggedIn(),
emptyDiscussionSvgPath: EMPTY_DISCUSSION_URL, emptyDiscussionSvgPath: EMPTY_DISCUSSION_URL,
isEditing: false,
}; };
}, },
computed: { computed: {
...@@ -110,13 +108,6 @@ export default { ...@@ -110,13 +108,6 @@ export default {
this.$emit('toggleResolvedComments', isExpanded); this.$emit('toggleResolvedComments', isExpanded);
}, },
}, },
showAddDescriptionButton() {
return (
this.design.issue?.userPermissions?.updateDesign &&
!this.isEditing &&
!this.design.descriptionHtml
);
},
}, },
mounted() { mounted() {
if (!this.isResolvedCommentsPopoverHidden && this.$refs.resolvedComments) { if (!this.isResolvedCommentsPopoverHidden && this.$refs.resolvedComments) {
...@@ -156,27 +147,13 @@ export default { ...@@ -156,27 +147,13 @@ export default {
<template #default> <template #default>
<div class="image-notes gl-h-full gl-pt-0" @click.self="handleSidebarClick"> <div class="image-notes gl-h-full gl-pt-0" @click.self="handleSidebarClick">
<div class="gl-border-b"> <div class="gl-border-b">
<gl-button <description-form
v-if="showAddDescriptionButton" v-if="!isLoading"
class="gl-ml-auto gl-my-5" :design="design"
size="small" :design-variables="designVariables"
data-testid="add-design-description" :markdown-preview-path="markdownPreviewPath"
:aria-label="$options.i18n.addDescription" class="gl-my-5"
@click="isEditing = !isEditing" />
>
{{ $options.i18n.addDescription }}
</gl-button>
<template v-else>
<description-form
v-if="!isLoading"
:design="design"
:design-variables="designVariables"
:markdown-preview-path="markdownPreviewPath"
:initially-open="isEditing"
class="gl-my-5"
@editorClosed="isEditing = false"
/>
</template>
</div> </div>
<div v-if="isLoading" class="gl-my-5"> <div v-if="isLoading" class="gl-my-5">
<gl-skeleton-loader /> <gl-skeleton-loader />
......
...@@ -18095,6 +18095,9 @@ msgstr "" ...@@ -18095,6 +18095,9 @@ msgstr ""
msgid "DesignManagement|Hide comments" msgid "DesignManagement|Hide comments"
msgstr "" msgstr ""
   
msgid "DesignManagement|None"
msgstr ""
msgid "DesignManagement|Requested design version does not exist. Showing latest version instead" msgid "DesignManagement|Requested design version does not exist. Showing latest version instead"
msgstr "" msgstr ""
   
...@@ -18104,7 +18107,7 @@ msgstr "" ...@@ -18104,7 +18107,7 @@ msgstr ""
msgid "DesignManagement|Resolved Comments" msgid "DesignManagement|Resolved Comments"
msgstr "" msgstr ""
   
msgid "DesignManagement|Save" msgid "DesignManagement|Save changes"
msgstr "" msgstr ""
   
msgid "DesignManagement|Save comment" msgid "DesignManagement|Save comment"
...@@ -68,6 +68,7 @@ describe('Design description form', () => { ...@@ -68,6 +68,7 @@ describe('Design description form', () => {
}); });
const findDesignContent = () => wrapper.findByTestId('design-description-content'); const findDesignContent = () => wrapper.findByTestId('design-description-content');
const findDesignNoneBlock = () => wrapper.findByTestId('design-description-none');
const findEditDescriptionButton = () => wrapper.findByTestId('edit-description'); const findEditDescriptionButton = () => wrapper.findByTestId('edit-description');
const findSaveDescriptionButton = () => wrapper.findByTestId('save-description'); const findSaveDescriptionButton = () => wrapper.findByTestId('save-description');
const findCancelDescriptionButton = () => wrapper.findByTestId('cancel'); const findCancelDescriptionButton = () => wrapper.findByTestId('cancel');
...@@ -75,6 +76,7 @@ describe('Design description form', () => { ...@@ -75,6 +76,7 @@ describe('Design description form', () => {
const findTextarea = () => wrapper.find('textarea'); const findTextarea = () => wrapper.find('textarea');
const findCheckboxAtIndex = (index) => wrapper.findAll('input[type="checkbox"]').at(index); const findCheckboxAtIndex = (index) => wrapper.findAll('input[type="checkbox"]').at(index);
const findAlert = () => wrapper.findComponent(GlAlert); const findAlert = () => wrapper.findComponent(GlAlert);
const findAddDesignDescriptionButton = () => wrapper.findByTestId('add-design-description');
describe('user has updateDesign permission', () => { describe('user has updateDesign permission', () => {
let trackingSpy; let trackingSpy;
...@@ -100,9 +102,7 @@ describe('Design description form', () => { ...@@ -100,9 +102,7 @@ describe('Design description form', () => {
}); });
it('renders save button when editor is open', async () => { it('renders save button when editor is open', async () => {
createComponent({ createComponent();
design: designFactory({ description: '', descriptionHtml: '' }),
});
await findEditDescriptionButton().vm.$emit('click'); await findEditDescriptionButton().vm.$emit('click');
...@@ -133,24 +133,44 @@ describe('Design description form', () => { ...@@ -133,24 +133,44 @@ describe('Design description form', () => {
}); });
}); });
it('shows form by default when initiallyOpen prop is true', () => { it('renders add a description button when there is no description', () => {
createComponent({ createComponent({
initiallyOpen: true, design: designFactory({
description: '',
descriptionHtml: '',
}),
}); });
expect(findMarkdownEditor().exists()).toBe(true); expect(findMarkdownEditor().exists()).toBe(false);
expect(findAddDesignDescriptionButton().exists()).toBe(true);
}); });
it('emits editor closed event and resets description text if empty when form is closed', async () => { it('renders description form when add a description button is clicked', async () => {
createComponent({ createComponent({
initiallyOpen: true, design: designFactory({
description: '',
descriptionHtml: '',
}),
}); });
expect(findAddDesignDescriptionButton().exists()).toBe(true);
expect(findMarkdownEditor().exists()).toBe(false);
await findAddDesignDescriptionButton().vm.$emit('click');
expect(findMarkdownEditor().exists()).toBe(true);
expect(findAddDesignDescriptionButton().exists()).toBe(false);
});
it('resets description text if empty when form is closed', async () => {
createComponent();
await findEditDescriptionButton().vm.$emit('click');
findMarkdownEditor().vm.$emit('input', ''); findMarkdownEditor().vm.$emit('input', '');
await findCancelDescriptionButton().vm.$emit('click'); await findCancelDescriptionButton().vm.$emit('click');
expect(wrapper.emitted('editorClosed')).toHaveLength(1);
expect(findDesignContent().text()).toEqual('Test description'); expect(findDesignContent().text()).toEqual('Test description');
}); });
...@@ -307,15 +327,26 @@ describe('Design description form', () => { ...@@ -307,15 +327,26 @@ describe('Design description form', () => {
}); });
describe('user has no updateDesign permission', () => { describe('user has no updateDesign permission', () => {
beforeEach(() => { it('does not render edit button', () => {
const designWithNoUpdateUserPermission = designFactory({ createComponent({
updateDesign: false, design: designFactory({
updateDesign: false,
}),
}); });
createComponent({ design: designWithNoUpdateUserPermission });
});
it('does not render edit button', () => {
expect(findEditDescriptionButton().exists()).toBe(false); expect(findEditDescriptionButton().exists()).toBe(false);
}); });
it('renders none when description is empty', () => {
createComponent({
design: designFactory({
description: '',
descriptionHtml: '',
updateDesign: false,
}),
});
expect(findDesignNoneBlock().text()).toEqual('None');
});
}); });
}); });
...@@ -48,7 +48,6 @@ describe('Design management design sidebar component', () => { ...@@ -48,7 +48,6 @@ describe('Design management design sidebar component', () => {
const findDescriptionForm = () => wrapper.findComponent(DescriptionForm); const findDescriptionForm = () => wrapper.findComponent(DescriptionForm);
const findEmptyState = () => wrapper.findComponent(GlEmptyState); const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findUnresolvedDiscussionsCount = () => wrapper.findByTestId('unresolved-discussion-count'); const findUnresolvedDiscussionsCount = () => wrapper.findByTestId('unresolved-discussion-count');
const findAddDesignDescriptionButton = () => wrapper.findByTestId('add-design-description');
function createComponent(props = {}) { function createComponent(props = {}) {
wrapper = shallowMountExtended(DesignSidebar, { wrapper = shallowMountExtended(DesignSidebar, {
...@@ -84,86 +83,19 @@ describe('Design management design sidebar component', () => { ...@@ -84,86 +83,19 @@ describe('Design management design sidebar component', () => {
expect(findDisclosure().exists()).toBe(true); expect(findDisclosure().exists()).toBe(true);
}); });
describe('description', () => { it('does not render description form when loading', () => {
it('renders add a description button when there is no description', () => { createComponent({ isLoading: true });
createComponent({
design: {
...design,
description: '',
descriptionHtml: '',
},
});
expect(findAddDesignDescriptionButton().exists()).toBe(true);
expect(findDescriptionForm().exists()).toBe(false);
});
it('does not render add a description button when there is no permission', () => {
createComponent({
design: {
...design,
issue: {
userPermissions: {
updateDesign: false,
},
},
},
});
expect(findAddDesignDescriptionButton().exists()).toBe(false);
});
it('renders description form when add a description button is clicked', async () => {
createComponent({
design: {
...design,
description: '',
descriptionHtml: '',
},
});
expect(findAddDesignDescriptionButton().exists()).toBe(true);
expect(findDescriptionForm().exists()).toBe(false);
await findAddDesignDescriptionButton().vm.$emit('click'); expect(findDescriptionForm().exists()).toBe(false);
});
expect(findDescriptionForm().exists()).toBe(true);
expect(findAddDesignDescriptionButton().exists()).toBe(false);
expect(findDescriptionForm().props('initiallyOpen')).toEqual(true);
});
it('renders description form when there is description', () => {
createComponent();
expect(findDescriptionForm().exists()).toBe(true);
expect(findAddDesignDescriptionButton().exists()).toBe(false);
});
it('renders description form with default props', () => {
createComponent();
expect(findDescriptionForm().props()).toMatchObject({
design,
markdownPreviewPath: 'markdown/path',
initiallyOpen: false,
designVariables: mockDesignVariables,
});
});
it('shows add a description button if editor is closed with empty description', async () => {
createComponent({
design: {
...design,
description: '',
descriptionHtml: '',
},
});
await findAddDesignDescriptionButton().vm.$emit('click');
await findDescriptionForm().vm.$emit('editorClosed'); it('renders description form with default props', () => {
createComponent();
expect(findAddDesignDescriptionButton().exists()).toBe(true); expect(findDescriptionForm().props()).toMatchObject({
design,
markdownPreviewPath: 'markdown/path',
designVariables: mockDesignVariables,
}); });
}); });
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment