From e0424b960315b8328f7da96f9d5bc58f2628cd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 30 Apr 2018 15:30:59 +0200 Subject: [PATCH] [FIX] web: fix form_view_id attribute in calendar view. The way the calendar view selected its form view was broken for two reasons: - any value given in the form_view_id attribute was kept as string, which means that the string value would be sent to the server, and this is not good. - if no value was set, the calendar view then simply did a do_action with the form view id set to false, which means that the default form view is used. This is mostly ok, except when we are in the context of an action with a form view which is not the default one. In that case, we clearly prefer the form view from the action. For example, before this commit, the form view in the timesheet application (community) is not the same as the default form view on account.analytic.line. Note that this commit also adds a small tweak to the mock server to better simulate errors like the web client does (in session.js). --- .../src/js/views/calendar/calendar_view.js | 16 +++- .../web/static/tests/helpers/mock_server.js | 4 +- .../web/static/tests/views/calendar_tests.js | 95 +++++++++++++++++++ doc/reference/views.rst | 4 +- 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/addons/web/static/src/js/views/calendar/calendar_view.js b/addons/web/static/src/js/views/calendar/calendar_view.js index 7f58ca55632..bfeb5c5cbbb 100644 --- a/addons/web/static/src/js/views/calendar/calendar_view.js +++ b/addons/web/static/src/js/views/calendar/calendar_view.js @@ -112,8 +112,20 @@ var CalendarView = AbstractView.extend({ //if quick_add = is NOT False and IS specified in view, we this one for widgets.QuickCreate' this.controllerParams.quickAddPop = (!('quick_add' in attrs) || utils.toBoolElse(attrs.quick_add+'', true)); this.controllerParams.disableQuickCreate = params.disable_quick_create || !this.controllerParams.quickAddPop; - // If this field is set ot true, we don't open the event in form view, but in a popup with the view_id passed by this parameter - this.controllerParams.formViewId = !attrs.form_view_id || !utils.toBoolElse(attrs.form_view_id, true) ? false : attrs.form_view_id; + + // If form_view_id is set, then the calendar view will open a form view + // with this id, when it needs to edit or create an event. + this.controllerParams.formViewId = + attrs.form_view_id ? parseInt(attrs.form_view_id, 10) : false; + if (!this.controllerParams.formViewId && params.action) { + var formViewDescr = _.find(params.action.views, function (v) { + return v[1] === 'form'; + }); + if (formViewDescr) { + this.controllerParams.formViewId = formViewDescr[0]; + } + } + this.controllerParams.readonlyFormViewId = !attrs.readonly_form_view_id || !utils.toBoolElse(attrs.readonly_form_view_id, true) ? false : attrs.readonly_form_view_id; this.controllerParams.eventOpenPopup = utils.toBoolElse(attrs.event_open_popup || '', false); this.controllerParams.mapping = mapping; diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index a47cd71fe48..08f3bb95c77 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -110,14 +110,14 @@ var MockServer = Class.extend({ console.log('%c[rpc] response' + route, 'color: blue; font-weight: bold;', JSON.parse(resultString)); } return JSON.parse(resultString); - }).fail(function (result) { + }, function (result, event) { var errorString = JSON.stringify(result || false); if (logLevel === 1) { console.log('Mock: (ERROR)' + route, JSON.parse(errorString)); } else if (logLevel === 2) { console.log('%c[rpc] response (error) ' + route, 'color: orange; font-weight: bold;', JSON.parse(errorString)); } - return JSON.parse(errorString); + return $.Deferred().reject(errorString, event || $.Event()); }); }, diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index b6bebc0f4a2..4840e05af02 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -1766,6 +1766,101 @@ QUnit.module('Views', { calendar.destroy(); }); + + QUnit.test('form_view_id attribute works (for creating events)', function (assert) { + assert.expect(1); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: ''+ + ''+ + '', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + mockRPC: function (route, args) { + if (args.method === "create") { + // we simulate here the case where a create call with just + // the field name fails. This is a normal flow, the server + // reject the create rpc (quick create), then the web client + // fall back to a form view. This happens typically when a + // model has required fields + return $.Deferred().reject('None shall pass!'); + } + return this._super(route, args); + }, + intercepts: { + do_action: function (event) { + assert.strictEqual(event.data.action.views[0][0], 42, + "should do a do_action with view id 42"); + }, + }, + }); + + var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); + testUtils.triggerMouseEvent($cell, "mousedown"); + testUtils.triggerMouseEvent($cell, "mouseup"); + var $input = $('.modal-body input:first'); + $input.val("It's just a fleshwound").trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + + calendar.destroy(); + }); + + QUnit.test('calendar fallback to form view id in action if necessary', function (assert) { + assert.expect(1); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: ' '+ + ''+ + '', + archs: archs, + viewOptions: { + initialDate: initialDate, + action: {views: [[1, 'kanban'], [43, 'form']]} + }, + mockRPC: function (route, args) { + if (args.method === "create") { + // we simulate here the case where a create call with just + // the field name fails. This is a normal flow, the server + // reject the create rpc (quick create), then the web client + // fall back to a form view. This happens typically when a + // model has required fields + return $.Deferred().reject('None shall pass!'); + } + return this._super(route, args); + }, + intercepts: { + do_action: function (event) { + assert.strictEqual(event.data.action.views[0][0], 43, + "should do a do_action with view id 43"); + }, + }, + }); + + var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); + testUtils.triggerMouseEvent($cell, "mousedown"); + testUtils.triggerMouseEvent($cell, "mouseup"); + var $input = $('.modal-body input:first'); + $input.val("It's just a fleshwound").trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + + calendar.destroy(); + }); + }); }); diff --git a/doc/reference/views.rst b/doc/reference/views.rst index d53ff2b6ce7..d23a0db9da3 100644 --- a/doc/reference/views.rst +++ b/doc/reference/views.rst @@ -954,7 +954,9 @@ calendar view are: ``readonly_form_view_id`` view to open in readonly mode ``form_view_id`` - view to open when the user create or edit an event + view to open when the user create or edit an event. Note that if this attribute + is not set, the calendar view will fall back to the id of the form view in the + current action, if any. ``event_open_popup`` If the option 'event_open_popup' is set to true, then the calendar view will open events (or records) in a FormViewDialog. Otherwise, it will open events