From fa48e05f42492fdca7fd371bca1b2643b50e4ac0 Mon Sep 17 00:00:00 2001 From: jbm-odoo Date: Mon, 9 Dec 2019 13:11:36 +0000 Subject: [PATCH] [IMP] calendar: Improve color and filters Now in a calendar view, if we use the color, attribute, it will use the same color as Gantt views and the color picker widget. The attribute color isn't more set as default in filter because it make, in most situation, no sense to filter by color. Now, we can add new filters in the right panel. To do that, we must add the attribute "filter='1'" in the corresponding field line. And if the filter has no direct link with the color of the model, we can specify an attribute 'color' for this filter line block. (for example color='color', and the color of the related model will be used) TaskID: 2153249 --- addons/calendar/views/calendar_views.xml | 2 +- .../src/js/views/calendar/calendar_model.js | 36 +++++++++++- .../js/views/calendar/calendar_renderer.js | 3 + .../src/js/views/calendar/calendar_view.js | 28 ++++++---- addons/web/static/src/scss/web_calendar.scss | 6 +- .../web/static/tests/views/calendar_tests.js | 55 +++++++++++++++++++ doc/reference/views.rst | 3 + 7 files changed, 116 insertions(+), 17 deletions(-) diff --git a/addons/calendar/views/calendar_views.xml b/addons/calendar/views/calendar_views.xml index 0bf7f52984c..d15b7f6f356 100644 --- a/addons/calendar/views/calendar_views.xml +++ b/addons/calendar/views/calendar_views.xml @@ -263,7 +263,7 @@ event_limit="5" color="partner_id"> - + diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index 2f2c6339ac6..9635fc5ffc4 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -579,6 +579,8 @@ return AbstractModel.extend({ var self = this; var new_filters = {}; var to_read = {}; + var defs = []; + var color_filter = {}; _.each(this.data.filters, function (filter, fieldName) { var field = self.fields[fieldName]; @@ -620,7 +622,7 @@ return AbstractModel.extend({ }); }); _.each(_.union(fs, undefined_fs), function (f) { - var f1 = _.findWhere(filter.filters, f); + var f1 = _.findWhere(filter.filters, _.omit(f, 'color_index')); if (f1) { f1.display = true; } else { @@ -628,9 +630,32 @@ return AbstractModel.extend({ filter.filters.push(f); } }); + + if (filter.color_model && filter.field_color) { + var ids = filter.filters.reduce((acc, f) => { + if (!f.color_index && f.value) { + acc.push(f.value); + } + return acc; + }, []); + if (!color_filter[filter.color_model]) { + color_filter[filter.color_model] = {}; + } + if (ids.length) { + defs.push(self._rpc({ + model: filter.color_model, + method: 'read', + args: [_.uniq(ids), [filter.field_color]], + }) + .then(function (res) { + _.each(res, function (c) { + color_filter[filter.color_model][c.id] = c[filter.field_color]; + }); + })); + } + } }); - var defs = []; _.each(to_read, function (ids, model) { defs.push(self._rpc({ model: model, @@ -651,6 +676,13 @@ return AbstractModel.extend({ f.label = to_read[f.avatar_model][f.value]; }); } + if (filter.color_model && filter.field_color) { + _.each(filter.filters, function (f) { + if (!f.color_index) { + f.color_index = color_filter[filter.color_model] && color_filter[filter.color_model][f.value]; + } + }); + } }); }); }, diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js index f563f793203..7755097d412 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -284,6 +284,9 @@ return AbstractRenderer.extend({ if (typeof key === 'string' && key.match(/^((#[A-F0-9]{3})|(#[A-F0-9]{6})|((hsl|rgb)a?\(\s*(?:(\s*\d{1,3}%?\s*),?){3}(\s*,[0-9.]{1,4})?\))|)$/i)) { return this.color_map[key] = key; } + if (typeof key === 'number' && !(key in this.color_map)) { + return this.color_map[key] = key; + } var index = (((_.keys(this.color_map).length + 1) * 5) % 24) + 1; this.color_map[key] = index; return index; 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 9c9355145ee..b68a134a00a 100644 --- a/addons/web/static/src/js/views/calendar/calendar_view.js +++ b/addons/web/static/src/js/views/calendar/calendar_view.js @@ -92,23 +92,29 @@ var CalendarView = AbstractView.extend({ modelFilters.push(fields[fieldName].relation); } + if (child.attrs.filter) { + filters[fieldName] = filters[fieldName] || { + 'title': fields[fieldName].string, + 'fieldName': fieldName, + 'filters': [], + }; + if (child.attrs.color) { + filters[fieldName].field_color = child.attrs.color; + filters[fieldName].color_model = fields[fieldName].relation; + } + if (!child.attrs.avatar_field && fields[fieldName].relation) { + if (fields[fieldName].relation.includes(['res.users', 'res.partner', 'hr.employee'])) { + filters[fieldName].avatar_field = 'image_128'; + } + filters[fieldName].avatar_model = fields[fieldName].relation; + } + } } }); if (attrs.color) { var fieldName = attrs.color; fieldNames.push(fieldName); - filters[fieldName] = { - 'title': fields[fieldName].string, - 'fieldName': fieldName, - 'filters': [], - }; - if (fields[fieldName].relation) { - if (['res.users', 'res.partner', 'hr.employee'].indexOf(fields[fieldName].relation) !== -1) { - filters[fieldName].avatar_field = 'image_128'; - } - filters[fieldName].avatar_model = fields[fieldName].relation; - } } //if quick_add = False, we don't allow quick_add diff --git a/addons/web/static/src/scss/web_calendar.scss b/addons/web/static/src/scss/web_calendar.scss index 6f7c569feb6..c81bf92ec47 100644 --- a/addons/web/static/src/scss/web_calendar.scss +++ b/addons/web/static/src/scss/web_calendar.scss @@ -588,7 +588,7 @@ $o-cw-filter-avatar-size: 20px; $color: nth($o-colors-complete, $i); .o_calendar_view .fc-view { - .fc-event.o_calendar_color_#{$i} { + .fc-event.o_calendar_color_#{$i - 1} { border-color: $color; color: darken($color, 35%); opacity: 0.8; @@ -616,7 +616,7 @@ $o-cw-filter-avatar-size: 20px; } } - .o_cw_filter_color_#{$i} { + .o_cw_filter_color_#{$i - 1} { .o_cw_filter_input_bg { border-color: $color; background: $color; @@ -624,7 +624,7 @@ $o-cw-filter-avatar-size: 20px; } } - .o_cw_popover.o_calendar_color_#{$i} { + .o_cw_popover.o_calendar_color_#{$i - 1} { $color-subdle: mix(white, $color, 90%); .card-header, .card-header .popover-header { diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 0bdddb7bfae..8286bb6b4cc 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -54,6 +54,8 @@ QUnit.module('Views', { allday: {string: "allday", type: "boolean"}, partner_ids: {string: "attendees", type: "one2many", relation: 'partner', default: [[6, 0, [1]]]}, type: {string: "type", type: "integer"}, + event_type_id: {string: "Event_Type", type: "many2one", relation: 'event_type'}, + color: {string: "Color", type: "integer", related: 'event_type_id.color'}, }, records: [ {id: 1, user_id: session.uid, partner_id: 1, name: "event 1", start: "2016-12-11 00:00:00", stop: "2016-12-11 00:00:00", allday: false, partner_ids: [1,2,3], type: 1}, @@ -92,6 +94,18 @@ QUnit.module('Views', { {id: 4, display_name: "partner 4", image: 'DDD'} ] }, + event_type: { + fields: { + id: {string: "ID", type: "integer"}, + display_name: {string: "Displayed name", type: "char"}, + color: {string: "Color", type: "integer"}, + }, + records: [ + {id: 1, display_name: "Event Type 1", color: 1}, + {id: 2, display_name: "Event Type 2", color: 2}, + {id: 3, display_name: "Event Type 3 (color 4)", color: 4}, + ] + }, filter_partner: { fields: { id: {string: "ID", type: "integer"}, @@ -1973,6 +1987,47 @@ QUnit.module('Views', { calendar.destroy(); }); + QUnit.test('Add filters and specific color', async function (assert) { + assert.expect(5); + + this.data.event.records.push( + {id: 7, user_id: 4, partner_id: 1, name: "event 7", start: "2016-12-11 09:00:00", stop: "2016-12-11 10:00:00", allday: false, partner_ids: [1,2,3], event_type_id: 3, color: 4}, + {id: 8, user_id: 4, partner_id: 1, name: "event 8", start: "2016-12-11 19:00:00", stop: "2016-12-11 20:00:00", allday: false, partner_ids: [1,2,3], event_type_id: 1, color: 1}, + ); + + var calendar = await createCalendarView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + ''+ + ''+ + ''+ + '', + viewOptions: { + initialDate: initialDate, + }, + }); + + assert.containsN(calendar, '.o_calendar_filter', 2, "should display 2 filters"); + + var $typeFilter = calendar.$('.o_calendar_filter:has(h5:contains(Event_Type))'); + assert.ok($typeFilter.length, "should display 'Event Type' filter"); + assert.containsN($typeFilter, '.o_calendar_filter_item', 3, "should display 3 filter items for 'Event Type'"); + + assert.containsOnce($typeFilter, '.o_calendar_filter_item[data-value=3].o_cw_filter_color_4', "Filter for event type 3 must have the color 4"); + + assert.containsOnce(calendar, '.fc-event[data-event-id=7].o_calendar_color_4', "Event of event type 3 must have the color 4"); + + calendar.destroy(); + }); + QUnit.test('create event with filters', async function (assert) { assert.expect(7); diff --git a/doc/reference/views.rst b/doc/reference/views.rst index af84421ea91..4a4ab2f1206 100644 --- a/doc/reference/views.rst +++ b/doc/reference/views.rst @@ -927,6 +927,9 @@ calendar view are: ``write_model`` and ``write_field`` you can add a filter and save the result in the defined model, the filter is added in the sidebar + ``filter`` and ``color`` + use "True" to add this field in filter in the sidebar. You can specify + a color field used to colorize the checkbox. ``templates`` defines the :ref:`reference/qweb` template ``calendar-box``. Cards definition