Files
jikimo_sf/web_studio/static/src/legacy/js/approval_component.js
2023-04-14 17:42:23 +08:00

206 lines
7.0 KiB
JavaScript

odoo.define('web_studio.ApprovalComponent', function (require) {
'use strict';
const Dialog = require('web.OwlDialog');
const Popover = require("web.Popover");
const { useService } = require("@web/core/utils/hooks");
const { Component, onMounted, onWillUnmount, onWillStart, onWillUpdateProps, useState } = owl;
class ApprovalComponent extends Component {
//--------------------------------------------------------------------------
// Lifecycle
//--------------------------------------------------------------------------
setup() {
this.state = useState({
entries: null,
rules: null,
showInfo: false,
syncing: false,
init: true,
});
this.rpc = useService("rpc");
onMounted( () => {
this.env.bus.on('refresh-approval', this, this._onRefresh);
});
onWillUnmount( () => {
this.env.bus.off('refresh-approval', this, this._onRefresh);
});
onWillStart(async () => {
await this._fetchApprovalData();
});
onWillUpdateProps(async () => {
await this._fetchApprovalData();
});
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* @param {Number} ruleId: id of the rule for which the entry is requested.
* @returns {Object}
*/
getEntry(ruleId) {
return this.state.entries.find((e) => e.rule_id[0] === ruleId);
}
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Delete an approval entry for a given rule server-side.
* @private
* @param {Number} ruleId
*/
_cancelApproval(ruleId) {
this._setSyncing(true);
this.rpc({
model: 'studio.approval.rule',
method: 'delete_approval',
args: [[ruleId]],
kwargs: {
res_id: this.props.resId,
},
context: this.env.session.user_context,
}).then(async () => {
this._notifyChange();
await this._fetchApprovalData()
this._setSyncing(false);
}).guardedCatch(async () => {
this._notifyChange();
await this._fetchApprovalData()
this._setSyncing(false);
});
}
/**
* @private
*/
async _fetchApprovalData() {
const spec = await this.rpc(
{
model: 'studio.approval.rule',
method: 'get_approval_spec',
args: [this.props.model, this.props.method, this.props.action],
kwargs: {
res_id: !this.props.inStudio && this.props.resId,
},
context: this.env.session.user_context,
},
{ shadow: true }
);
// reformat the dates
spec.entries.forEach((entry) => {
entry.long_date = moment.utc(entry.write_date).local().format('LLL');
entry.short_date = moment.utc(entry.write_date).local().format('LL');
});
Object.assign(this.state, spec);
this.state.init = false;
}
/**
* Notifies other widgets that an approval change has occurred server-side,
* this is useful if more than one button with the same action is in the view
* to avoid displaying conflicting approval data.
* @private
*/
_notifyChange() {
this.env.bus.trigger('refresh-approval', {
approvalSpec: [this.props.model, this.props.resId, this.props.method, this.props.action],
});
}
/**
* Create or update an approval entry for a specified rule server-side.
* @private
* @param {Number} ruleId
* @param {Boolean} approved
*/
_setApproval(ruleId, approved) {
this._setSyncing(true);
this.rpc({
model: 'studio.approval.rule',
method: 'set_approval',
args: [[ruleId]],
kwargs: {
res_id: this.props.resId,
approved: approved,
},
context: this.env.session.user_context,
}).then(async () => {
this._notifyChange();
await this._fetchApprovalData();
this._setSyncing(false);
}).guardedCatch(async () => {
this._notifyChange();
await this._fetchApprovalData();
this._setSyncing(false);
});
}
/**
* Mark the widget as syncing; this is used to disable buttons while
* an action is being processed server-side.
* @param {Boolean} value: true to mark the widget as syncing, false otherwise.
*/
_setSyncing(value) {
this.state.syncing = value;
}
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Handle notification dispatched by the bus; if another action has modifed
* approval data server-side for an approval spec that matches this widget,
* it will update itself.
* @param {Object} ev
*/
_onRefresh(ev) {
if (
ev.approvalSpec[0] === this.props.model &&
ev.approvalSpec[1] === this.props.resId &&
ev.approvalSpec[2] === this.props.method &&
ev.approvalSpec[3] === this.props.action
) {
// someone clicked on this widget's button, which
// might trigger approvals server-side
// refresh the widget
this._fetchApprovalData();
}
}
/**
* Display or hide more information through a popover (desktop) or
* dialog (mobile).
* @param {DOMEvent} ev
*/
_toggleInfo() {
this.state.showInfo = !this.state.showInfo;
}
}
ApprovalComponent.template = 'Studio.ApprovalComponent.Legacy';
ApprovalComponent.components = { Dialog, Popover };
ApprovalComponent.props = {
action: [Number, Boolean],
actionName: { type: String, optional: true },
inStudio: Boolean,
method: [String, Boolean],
model: String,
resId: { type: Number, optional: true },
};
return ApprovalComponent;
});