[IMP] calendar change view grammar.

* Remove filter tag
* Use color attribute on the view who add a filter/legend
* Filter is automatically added when 'avatar_field' option is used on a
field tag, and the default template display the avatar.
* Can overwrite the template (add tag template who contains qweb with
<t t-name="calendar-box">...</t>
This commit is contained in:
Christophe Matthieu
2017-04-11 19:44:38 +02:00
committed by Aaron Bohy
parent bf320d2a0d
commit 09731b7860
24 changed files with 87 additions and 141 deletions
@@ -7,10 +7,9 @@
<field name="name">account.invoice.calendar</field>
<field name="model">account.invoice</field>
<field name="arch" type="xml">
<calendar string="Invoices" date_start="date_invoice">
<calendar string="Invoices" date_start="date_invoice" color="journal_id">
<field name="partner_id"/>
<field name="amount_total_signed"/>
<filter name="journal_id" color="True"/>
</calendar>
</field>
</record>
+1 -8
View File
@@ -742,10 +742,8 @@ class Meeting(models.Model):
('-1', 'Last')
], string='By day')
final_date = fields.Date('Repeat Until')
user_id = fields.Many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}, default=lambda self: self.env.user)
color_partner_id = fields.Integer("Color index of creator", compute='_compute_color_partner', store=False)
partner_id = fields.Many2one('res.partner', string='Responsible', related='user_id.partner_id', readonly=True)
active = fields.Boolean('Active', default=True, help="If the active field is set to false, it will allow you to hide the event alarm information without removing it.")
categ_ids = fields.Many2many('calendar.event.type', 'meeting_category_rel', 'event_id', 'type_id', 'Tags')
attendee_ids = fields.One2many('calendar.attendee', 'event_id', 'Participant', ondelete='cascade')
@@ -834,11 +832,6 @@ class Meeting(models.Model):
data.update(self._rrule_parse(meeting.rrule, data, meeting.start))
meeting.update(data)
@api.multi
def _compute_color_partner(self):
for meeting in self:
meeting.color_partner_id = meeting.user_id.partner_id.id
@api.constrains('start_datetime', 'stop_datetime', 'start_date', 'stop_date')
def _check_closing_date(self):
for meeting in self:
+2 -3
View File
@@ -265,11 +265,10 @@
<field name="arch" type="xml">
<calendar string="Meetings" date_start="start" date_stop="stop" date_delay="duration" all_day="allday"
readonly_form_view_id="%(calendar.view_calendar_event_form_popup)s" event_limit="3"
color="user_id.partner_id">
color="partner_id">
<field name="name"/>
<field name="partner_ids" avatar_field="image_small"/>
<field name="partner_ids" write_model="calendar.contacts" write_field="partner_id" avatar_field="image_small"/>
<field name="is_highlighted" invisible="1"/>
<filter name="partner_ids" write_model="calendar.contacts" write_field="partner_id" avatar_field="image_small"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -186,10 +186,9 @@
<field name="model">crm.lead</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<calendar string="Leads Generation" date_start="activity_date_deadline">
<calendar string="Leads Generation" date_start="activity_date_deadline" color="user_id">
<field name="name"/>
<field name="partner_name"/>
<filter name="user_id" color="True" avatar_field="image_small"/>
</calendar>
</field>
</record>
+2 -4
View File
@@ -360,10 +360,9 @@
<field name="model">event.event</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<calendar date_start="date_begin" date_stop="date_end" string="Event Organization">
<calendar date_start="date_begin" date_stop="date_end" string="Event Organization" color="event_type_id">
<field name="name"/>
<field name="event_type_id"/>
<filter name="event_type_id" color="True"/>
</calendar>
</field>
</record>
@@ -503,10 +502,9 @@
<field name="model">event.registration</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<calendar date_start="event_begin_date" date_stop="event_end_date" string="Event Registration">
<calendar date_start="event_begin_date" date_stop="event_end_date" string="Event Registration" color="event_id">
<field name="event_id"/>
<field name="name"/>
<filter name="event_id" color="True"/>
</calendar>
</field>
</record>
@@ -65,9 +65,8 @@
<field name="name">Leave Request</field>
<field name="model">hr.holidays</field>
<field name="arch" type="xml">
<calendar string="Leave Request" date_start="date_from" date_stop="date_to" mode="month" quick_add="False">
<calendar string="Leave Request" date_start="date_from" date_stop="date_to" mode="month" quick_add="False" color="employee_id">
<field name="display_name"/>
<filter name="employee_id" color="True" avatar_field="image_small"/>
</calendar>
</field>
</record>
@@ -232,11 +232,10 @@
<field name="model">hr.applicant</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<calendar string="Applicants" date_start="activity_date_deadline">
<calendar string="Applicants" date_start="activity_date_deadline" color="user_id">
<field name="name"/>
<field name="partner_name"/>
<field name="activity_summary"/>
<filter name="user_id" color="True" avatar_field="image_small"/>
</calendar>
</field>
</record>
@@ -217,10 +217,9 @@
<field name="name">equipment.request.calendar</field>
<field name="model">maintenance.request</field>
<field name="arch" type="xml">
<calendar date_start="schedule_date" date_delay="duration">
<calendar date_start="schedule_date" date_delay="duration" color="technician_user_id">
<field name="name"/>
<field name="technician_user_id"/>
<filter name="technician_user_id" color="True"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -212,11 +212,10 @@
<field name="model">mrp.production</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<calendar date_start="date_planned_start" string="Manufacturing Orders">
<calendar date_start="date_planned_start" string="Manufacturing Orders" color="routing_id">
<field name="name"/>
<field name="product_id"/>
<field name="product_qty"/>
<filter name="routing_id" color="True"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -272,10 +272,9 @@
<field name="name">mrp.production.work.order.calendar</field>
<field name="model">mrp.workorder</field>
<field name="arch" type="xml">
<calendar date_stop="date_planned_finished" date_start="date_planned_start" string="Operations">
<calendar date_stop="date_planned_finished" date_start="date_planned_start" string="Operations" color="workcenter_id">
<field name="workcenter_id"/>
<field name="production_id"/>
<filter name="workcenter_id" color="True"/>
</calendar>
</field>
</record>
-2
View File
@@ -532,8 +532,6 @@ action = model.activate_sample_project()
<field name="arch" type="xml">
<calendar date_start="date_deadline" string="Tasks" mode="month" color="user_id">
<field name="name"/>
<filter name="user_id" avatar_field="image_small"/>
<filter name="project_id"/>
</calendar>
</field>
</record>
@@ -153,10 +153,9 @@
<field name="model">project.issue</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<calendar string="Issues" date_start="date" date_delay="duration">
<calendar string="Issues" date_start="date" date_delay="duration" color="user_id">
<field name="name"/>
<field name="partner_id"/>
<filter name="user_id" color="True" avatar_field="image_small"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -113,11 +113,10 @@
<field name="model">purchase.order</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<calendar string="Calendar View" date_start="date_planned">
<calendar string="Calendar View" date_start="date_planned" color="partner_id">
<field name="name"/>
<field name="amount_total" widget="monetary"/>
<field name="partner_id"/>
<filter name="partner_id" color="True" avatar_field="image_small"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -103,9 +103,8 @@
<field name="name">resource.calendar.leaves.calendar</field>
<field name="model">resource.calendar.leaves</field>
<field name="arch" type="xml">
<calendar date_start="date_from" date_stop="date_to" string="Resource">
<calendar date_start="date_from" date_stop="date_to" string="Resource" color="resource_id">
<field name="name"/>
<filter name="resource_id" color="True"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -35,10 +35,9 @@
<field name="name">sale.order.calendar</field>
<field name="model">sale.order</field>
<field name="arch" type="xml">
<calendar string="Sales Orders" date_start="date_order">
<calendar string="Sales Orders" date_start="date_order" color="state">
<field name="partner_id"/>
<field name="amount_total" widget="monetary"/>
<filter name="state" color="True"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -127,11 +127,10 @@
<field name="model">stock.picking</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<calendar string="Calendar View" date_start="min_date" date_stop="max_date">
<calendar string="Calendar View" date_start="min_date" date_stop="max_date" color="partner_id">
<field name="origin"/>
<field name="picking_type_id"/>
<field name="partner_id"/>
<filter name="partner_id" color="True" avatar_field="image_small"/>
</calendar>
</field>
</record>
@@ -164,26 +164,8 @@ return AbstractModel.extend({
// fields to display color, e.g.: user_id.partner_id
this.field_color = params.field_color;
if (!this.preload_def) {
var def;
if (this.field_color) {
var fields = this.field_color.split('.');
if (fields.length > 1) {
def = new $.Deferred();
if (!this.model_color) {
var dataset = new data.DataSetSearch(this, this.fields[fields[0]].relation, params.context, []);
this.loadFieldView(dataset, false, 'form').then(function (fieldView) {
self.model_color = fieldView.fields[fields[1]].relation;
def.resolve();
});
} else {
def.resolve();
}
}
}
this.preload_def = $.Deferred();
$.when(
def,
this.performModelRPC(this.modelName, 'check_access_rights', ["write", false]),
this.performModelRPC(this.modelName, 'check_access_rights', ["create", false]))
.then(function (write, create) {
@@ -401,32 +383,12 @@ return AbstractModel.extend({
*/
_loadColors: function (element, events) {
if (this.field_color) {
var fields = this.field_color.split('.');
var first = fields[0];
var self = this;
if (fields.length === 1) {
_.each(events, function (event) {
var value = event.record[first];
event.color_index = _.isArray(value) ? value[0] : value;
});
this.model_color = this.fields[first].relation || element.model;
} else {
var model = this.fields[first].relation;
var ids = [];
_.each(events, function (event) {
ids.push(event.record[first][0]);
});
ids = _.uniq(ids);
return self.performModelRPC(model, 'read', [ids, [fields[1]]]).then(function (res) {
res = _.object(_.pluck(res, ['id']), _.pluck(res, [fields[1]]));
_.each(events, function (event) {
var value = res[event.record[first][0]];
event.color_index = _.isArray(value) ? value[0] : value;
});
});
}
var fieldName = this.field_color;
_.each(events, function (event) {
var value = event.record[fieldName];
event.color_index = _.isArray(value) ? value[0] : value;
});
this.model_color = this.fields[fieldName].relation || element.model;
}
return $.Deferred().resolve();
},
@@ -498,6 +460,7 @@ return AbstractModel.extend({
var self = this;
var new_filters = {};
var to_read = {};
_.each(this.data.filters, function (filter, fieldName) {
var field = self.fields[fieldName];
@@ -526,7 +489,7 @@ return AbstractModel.extend({
_.each(data, function (_value) {
var value = _.isArray(_value) ? _value[0] : _value;
fs.push({
'color': self.model_color === (field.relation || element.model) ? value : false,
'color_index': self.model_color === (field.relation || element.model) ? value : false,
'value': value,
'label': field_utils.format[field.type](_value, field),
'avatar_model': field.relation || element.model,
@@ -151,11 +151,6 @@ return AbstractRenderer.extend({
if (params.eventTemplate) {
this.qweb = new QWeb(session.debug, {_s: session.origin});
params.eventTemplate.children = [{
'tag': "t",
'attrs': {'t-name': "calendar-box"},
'children': params.eventTemplate.children
}];
this.qweb.add_template(utils.json_node_to_xml(params.eventTemplate));
}
},
@@ -31,7 +31,7 @@ var CalendarView = AbstractView.extend({
var attrs = arch.attrs;
if (!attrs.date_start) {
throw new Error(_t("Calendar view has not defined 'date_start' attribute."));
throw new Error(_lt("Calendar view has not defined 'date_start' attribute."));
}
var mapping = {};
@@ -46,42 +46,59 @@ var CalendarView = AbstractView.extend({
}
});
if (attrs.color) {
fieldNames.push(attrs.color.split('.')[0]);
}
var filters = {};
var eventLimit = attrs.event_limit !== null && (isNaN(+attrs.event_limit) ? _.str.toBool(attrs.event_limit) : +attrs.event_limit);
var filters = {};
var modelFilters = [];
_.each(arch.children, function (child) {
switch (child.tag) {
case "filter":
if (params.sidebar === false) break; // if we have not sidebar, (eg: Dashboard), we don't use the filter "coworkers"
var fieldName = child.attrs.name;
filters[fieldName] = {
if (child.tag !== 'field') return;
var fieldName = child.attrs.name;
fieldNames.push(fieldName);
if (!child.attrs.invisible) {
displayFields[fieldName] = child.attrs;
if (params.sidebar === false) return; // if we have not sidebar, (eg: Dashboard), we don't use the filter "coworkers"
if (child.attrs.avatar_field) {
filters[fieldName] = filters[fieldName] || {
'title': fields[fieldName].string,
'fieldName': fieldName,
'filters': [],
};
if (child.attrs.avatar_field) {
filters[fieldName].avatar_field = child.attrs.avatar_field;
filters[fieldName].avatar_model = fields[fieldName].relation;
}
if (child.attrs.write_model) {
filters[fieldName].write_model = child.attrs.write_model;
filters[fieldName].write_field = child.attrs.write_field; // can't use a x2many fields
}
fieldNames.push(child.attrs.name);
break;
case "field":
fieldNames.push(child.attrs.name);
if (!child.attrs.invisible) {
displayFields[child.attrs.name] = child.attrs;
}
filters[fieldName].avatar_field = child.attrs.avatar_field;
filters[fieldName].avatar_model = fields[fieldName].relation;
}
if (child.attrs.write_model) {
filters[fieldName] = filters[fieldName] || {
'title': fields[fieldName].string,
'fieldName': fieldName,
'filters': [],
};
filters[fieldName].write_model = child.attrs.write_model;
filters[fieldName].write_field = child.attrs.write_field; // can't use a x2many fields
modelFilters.push(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'].indexOf(fields[fieldName].relation) !== -1) {
filters[fieldName].avatar_field = 'image_small';
}
filters[fieldName].avatar_model = fields[fieldName].relation;
}
}
if (_.isEmpty(displayFields)) {
displayFields = fields.display_name ? {'display_name': {}} : [];
}
+15 -13
View File
@@ -26,6 +26,7 @@ QUnit.module('Views', {
fields: {
id: {string: "ID", type: "integer"},
user_id: {string: "user", type: "many2one", relation: 'user'},
parnter_id: {string: "user", type: "many2one", relation: 'partner', related: 'user_id.parnter_id'},
name: {string: "name", type: "char"},
start: {string: "start", type: "datetime"},
stop: {string: "stop", type: "datetime"},
@@ -34,12 +35,12 @@ QUnit.module('Views', {
type: {string: "type", type: "integer"},
},
records: [
{id: 1, user_id: session.uid, 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},
{id: 2, user_id: session.uid, name: "event 2", start: "2016-12-12 10:55:05", stop: "2016-12-12 14:55:05", allday: false, partner_ids: [1,2], type: 3},
{id: 3, user_id: 4, name: "event 3", start: "2016-12-12 15:55:05", stop: "2016-12-12 16:55:05", allday: false, partner_ids: [1], type: 2},
{id: 4, user_id: session.uid, name: "event 4", start: "2016-12-14 15:55:05", stop: "2016-12-14 18:55:05", allday: true, partner_ids: [1], type: 2},
{id: 5, user_id: 4, name: "event 5", start: "2016-12-13 15:55:05", stop: "2016-12-20 18:55:05", allday: false, partner_ids: [2,3], type: 2},
{id: 6, user_id: session.uid, name: "event 6", start: "2016-12-18 08:00:00", stop: "2016-12-18 09:00:00", allday: false, partner_ids: [3], type: 3}
{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},
{id: 2, user_id: session.uid, partner_id: 1, name: "event 2", start: "2016-12-12 10:55:05", stop: "2016-12-12 14:55:05", allday: false, partner_ids: [1,2], type: 3},
{id: 3, user_id: 4, partner_id: 4, name: "event 3", start: "2016-12-12 15:55:05", stop: "2016-12-12 16:55:05", allday: false, partner_ids: [1], type: 2},
{id: 4, user_id: session.uid, partner_id: 1, name: "event 4", start: "2016-12-14 15:55:05", stop: "2016-12-14 18:55:05", allday: true, partner_ids: [1], type: 2},
{id: 5, user_id: 4, partner_id: 4, name: "event 5", start: "2016-12-13 15:55:05", stop: "2016-12-20 18:55:05", allday: false, partner_ids: [2,3], type: 2},
{id: 6, user_id: session.uid, partner_id: 1, name: "event 6", start: "2016-12-18 08:00:00", stop: "2016-12-18 09:00:00", allday: false, partner_ids: [3], type: 3}
]
},
user: {
@@ -47,6 +48,7 @@ QUnit.module('Views', {
id: {string: "ID", type: "integer"},
display_name: {string: "Displayed name", type: "char"},
parnter_id: {string: "partner", type: "many2one", relation: 'partner'},
image: {string: "image", type: "integer"},
},
records: [
{id: session.uid, display_name: "user 1", partner_id: 1},
@@ -158,10 +160,10 @@ QUnit.module('Views', {
'all_day="allday" '+
'mode="week" '+
'attendee="partner_ids" '+
'color="user_id.parnter_id">'+
'color="parnter_id">'+
'<field name="name"/>'+
'<filter name="type"/>'+
'<filter name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+ // todo test image: avatar_field="image"
'<filter name="user_id" avatar_field="image"/>'+
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
'</calendar>',
archs: archs,
mockRPC: mock_check_access_rights,
@@ -191,11 +193,11 @@ QUnit.module('Views', {
// test filters
assert.strictEqual($sidebar.find('.o_calendar_filter').length, 2, "should display 2 filters");
assert.strictEqual($sidebar.find('.o_calendar_filter').length, 2, "should display 3 filters");
var $typeFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(type))');
assert.ok($typeFilter.length, "should display 'type' filter");
assert.strictEqual($typeFilter.find('.o_calendar_filter_item').length, 3, "should display 3 filter items for 'type'");
var $typeFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(user))');
assert.ok($typeFilter.length, "should display 'user' filter");
assert.strictEqual($typeFilter.find('.o_calendar_filter_item').length, 1, "should display 1 filter items for 'user'");
var $attendeesFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(attendees))');
assert.ok($attendeesFilter.length, "should display 'attendees' filter");
@@ -60,10 +60,9 @@
<field name="model">event.track</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
<calendar date_start="date" date_delay="duration" string="Event Tracks">
<calendar date_start="date" date_delay="duration" string="Event Tracks" color="location_id">
<field name="name"/>
<field name="event_id"/>
<filter name="location_id" color="True"/>
</calendar>
</field>
</record>
+1 -2
View File
@@ -64,9 +64,8 @@ diff --git a/openacademy/views/openacademy.xml b/openacademy/views/openacademy.x
+ <field name="name">session.calendar</field>
+ <field name="model">openacademy.session</field>
+ <field name="arch" type="xml">
+ <calendar string="Session Calendar" date_start="start_date" date_stop="end_date">
+ <calendar string="Session Calendar" date_start="start_date" date_stop="end_date" color="instructor_id">
+ <field name="name"/>
+ <filter name="instructor_id" color="True"/>
+ </calendar>
+ </field>
+ </record>
+1 -3
View File
@@ -54,10 +54,8 @@
<field name="model">ir.cron</field>
<field name="priority" eval="2"/>
<field name="arch" type="xml">
<calendar string="Scheduled Actions" date_start="nextcall">
<calendar string="Scheduled Actions" date_start="nextcall" color="user_id">
<field name="name"/>
<field name="user_id"/>
<filter name="user_id" color="True" avatar_field="image_small"/>
</calendar>
</field>
</record>
+1 -4
View File
@@ -649,10 +649,7 @@
</rng:attribute>
</rng:optional>
<rng:zeroOrMore>
<rng:ref name="field"/>
</rng:zeroOrMore>
<rng:zeroOrMore>
<rng:element name="filter">
<rng:element name="field">
<rng:attribute name="name" />
<rng:optional><rng:attribute name="avatar_field" /></rng:optional>
<rng:optional><rng:attribute name="write_model" /></rng:optional>