From 8fe0705349ef4f44d18b9ce86410a90334371cc4 Mon Sep 17 00:00:00 2001 From: Noor Syed Date: Thu, 10 Oct 2024 14:33:03 -0400 Subject: [PATCH] RDISCROWD-7088 Ownership ID v2 (#470) * update ownership_id handling * error handling * update test * lint * lint --- .../components/setting/ownership_setting.vue | 80 ++++++++++++++----- .../setting/ownship_setting.spec.js | 18 ++--- templates/projects/summary.webpack.ejs | 3 + 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/static/src/components/setting/ownership_setting.vue b/static/src/components/setting/ownership_setting.vue index 2b1f9a4b..246a509a 100644 --- a/static/src/components/setting/ownership_setting.vue +++ b/static/src/components/setting/ownership_setting.vue @@ -194,14 +194,17 @@ export default { contactResult: [], coownerQuery: '', contactQuery: '', - ownership_id: {}, - ownership_id_title: 'Ownership ID', - waiting: false + ownershipId: '', + ownershipIdTitle: 'Ownership ID', + waiting: false, + projectId: '' }; }, created () { this.getData(); + this.getOwnershipIdTitle(); + this.getProjectId(); }, methods: { @@ -221,13 +224,35 @@ export default { return users; }, - getURL (keyword) { + getCoownersURL () { let path = window.location.pathname; let res = path.split('/'); - res[res.length - 1] = keyword; + res[res.length - 1] = 'coowners'; return res.join('/'); }, + getProjectApiURL () { + return `/api/project/${this.projectId}`; + }, + + getOwnershipIdTitle () { + let element = document.getElementById('ownership-id-title'); + if (element == null) { + window.pybossaNotify('An error occurred.', true, 'error'); + return; + } + this.ownershipIdTitle = element.innerText; + }, + + getProjectId () { + let element = document.getElementById('project-id'); + if (element == null) { + window.pybossaNotify('An error occurred.', true, 'error'); + return; + } + this.projectId = element.innerText; + }, + async search (user, contact) { // Reset and hide drop-downs with search results. this.coownerResult = []; @@ -237,8 +262,7 @@ export default { } else { this.contactQuery = null; } - - const res = await fetch(this.getURL('coowners'), { + const res = await fetch(this.getCoownersURL(), { method: 'POST', headers: { 'content-type': 'application/json', @@ -258,7 +282,7 @@ export default { async getData () { this.waiting = true; try { - const res = await fetch(this.getURL('coowners'), { + const res = await fetch(this.getCoownersURL(), { method: 'GET', headers: { 'content-type': 'application/json' @@ -271,7 +295,7 @@ export default { window.pybossaNotify('An error occurred.', true, 'error'); } try { - const res = await fetch(this.getURL('ownership_id'), { + const res = await fetch(this.getProjectApiURL(), { method: 'GET', headers: { 'content-type': 'application/json' @@ -279,8 +303,7 @@ export default { credentials: 'same-origin' }); const data = await res.json(); - this.ownership_id = data.ownership_id; - this.ownership_id_title = data.title; + this.ownershipId = data.info.ownership_id == null ? '' : data.info.ownership_id; } catch (error) { window.pybossaNotify('An error occurred.', true, 'error'); } finally { @@ -306,6 +329,12 @@ export default { Vue.delete(this.contacts, id); }, + validateOwnershipId () { + let reg = new RegExp('^[0-9]+$'); + return this.ownershipId.length === 0 || + (reg.test(this.ownershipId) && this.ownershipId.length <= 20); + }, + async searchCoowners () { try { if (this.coownerQuery) { @@ -331,6 +360,11 @@ export default { }, async save () { + if (!this.validateOwnershipId()) { + window.pybossaNotify(`${this.ownershipIdTitle} must be numeric and less than 20 characters!`, true, 'error'); + return; + } + const coowners = Object.keys(this.coowners); const contacts = Object.keys(this.contacts); // Reset and hide drop-downs with search results. @@ -339,9 +373,8 @@ export default { this.coownerQuery = null; this.contactQuery = null; this.waiting = true; - try { - const res = await fetch(this.getURL('coowners'), { + const res = await fetch(this.getCoownersURL(), { method: 'POST', headers: { 'content-type': 'application/json', @@ -365,19 +398,23 @@ export default { window.pybossaNotify('An error occurred configuring ownership config.', true, 'error'); } try { - const res = await fetch(this.getURL('ownership_id'), { + let body = { + 'info': { + 'ownership_id': this.ownershipId + } + }; + const res = await fetch(this.getProjectApiURL(), { method: 'PUT', headers: { 'content-type': 'application/json', 'X-CSRFToken': this.csrfToken }, credentials: 'same-origin', - body: JSON.stringify({ ownership_id: this.ownership_id }) + body: JSON.stringify(body) }); if (res.ok) { const data = await res.json(); - this.ownership_id = data.ownership_id; - window.pybossaNotify(data['flash'], true, data['status']); + this.ownershipId = data.info.ownership_id; } else { window.pybossaNotify('An error occurred configuring ownership id.', true, 'error'); } @@ -396,14 +433,17 @@ export default { font-size: 100%; margin-right: 10px } + .fa-times { - margin-left:3px; - color:silver + margin-left: 3px; + color: silver } + .fa-times:hover { color: red } + .form-control.input-sm { - width: 280px; + width: 280px; } diff --git a/static/src/test/components/setting/ownship_setting.spec.js b/static/src/test/components/setting/ownship_setting.spec.js index a17e482e..ff123c0e 100644 --- a/static/src/test/components/setting/ownship_setting.spec.js +++ b/static/src/test/components/setting/ownship_setting.spec.js @@ -27,7 +27,7 @@ describe('ownershipConfig', () => { const wrapper = shallowMount(ownershipConfig); await localVue.nextTick(); expect(fetch.mock.calls).toHaveLength(2); - expect(notify.mock.calls).toHaveLength(0); + expect(notify.mock.calls).toHaveLength(2); expect(wrapper.vm._data.owner.id).toBe(1); expect(Object.keys(wrapper.vm._data.coowners)).toHaveLength(1); expect(Object.keys(wrapper.vm._data.contacts)).toHaveLength(1); @@ -81,7 +81,7 @@ describe('ownershipConfig', () => { searchButton.trigger('click'); await localVue.nextTick(); expect(wrapper.findAll('p')).toHaveLength(9); // valid search results - expect(notify.mock.calls).toHaveLength(0); // no error alert + expect(notify.mock.calls).toHaveLength(2); // no error alert }); it('search users invalid', async () => { @@ -97,8 +97,8 @@ describe('ownershipConfig', () => { const searchButton = wrapper.findAll('button').at(0); // Search users button searchButton.trigger('click'); await localVue.nextTick(); - expect(notify.mock.calls).toHaveLength(2); // no search results - expect(notify.mock.calls[0][0]).toEqual('Please enter a search query.'); // error alert + expect(notify.mock.calls).toHaveLength(4); // no search results + expect(notify.mock.calls[2][0]).toEqual('Please enter a search query.'); // error alert }); it('search contacts', async () => { @@ -129,7 +129,7 @@ describe('ownershipConfig', () => { searchButton.trigger('click'); await localVue.nextTick(); expect(wrapper.findAll('p')).toHaveLength(9); // valid search results - expect(notify.mock.calls).toHaveLength(0); // no error alert + expect(notify.mock.calls).toHaveLength(2); // no error alert }); it('search contacts invalid', async () => { @@ -145,8 +145,8 @@ describe('ownershipConfig', () => { const searchButton = wrapper.findAll('button').at(1); // Search contacts button searchButton.trigger('click'); await localVue.nextTick(); - expect(notify.mock.calls).toHaveLength(2); // no search results - expect(notify.mock.calls[0][0]).toEqual('Please enter a search query.'); // error alert + expect(notify.mock.calls).toHaveLength(4); // no search results + expect(notify.mock.calls[2][0]).toEqual('Please enter a search query.'); // error alert }); it('add coowners', async () => { @@ -226,7 +226,7 @@ describe('ownershipConfig', () => { saveButton.trigger('click'); await localVue.nextTick(); expect(fetch.mock.calls).toHaveLength(4); - expect(notify.mock.calls).toHaveLength(4); + expect(notify.mock.calls).toHaveLength(6); }); it('saves config fails', async () => { @@ -242,6 +242,6 @@ describe('ownershipConfig', () => { saveButton.trigger('click'); await localVue.nextTick(); expect(fetch.mock.calls).toHaveLength(4); - expect(notify.mock.calls).toHaveLength(4); + expect(notify.mock.calls).toHaveLength(6); }); }); diff --git a/templates/projects/summary.webpack.ejs b/templates/projects/summary.webpack.ejs index f313d49c..549113c2 100644 --- a/templates/projects/summary.webpack.ejs +++ b/templates/projects/summary.webpack.ejs @@ -13,6 +13,9 @@
+ + +