[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
This commit is contained in:
jbm-odoo
2020-01-27 16:08:34 +00:00
committed by Yannick Tivisse
parent d39fc89324
commit fa48e05f42
7 changed files with 116 additions and 17 deletions
+1 -1
View File
@@ -263,7 +263,7 @@
event_limit="5"
color="partner_id">
<field name="attendee_status"/>
<field name="partner_id"/>
<field name="partner_id" filter="1"/>
<field name="partner_ids" widget="many2many_tags_avatar" write_model="calendar.contacts" write_field="partner_id" avatar_field="image_128"/>
<field name="is_highlighted" invisible="1"/>
<field name="description"/>
@@ -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];
}
});
}
});
});
},
@@ -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;
@@ -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
+3 -3
View File
@@ -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 {
@@ -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:
'<calendar class="o_calendar_test" '+
'event_open_popup="true" '+
'date_start="start" '+
'date_stop="stop" '+
'all_day="allday" '+
'mode="week" '+
'color="color">'+
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
'<field name="event_type_id" filters="1" color="color"/>'+
'</calendar>',
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);
+3
View File
@@ -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