Commit dbae9d73 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'kp-update-issuable-show-for-requirements' into 'master'

Update Issuable Show app components to use with Requirements

See merge request gitlab-org/gitlab!49925
parents fc5035f3 8b99ee5b
...@@ -36,10 +36,18 @@ export default { ...@@ -36,10 +36,18 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
enableAutosave: {
type: Boolean,
required: true,
},
editFormVisible: { editFormVisible: {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
showFieldTitle: {
type: Boolean,
required: true,
},
descriptionPreviewPath: { descriptionPreviewPath: {
type: String, type: String,
required: true, required: true,
...@@ -57,6 +65,14 @@ export default { ...@@ -57,6 +65,14 @@ export default {
return this.issuable.updatedBy; return this.issuable.updatedBy;
}, },
}, },
methods: {
handleKeydownTitle(e, issuableMeta) {
this.$emit('keydown-title', e, issuableMeta);
},
handleKeydownDescription(e, issuableMeta) {
this.$emit('keydown-description', e, issuableMeta);
},
},
}; };
</script> </script>
...@@ -67,8 +83,12 @@ export default { ...@@ -67,8 +83,12 @@ export default {
v-if="editFormVisible" v-if="editFormVisible"
:issuable="issuable" :issuable="issuable"
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
:enable-autosave="enableAutosave"
:show-field-title="showFieldTitle"
:description-preview-path="descriptionPreviewPath" :description-preview-path="descriptionPreviewPath"
:description-help-path="descriptionHelpPath" :description-help-path="descriptionHelpPath"
@keydown-title="handleKeydownTitle"
@keydown-description="handleKeydownDescription"
> >
<template #edit-form-actions="issuableMeta"> <template #edit-form-actions="issuableMeta">
<slot name="edit-form-actions" v-bind="issuableMeta"></slot> <slot name="edit-form-actions" v-bind="issuableMeta"></slot>
......
...@@ -23,6 +23,14 @@ export default { ...@@ -23,6 +23,14 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
enableAutosave: {
type: Boolean,
required: true,
},
showFieldTitle: {
type: Boolean,
required: true,
},
descriptionPreviewPath: { descriptionPreviewPath: {
type: String, type: String,
required: true, required: true,
...@@ -33,19 +41,27 @@ export default { ...@@ -33,19 +41,27 @@ export default {
}, },
}, },
data() { data() {
const { title, description } = this.issuable;
return { return {
title, title: '',
description, description: '',
}; };
}, },
watch: {
issuable: {
handler(value) {
this.title = value?.title || '';
this.description = value?.description || '';
},
deep: true,
immediate: true,
},
},
created() { created() {
eventHub.$on('update.issuable', this.resetAutosave); eventHub.$on('update.issuable', this.resetAutosave);
eventHub.$on('close.form', this.resetAutosave); eventHub.$on('close.form', this.resetAutosave);
}, },
mounted() { mounted() {
this.initAutosave(); if (this.enableAutosave) this.initAutosave();
}, },
beforeDestroy() { beforeDestroy() {
eventHub.$off('update.issuable', this.resetAutosave); eventHub.$off('update.issuable', this.resetAutosave);
...@@ -73,6 +89,12 @@ export default { ...@@ -73,6 +89,12 @@ export default {
this.autosaveTitle.reset(); this.autosaveTitle.reset();
this.autosaveDescription.reset(); this.autosaveDescription.reset();
}, },
handleKeydown(e, inputType) {
this.$emit(`keydown-${inputType}`, e, {
issuableTitle: this.title,
issuableDescription: this.description,
});
},
}, },
}; };
</script> </script>
...@@ -82,9 +104,9 @@ export default { ...@@ -82,9 +104,9 @@ export default {
<gl-form-group <gl-form-group
data-testid="title" data-testid="title"
:label="__('Title')" :label="__('Title')"
:label-sr-only="true" :label-sr-only="!showFieldTitle"
label-for="issuable-title" label-for="issuable-title"
class="col-12" class="col-12 gl-px-0"
> >
<gl-form-input <gl-form-input
id="issuable-title" id="issuable-title"
...@@ -94,14 +116,16 @@ export default { ...@@ -94,14 +116,16 @@ export default {
:aria-label="__('Title')" :aria-label="__('Title')"
:autofocus="true" :autofocus="true"
class="qa-title-input" class="qa-title-input"
@keydown="handleKeydown($event, 'title')"
/> />
</gl-form-group> </gl-form-group>
<gl-form-group <gl-form-group
data-testid="description" data-testid="description"
:label="__('Description')" :label="__('Description')"
:label-sr-only="true" :label-sr-only="!showFieldTitle"
label-for="issuable-description" label-for="issuable-description"
class="col-12 common-note-form" label-class="gl-pb-0!"
class="col-12 gl-px-0 common-note-form"
> >
<markdown-field <markdown-field
:markdown-preview-path="descriptionPreviewPath" :markdown-preview-path="descriptionPreviewPath"
...@@ -120,11 +144,12 @@ export default { ...@@ -120,11 +144,12 @@ export default {
class="note-textarea js-gfm-input js-autosize markdown-area class="note-textarea js-gfm-input js-autosize markdown-area
qa-description-textarea" qa-description-textarea"
dir="auto" dir="auto"
@keydown="handleKeydown($event, 'description')"
></textarea> ></textarea>
</template> </template>
</markdown-field> </markdown-field>
</gl-form-group> </gl-form-group>
<div data-testid="actions" class="col-12 gl-mt-3 gl-mb-3 clearfix"> <div data-testid="actions" class="col-12 gl-mt-3 gl-mb-3 gl-px-0 clearfix">
<slot <slot
name="edit-form-actions" name="edit-form-actions"
:issuable-title="title" :issuable-title="title"
......
...@@ -35,11 +35,21 @@ export default { ...@@ -35,11 +35,21 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
enableAutosave: {
type: Boolean,
required: false,
default: true,
},
editFormVisible: { editFormVisible: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
showFieldTitle: {
type: Boolean,
required: false,
default: false,
},
descriptionPreviewPath: { descriptionPreviewPath: {
type: String, type: String,
required: false, required: false,
...@@ -51,6 +61,14 @@ export default { ...@@ -51,6 +61,14 @@ export default {
default: '', default: '',
}, },
}, },
methods: {
handleKeydownTitle(e, issuableMeta) {
this.$emit('keydown-title', e, issuableMeta);
},
handleKeydownDescription(e, issuableMeta) {
this.$emit('keydown-description', e, issuableMeta);
},
},
}; };
</script> </script>
...@@ -77,10 +95,14 @@ export default { ...@@ -77,10 +95,14 @@ export default {
:status-icon="statusIcon" :status-icon="statusIcon"
:enable-edit="enableEdit" :enable-edit="enableEdit"
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
:enable-autosave="enableAutosave"
:edit-form-visible="editFormVisible" :edit-form-visible="editFormVisible"
:show-field-title="showFieldTitle"
:description-preview-path="descriptionPreviewPath" :description-preview-path="descriptionPreviewPath"
:description-help-path="descriptionHelpPath" :description-help-path="descriptionHelpPath"
@edit-issuable="$emit('edit-issuable', $event)" @edit-issuable="$emit('edit-issuable', $event)"
@keydown-title="handleKeydownTitle"
@keydown-description="handleKeydownDescription"
> >
<template #status-badge> <template #status-badge>
<slot name="status-badge"></slot> <slot name="status-badge"></slot>
......
...@@ -135,6 +135,33 @@ describe('IssuableBody', () => { ...@@ -135,6 +135,33 @@ describe('IssuableBody', () => {
expect(wrapper.emitted('edit-issuable')).toBeTruthy(); expect(wrapper.emitted('edit-issuable')).toBeTruthy();
}); });
it.each(['keydown-title', 'keydown-description'])(
'component emits `%s` event with event object and issuableMeta params via issuable-edit-form',
async eventName => {
const eventObj = {
preventDefault: jest.fn(),
stopPropagation: jest.fn(),
};
const issuableMeta = {
issuableTitle: 'foo',
issuableDescription: 'foobar',
};
wrapper.setProps({
editFormVisible: true,
});
await wrapper.vm.$nextTick();
const issuableEditForm = wrapper.find(IssuableEditForm);
issuableEditForm.vm.$emit(eventName, eventObj, issuableMeta);
expect(wrapper.emitted(eventName)).toBeTruthy();
expect(wrapper.emitted(eventName)[0]).toMatchObject([eventObj, issuableMeta]);
},
);
}); });
}); });
}); });
...@@ -41,6 +41,40 @@ describe('IssuableEditForm', () => { ...@@ -41,6 +41,40 @@ describe('IssuableEditForm', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('watch', () => {
describe('issuable', () => {
it('sets title and description to `issuable.title` and `issuable.description` when those values are available', async () => {
wrapper.setProps({
issuable: {
...issuableEditFormProps.issuable,
title: 'Foo',
description: 'Foobar',
},
});
await wrapper.vm.$nextTick();
expect(wrapper.vm.title).toBe('Foo');
expect(wrapper.vm.description).toBe('Foobar');
});
it('sets title and description to empty string when `issuable.title` and `issuable.description` is unavailable', async () => {
wrapper.setProps({
issuable: {
...issuableEditFormProps.issuable,
title: null,
description: null,
},
});
await wrapper.vm.$nextTick();
expect(wrapper.vm.title).toBe('');
expect(wrapper.vm.description).toBe('');
});
});
});
describe('created', () => { describe('created', () => {
it('binds `update.issuable` and `close.form` event listeners', () => { it('binds `update.issuable` and `close.form` event listeners', () => {
const eventOnSpy = jest.spyOn(IssuableEventHub, '$on'); const eventOnSpy = jest.spyOn(IssuableEventHub, '$on');
...@@ -118,5 +152,42 @@ describe('IssuableEditForm', () => { ...@@ -118,5 +152,42 @@ describe('IssuableEditForm', () => {
expect(actionsEl.find('button.js-save').exists()).toBe(true); expect(actionsEl.find('button.js-save').exists()).toBe(true);
expect(actionsEl.find('button.js-cancel').exists()).toBe(true); expect(actionsEl.find('button.js-cancel').exists()).toBe(true);
}); });
describe('events', () => {
const eventObj = {
preventDefault: jest.fn(),
stopPropagation: jest.fn(),
};
it('component emits `keydown-title` event with event object and issuableMeta params via gl-form-input', async () => {
const titleInputEl = wrapper.find(GlFormInput);
titleInputEl.vm.$emit('keydown', eventObj, 'title');
expect(wrapper.emitted('keydown-title')).toBeTruthy();
expect(wrapper.emitted('keydown-title')[0]).toMatchObject([
eventObj,
{
issuableTitle: wrapper.vm.title,
issuableDescription: wrapper.vm.description,
},
]);
});
it('component emits `keydown-description` event with event object and issuableMeta params via textarea', async () => {
const descriptionInputEl = wrapper.find('[data-testid="description"] textarea');
descriptionInputEl.trigger('keydown', eventObj, 'description');
expect(wrapper.emitted('keydown-description')).toBeTruthy();
expect(wrapper.emitted('keydown-description')[0]).toMatchObject([
eventObj,
{
issuableTitle: wrapper.vm.title,
issuableDescription: wrapper.vm.description,
},
]);
});
});
}); });
}); });
...@@ -118,6 +118,27 @@ describe('IssuableShowRoot', () => { ...@@ -118,6 +118,27 @@ describe('IssuableShowRoot', () => {
expect(wrapper.emitted('sidebar-toggle')).toBeTruthy(); expect(wrapper.emitted('sidebar-toggle')).toBeTruthy();
}); });
it.each(['keydown-title', 'keydown-description'])(
'component emits `%s` event with event object and issuableMeta params via issuable-body',
eventName => {
const eventObj = {
preventDefault: jest.fn(),
stopPropagation: jest.fn(),
};
const issuableMeta = {
issuableTitle: 'foo',
issuableDescription: 'foobar',
};
const issuableBody = wrapper.find(IssuableBody);
issuableBody.vm.$emit(eventName, eventObj, issuableMeta);
expect(wrapper.emitted(eventName)).toBeTruthy();
expect(wrapper.emitted(eventName)[0]).toMatchObject([eventObj, issuableMeta]);
},
);
}); });
}); });
}); });
...@@ -28,7 +28,9 @@ export const mockIssuableShowProps = { ...@@ -28,7 +28,9 @@ export const mockIssuableShowProps = {
descriptionPreviewPath: '/gitlab-org/gitlab-shell/preview_markdown', descriptionPreviewPath: '/gitlab-org/gitlab-shell/preview_markdown',
editFormVisible: false, editFormVisible: false,
enableAutocomplete: true, enableAutocomplete: true,
enableAutosave: true,
enableEdit: true, enableEdit: true,
showFieldTitle: false,
statusBadgeClass: 'status-box-open', statusBadgeClass: 'status-box-open',
statusIcon: 'issue-open-m', statusIcon: 'issue-open-m',
}; };
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