forked from Techsystech/web
[IMP] web_timeline: Follow create/edit/delete attrs
In addition to security rights (was already implemented), now follow `create="0"` / `edit="0"` / `delete="0"` attributes one can set onto the `timeline` tag, same as in other Odoo views.16.0
parent
abe3289943
commit
907aa64876
|
@ -1,6 +1,5 @@
|
||||||
* Implement a more efficient way of refreshing timeline after a record update;
|
* Implement a more efficient way of refreshing timeline after a record update;
|
||||||
* Make ``attrs`` attribute work;
|
* Make ``attrs`` attribute work;
|
||||||
* Make action attributes work (create, edit, delete) like in form and tree views.
|
|
||||||
* When grouping by m2m and more than one record is set, the timeline item appears only
|
* When grouping by m2m and more than one record is set, the timeline item appears only
|
||||||
on one group. Allow showing in both groups.
|
on one group. Allow showing in both groups.
|
||||||
* When grouping by m2m and dragging for changing the time or the group, the changes on
|
* When grouping by m2m and dragging for changing the time or the group, the changes on
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {Component} from "@odoo/owl";
|
||||||
export default AbstractController.extend({
|
export default AbstractController.extend({
|
||||||
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
|
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
|
||||||
onGroupClick: "_onGroupClick",
|
onGroupClick: "_onGroupClick",
|
||||||
|
onItemDoubleClick: "_onItemDoubleClick",
|
||||||
onUpdate: "_onUpdate",
|
onUpdate: "_onUpdate",
|
||||||
onRemove: "_onRemove",
|
onRemove: "_onRemove",
|
||||||
onMove: "_onMove",
|
onMove: "_onMove",
|
||||||
|
@ -101,6 +102,17 @@ export default AbstractController.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered on double-click on an item in read-only mode (otherwise, we use _onUpdate).
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {EventObject} event
|
||||||
|
* @returns {jQuery.Deferred}
|
||||||
|
*/
|
||||||
|
_onItemDoubleClick: function (event) {
|
||||||
|
return this.openItem(event.data.item, false);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a form view of a clicked timeline
|
* Opens a form view of a clicked timeline
|
||||||
* item (triggered by the TimelineRenderer).
|
* item (triggered by the TimelineRenderer).
|
||||||
|
@ -109,33 +121,35 @@ export default AbstractController.extend({
|
||||||
* @param {EventObject} event
|
* @param {EventObject} event
|
||||||
*/
|
*/
|
||||||
_onUpdate: function (event) {
|
_onUpdate: function (event) {
|
||||||
this.renderer = event.data.renderer;
|
|
||||||
const rights = event.data.rights;
|
|
||||||
const item = event.data.item;
|
const item = event.data.item;
|
||||||
const id = Number(item.evt.id) || item.evt.id;
|
const item_id = Number(item.evt.id) || item.evt.id;
|
||||||
const title = item.evt.__name;
|
return this.openItem(item_id, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Open specified item, either through modal, or by navigating to form view. */
|
||||||
|
openItem: function (item_id, is_editable) {
|
||||||
if (this.open_popup_action) {
|
if (this.open_popup_action) {
|
||||||
|
const options = {
|
||||||
|
resModel: this.model.modelName,
|
||||||
|
resId: item_id,
|
||||||
|
context: this.getSession().user_context,
|
||||||
|
};
|
||||||
|
if (is_editable) {
|
||||||
|
options.onRecordSaved = () => this.write_completed();
|
||||||
|
} else {
|
||||||
|
options.preventEdit = true;
|
||||||
|
}
|
||||||
this.Dialog = Component.env.services.dialog.add(
|
this.Dialog = Component.env.services.dialog.add(
|
||||||
FormViewDialog,
|
FormViewDialog,
|
||||||
{
|
options,
|
||||||
resId: id,
|
|
||||||
context: this.getSession().user_context,
|
|
||||||
title: title,
|
|
||||||
onRecordSaved: () => this.write_completed(),
|
|
||||||
resModel: this.model.modelName,
|
|
||||||
},
|
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let mode = "readonly";
|
|
||||||
if (rights.write) {
|
|
||||||
mode = "edit";
|
|
||||||
}
|
|
||||||
this.trigger_up("switch_view", {
|
this.trigger_up("switch_view", {
|
||||||
view_type: "form",
|
view_type: "form",
|
||||||
res_id: id,
|
|
||||||
mode: mode,
|
|
||||||
model: this.model.modelName,
|
model: this.model.modelName,
|
||||||
|
res_id: item_id,
|
||||||
|
mode: is_editable ? "edit" : "readonly",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,6 +29,9 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
|
||||||
this.modelName = params.model;
|
this.modelName = params.model;
|
||||||
this.mode = params.mode;
|
this.mode = params.mode;
|
||||||
this.options = params.options;
|
this.options = params.options;
|
||||||
|
this.can_create = params.can_create;
|
||||||
|
this.can_update = params.can_update;
|
||||||
|
this.can_delete = params.can_delete;
|
||||||
this.min_height = params.min_height;
|
this.min_height = params.min_height;
|
||||||
this.date_start = params.date_start;
|
this.date_start = params.date_start;
|
||||||
this.date_stop = params.date_stop;
|
this.date_stop = params.date_stop;
|
||||||
|
@ -192,22 +195,25 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
|
||||||
*/
|
*/
|
||||||
init_timeline: function () {
|
init_timeline: function () {
|
||||||
this._computeMode();
|
this._computeMode();
|
||||||
this.options.editable = {
|
this.options.editable = {};
|
||||||
// Add new items by double tapping
|
if (this.can_update && this.modelClass.data.rights.write) {
|
||||||
add: this.modelClass.data.rights.create,
|
this.options.onMove = this.on_move;
|
||||||
|
this.options.onUpdate = this.on_update;
|
||||||
// Drag items horizontally
|
// Drag items horizontally
|
||||||
updateTime: this.modelClass.data.rights.write,
|
this.options.editable.updateTime = true;
|
||||||
// Drag items from one group to another
|
// Drag items from one group to another
|
||||||
updateGroup: this.modelClass.data.rights.write,
|
this.options.editable.updateGroup = true;
|
||||||
|
if (this.can_create && this.modelClass.data.rights.create) {
|
||||||
|
this.options.onAdd = this.on_add;
|
||||||
|
// Add new items by double tapping
|
||||||
|
this.options.editable.add = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.can_delete && this.modelClass.data.rights.unlink) {
|
||||||
|
this.options.onRemove = this.on_remove;
|
||||||
// Delete an item by tapping the delete button top right
|
// Delete an item by tapping the delete button top right
|
||||||
remove: this.modelClass.data.rights.unlink,
|
this.options.editable.remove = true;
|
||||||
};
|
}
|
||||||
$.extend(this.options, {
|
|
||||||
onAdd: this.on_add,
|
|
||||||
onMove: this.on_move,
|
|
||||||
onUpdate: this.on_update,
|
|
||||||
onRemove: this.on_remove,
|
|
||||||
});
|
|
||||||
this.options.xss = {disabled: true};
|
this.options.xss = {disabled: true};
|
||||||
this.qweb = new QWeb(session.debug, {_s: session.origin}, false);
|
this.qweb = new QWeb(session.debug, {_s: session.origin}, false);
|
||||||
if (this.arch.children.length) {
|
if (this.arch.children.length) {
|
||||||
|
@ -218,7 +224,11 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.timeline = new vis.Timeline(this.$timeline.get(0), {}, this.options);
|
this.timeline = new vis.Timeline(this.$timeline.get(0), {}, this.options);
|
||||||
this.timeline.on("click", this.on_group_click);
|
this.timeline.on("click", this.on_timeline_click);
|
||||||
|
if (!this.options.onUpdate) {
|
||||||
|
// In read-only mode, catch double-clicks this way.
|
||||||
|
this.timeline.on("doubleClick", this.on_timeline_double_click);
|
||||||
|
}
|
||||||
const group_bys = this.arch.attrs.default_group_by.split(",");
|
const group_bys = this.arch.attrs.default_group_by.split(",");
|
||||||
this.last_group_bys = group_bys;
|
this.last_group_bys = group_bys;
|
||||||
this.last_domains = this.modelClass.data.domain;
|
this.last_domains = this.modelClass.data.domain;
|
||||||
|
@ -553,12 +563,12 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a click on a group header.
|
* Handle a click within the timeline.
|
||||||
*
|
*
|
||||||
* @param {ClickEvent} e
|
* @param {ClickEvent} e
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
on_group_click: function (e) {
|
on_timeline_click: function (e) {
|
||||||
if (e.what === "group-label" && e.group !== -1) {
|
if (e.what === "group-label" && e.group !== -1) {
|
||||||
this._trigger(
|
this._trigger(
|
||||||
e,
|
e,
|
||||||
|
@ -570,6 +580,24 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a double-click within the timeline.
|
||||||
|
*
|
||||||
|
* @param {ClickEvent} e
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
on_timeline_double_click: function (e) {
|
||||||
|
if (e.what === "item" && e.item !== -1) {
|
||||||
|
this._trigger(
|
||||||
|
e.item,
|
||||||
|
() => {
|
||||||
|
// No callback
|
||||||
|
},
|
||||||
|
"onItemDoubleClick"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger onUpdate.
|
* Trigger onUpdate.
|
||||||
*
|
*
|
||||||
|
@ -615,7 +643,7 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger_up encapsulation adds by default the rights, and the renderer.
|
* Trigger_up encapsulation adds by default the renderer.
|
||||||
*
|
*
|
||||||
* @param {HTMLElement} item
|
* @param {HTMLElement} item
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
|
@ -626,7 +654,6 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
|
||||||
this.trigger_up(trigger, {
|
this.trigger_up(trigger, {
|
||||||
item: item,
|
item: item,
|
||||||
callback: callback,
|
callback: callback,
|
||||||
rights: this.modelClass.data.rights,
|
|
||||||
renderer: this,
|
renderer: this,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,6 +22,10 @@ odoo.define("web_timeline.TimelineView", function (require) {
|
||||||
return _.isUndefined(value) || _.isNull(value);
|
return _.isUndefined(value) || _.isNull(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toBoolDefaultTrue(value) {
|
||||||
|
return isNullOrUndef(value) ? true : utils.toBoolElse(value, true);
|
||||||
|
}
|
||||||
|
|
||||||
var TimelineView = AbstractView.extend({
|
var TimelineView = AbstractView.extend({
|
||||||
display_name: _lt("Timeline"),
|
display_name: _lt("Timeline"),
|
||||||
icon: "fa fa-tasks",
|
icon: "fa fa-tasks",
|
||||||
|
@ -100,6 +104,9 @@ odoo.define("web_timeline.TimelineView", function (require) {
|
||||||
this.rendererParams.model = this.modelName;
|
this.rendererParams.model = this.modelName;
|
||||||
this.rendererParams.view = this;
|
this.rendererParams.view = this;
|
||||||
this.rendererParams.options = this._preapre_vis_timeline_options(attrs);
|
this.rendererParams.options = this._preapre_vis_timeline_options(attrs);
|
||||||
|
this.rendererParams.can_create = toBoolDefaultTrue(attrs.create);
|
||||||
|
this.rendererParams.can_update = toBoolDefaultTrue(attrs.edit);
|
||||||
|
this.rendererParams.can_delete = toBoolDefaultTrue(attrs.delete);
|
||||||
this.rendererParams.date_start = date_start;
|
this.rendererParams.date_start = date_start;
|
||||||
this.rendererParams.date_stop = date_stop;
|
this.rendererParams.date_stop = date_stop;
|
||||||
this.rendererParams.date_delay = date_delay;
|
this.rendererParams.date_delay = date_delay;
|
||||||
|
@ -127,9 +134,7 @@ odoo.define("web_timeline.TimelineView", function (require) {
|
||||||
selectable: true,
|
selectable: true,
|
||||||
multiselect: true,
|
multiselect: true,
|
||||||
showCurrentTime: true,
|
showCurrentTime: true,
|
||||||
stack: isNullOrUndef(attrs.stack)
|
stack: toBoolDefaultTrue(attrs.stack),
|
||||||
? true
|
|
||||||
: utils.toBoolElse(attrs.stack, true),
|
|
||||||
margin: attrs.margin ? JSON.parse(attrs.margin) : {item: 2},
|
margin: attrs.margin ? JSON.parse(attrs.margin) : {item: 2},
|
||||||
zoomKey: attrs.zoomKey || "ctrlKey",
|
zoomKey: attrs.zoomKey || "ctrlKey",
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue