Commit 6a0965e3 authored by Derek Knox's avatar Derek Knox Committed by Enrique Alcántara

Initial edit-meta UI implementation

Added modal and controls components for
overall editing merge request metadata
parent 3a98d7a0
<script> <script>
import { GlForm, GlFormGroup, GlFormInput, GlFormTextarea } from '@gitlab/ui'; import { GlForm, GlFormGroup, GlFormInput, GlFormTextarea } from '@gitlab/ui';
import AccessorUtilities from '~/lib/utils/accessor';
export default { export default {
components: { components: {
...@@ -26,12 +27,47 @@ export default { ...@@ -26,12 +27,47 @@ export default {
}, },
}; };
}, },
computed: {
editableStorageKey() {
return this.getId('local-storage', 'editable');
},
hasLocalStorage() {
return AccessorUtilities.isLocalStorageAccessSafe();
},
},
mounted() {
this.initCachedEditable();
this.preSelect();
},
methods: { methods: {
getId(type, key) { getId(type, key) {
return `sse-merge-request-meta-${type}-${key}`; return `sse-merge-request-meta-${type}-${key}`;
}, },
initCachedEditable() {
if (this.hasLocalStorage) {
const cachedEditable = JSON.parse(localStorage.getItem(this.editableStorageKey));
if (cachedEditable) {
this.editable = cachedEditable;
}
}
},
preSelect() {
this.$nextTick(() => {
this.$refs.title.$el.select();
});
},
resetCachedEditable() {
if (this.hasLocalStorage) {
window.localStorage.removeItem(this.editableStorageKey);
}
},
onUpdate() { onUpdate() {
this.$emit('updateSettings', { ...this.editable }); const payload = { ...this.editable };
this.$emit('updateSettings', payload);
if (this.hasLocalStorage) {
window.localStorage.setItem(this.editableStorageKey, JSON.stringify(payload));
}
}, },
}, },
}; };
...@@ -46,6 +82,7 @@ export default { ...@@ -46,6 +82,7 @@ export default {
> >
<gl-form-input <gl-form-input
:id="getId('control', 'title')" :id="getId('control', 'title')"
ref="title"
v-model.lazy="editable.title" v-model.lazy="editable.title"
type="text" type="text"
@input="onUpdate" @input="onUpdate"
......
...@@ -35,6 +35,12 @@ export default { ...@@ -35,6 +35,12 @@ export default {
attributes: [{ variant: 'success' }, { disabled: this.disabled }], attributes: [{ variant: 'success' }, { disabled: this.disabled }],
}; };
}, },
secondaryProps() {
return {
text: __('Keep editing'),
attributes: [{ variant: 'default' }],
};
},
}, },
methods: { methods: {
hide() { hide() {
...@@ -43,6 +49,13 @@ export default { ...@@ -43,6 +49,13 @@ export default {
show() { show() {
this.$refs.modal.show(); this.$refs.modal.show();
}, },
onPrimary() {
this.$emit('primary', this.mergeRequestMeta);
this.$refs.editMetaControls.resetCachedEditable();
},
onSecondary() {
this.hide();
},
onUpdateSettings(mergeRequestMeta) { onUpdateSettings(mergeRequestMeta) {
this.mergeRequestMeta = { ...mergeRequestMeta }; this.mergeRequestMeta = { ...mergeRequestMeta };
}, },
...@@ -56,11 +69,14 @@ export default { ...@@ -56,11 +69,14 @@ export default {
modal-id="edit-meta-modal" modal-id="edit-meta-modal"
:title="__('Submit your changes')" :title="__('Submit your changes')"
:action-primary="primaryProps" :action-primary="primaryProps"
:action-secondary="secondaryProps"
size="sm" size="sm"
@primary="() => $emit('primary', mergeRequestMeta)" @primary="onPrimary"
@secondary="onSecondary"
@hide="() => $emit('hide')" @hide="() => $emit('hide')"
> >
<edit-meta-controls <edit-meta-controls
ref="editMetaControls"
:title="mergeRequestMeta.title" :title="mergeRequestMeta.title"
:description="mergeRequestMeta.description" :description="mergeRequestMeta.description"
@updateSettings="onUpdateSettings" @updateSettings="onUpdateSettings"
......
---
title: Preserve the merge request title and description in the static site editor upon modal close
merge_request: 44512
author:
type: added
...@@ -14750,6 +14750,9 @@ msgstr "" ...@@ -14750,6 +14750,9 @@ msgstr ""
msgid "Keep divergent refs" msgid "Keep divergent refs"
msgstr "" msgstr ""
msgid "Keep editing"
msgstr ""
msgid "Kerberos access denied" msgid "Kerberos access denied"
msgstr "" msgstr ""
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { GlFormInput, GlFormTextarea } from '@gitlab/ui'; import { GlFormInput, GlFormTextarea } from '@gitlab/ui';
import EditMetaControls from '~/static_site_editor/components/edit_meta_controls.vue'; import EditMetaControls from '~/static_site_editor/components/edit_meta_controls.vue';
import { mergeRequestMeta } from '../mock_data'; import { mergeRequestMeta } from '../mock_data';
describe('~/static_site_editor/components/edit_meta_modal.vue', () => { describe('~/static_site_editor/components/edit_meta_controls.vue', () => {
useLocalStorageSpy();
let wrapper; let wrapper;
let mockSelect;
let mockGlFormInputTitleInstance;
const { title, description } = mergeRequestMeta; const { title, description } = mergeRequestMeta;
const newTitle = 'New title';
const newDescription = 'New description';
const buildWrapper = (propsData = {}) => { const buildWrapper = (propsData = {}) => {
wrapper = shallowMount(EditMetaControls, { wrapper = shallowMount(EditMetaControls, {
...@@ -20,11 +27,18 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => { ...@@ -20,11 +27,18 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => {
}); });
}; };
const buildMocks = () => {
mockSelect = jest.fn();
mockGlFormInputTitleInstance = { $el: { select: mockSelect } };
wrapper.vm.$refs.title = mockGlFormInputTitleInstance;
};
const findGlFormInputTitle = () => wrapper.find(GlFormInput); const findGlFormInputTitle = () => wrapper.find(GlFormInput);
const findGlFormTextAreaDescription = () => wrapper.find(GlFormTextarea); const findGlFormTextAreaDescription = () => wrapper.find(GlFormTextarea);
beforeEach(() => { beforeEach(() => {
buildWrapper(); buildWrapper();
buildMocks();
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -50,23 +64,36 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => { ...@@ -50,23 +64,36 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => {
expect(findGlFormTextAreaDescription().attributes().value).toBe(description); expect(findGlFormTextAreaDescription().attributes().value).toBe(description);
}); });
it('emits updated settings when title input updates', () => { it('calls select on the title input when mounted', () => {
const newTitle = 'New title'; expect(mockGlFormInputTitleInstance.$el.select).toHaveBeenCalled();
});
findGlFormInputTitle().vm.$emit('input', newTitle); describe('when inputs change', () => {
const storageKey = 'sse-merge-request-meta-local-storage-editable';
const newSettings = { description, title: newTitle }; afterEach(() => {
localStorage.removeItem(storageKey);
});
expect(wrapper.emitted('updateSettings')[0][0]).toMatchObject(newSettings); it.each`
}); findFn | key | value
${findGlFormInputTitle} | ${'title'} | ${newTitle}
${findGlFormTextAreaDescription} | ${'description'} | ${newDescription}
`('emits updated settings when $findFn input updates', ({ key, value, findFn }) => {
findFn().vm.$emit('input', value);
const newSettings = { ...mergeRequestMeta, [key]: value };
it('emits updated settings when description textarea updates', () => { expect(wrapper.emitted('updateSettings')[0][0]).toMatchObject(newSettings);
const newDescription = 'New description'; });
findGlFormTextAreaDescription().vm.$emit('input', newDescription); it('should remember the input changes', () => {
findGlFormInputTitle().vm.$emit('input', newTitle);
findGlFormTextAreaDescription().vm.$emit('input', newDescription);
const newSettings = { description: newDescription, title }; const newSettings = { title: newTitle, description: newDescription };
expect(wrapper.emitted('updateSettings')[0][0]).toMatchObject(newSettings); expect(localStorage.setItem).toHaveBeenCalledWith(storageKey, JSON.stringify(newSettings));
});
}); });
}); });
...@@ -9,6 +9,8 @@ import { sourcePath, mergeRequestMeta } from '../mock_data'; ...@@ -9,6 +9,8 @@ import { sourcePath, mergeRequestMeta } from '../mock_data';
describe('~/static_site_editor/components/edit_meta_modal.vue', () => { describe('~/static_site_editor/components/edit_meta_modal.vue', () => {
let wrapper; let wrapper;
let resetCachedEditable;
let mockEditMetaControlsInstance;
const { title, description } = mergeRequestMeta; const { title, description } = mergeRequestMeta;
const buildWrapper = (propsData = {}) => { const buildWrapper = (propsData = {}) => {
...@@ -20,11 +22,18 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => { ...@@ -20,11 +22,18 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => {
}); });
}; };
const buildMocks = () => {
resetCachedEditable = jest.fn();
mockEditMetaControlsInstance = { resetCachedEditable };
wrapper.vm.$refs.editMetaControls = mockEditMetaControlsInstance;
};
const findGlModal = () => wrapper.find(GlModal); const findGlModal = () => wrapper.find(GlModal);
const findEditMetaControls = () => wrapper.find(EditMetaControls); const findEditMetaControls = () => wrapper.find(EditMetaControls);
beforeEach(() => { beforeEach(() => {
buildWrapper(); buildWrapper();
buildMocks();
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -59,6 +68,11 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => { ...@@ -59,6 +68,11 @@ describe('~/static_site_editor/components/edit_meta_modal.vue', () => {
expect(wrapper.emitted('primary')).toEqual([[mergeRequestMeta]]); expect(wrapper.emitted('primary')).toEqual([[mergeRequestMeta]]);
}); });
it('calls resetCachedEditable on EditMetaControls when primary emits', () => {
findGlModal().vm.$emit('primary', mergeRequestMeta);
expect(mockEditMetaControlsInstance.resetCachedEditable).toHaveBeenCalled();
});
it('emits the hide event', () => { it('emits the hide event', () => {
findGlModal().vm.$emit('hide'); findGlModal().vm.$emit('hide');
expect(wrapper.emitted('hide')).toEqual([[]]); expect(wrapper.emitted('hide')).toEqual([[]]);
......
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