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