[IMP] hr: add a standalone version of the avatar employee widget

This will be useful for special views like gantt, grid…

A StandaloneM2OAvatarEmployee widget will be available and would allow to
instantiate a Many2OneAvatarEmployee widget anywhere.

Usage:
  const widget = new StandaloneM2OAvatarEmployee(<parent>, <value>);
  widget.appendTo(<Node>);

Where:
  <parent> the widget parent, if it is given
  <value> {number|[number, char]} either the employee id or an array representing the employee: [id, display_name]. If only the id is passed, the widget will fetch the display_name through a name_get rpc.
  <Node> any DOM Node object you want the widget to be appended to.

Examples:
  const w1 = new StandaloneM2OAvatarEmployee(null, 3);
  const w2 = new StandaloneM2OAvatarEmployee(null, [1, 'Mitchell Admin']);
  w1.appendTo(document.body);
  w2.appendTo(document.body);

closes odoo/odoo#54230

Taskid: 2272544
Taskid: 2272582
Related: odoo/enterprise#11412
Signed-off-by: Mathieu Duckerts-Antoine <Polymorphe57@users.noreply.github.com>
Co-authored-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Bruno Boi
2020-08-17 08:30:52 +00:00
co-authored by Aaron Bohy
parent 5750adea3a
commit 26633ea8bb
3 changed files with 187 additions and 0 deletions
@@ -0,0 +1,61 @@
odoo.define('hr.StandaloneM2OAvatarEmployee', function (require) {
'use strict';
const StandaloneFieldManagerMixin = require('web.StandaloneFieldManagerMixin');
const Widget = require('web.Widget');
const { Many2OneAvatarEmployee } = require('hr.Many2OneAvatarEmployee');
const StandaloneM2OAvatarEmployee = Widget.extend(StandaloneFieldManagerMixin, {
className: 'o_standalone_avatar_employee',
/**
* @override
*/
init(parent, value) {
this._super(...arguments);
StandaloneFieldManagerMixin.init.call(this);
this.value = value;
},
/**
* @override
*/
willStart() {
return Promise.all([this._super(...arguments), this._makeAvatarWidget()]);
},
/**
* @override
*/
start() {
this.avatarWidget.$el.appendTo(this.$el);
return this._super(...arguments);
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Create a record, and initialize and start the avatar widget.
*
* @private
* @returns {Promise}
*/
async _makeAvatarWidget() {
const modelName = 'hr.employee';
const fieldName = 'employee_id';
const recordId = await this.model.makeRecord(modelName, [{
name: fieldName,
relation: modelName,
type: 'many2one',
value: this.value,
}]);
const state = this.model.get(recordId);
this.avatarWidget = new Many2OneAvatarEmployee(this, fieldName, state);
this._registerWidget(recordId, fieldName, this.avatarWidget);
return this.avatarWidget.appendTo(document.createDocumentFragment());
},
});
return StandaloneM2OAvatarEmployee;
});
@@ -0,0 +1,124 @@
odoo.define('hr.StandaloneM2OEmployeeTests', function (require) {
"use strict";
const { xml } = owl.tags;
const AbstractRendererOwl = require('web.AbstractRendererOwl');
const BasicView = require("web.BasicView");
const BasicRenderer = require("web.BasicRenderer");
const RendererWrapper = require('web.RendererWrapper');
const { createView } = require('web.test_utils');
const StandaloneM2OAvatarEmployee = require('hr.StandaloneM2OAvatarEmployee');
function getHtmlRenderer(html) {
return BasicRenderer.extend({
start: function () {
this.$el.html(html);
return this._super.apply(this, arguments);
}
});
}
function getOwlView(owlRenderer, viewType) {
viewType = viewType || "test";
return BasicView.extend({
viewType: viewType,
config: Object.assign({}, BasicView.prototype.config, {
Renderer: owlRenderer,
}),
getRenderer() {
return new RendererWrapper(null, this.config.Renderer, {});
}
});
}
function getHtmlView(html, viewType) {
viewType = viewType || "test";
return BasicView.extend({
viewType: viewType,
config: Object.assign({}, BasicView.prototype.config, {
Renderer: getHtmlRenderer(html)
})
});
}
QUnit.module('hr', {}, function () {
QUnit.module('StandaloneM2OEmployeeTests', {
beforeEach: function () {
this.data = {
'foo': {
fields: {
employee_id: {string: "Employee", type: 'many2one', relation: 'hr.employee'},
},
records: [],
},
'hr.employee': {
fields: {},
records: [
{id: 10, name: "Mario"},
{id: 20, name: "Luigi"},
{id: 30, name: "Yoshi"}
],
},
};
},
});
QUnit.test('standalone_m2o_avatar_employee: legacy view', async function (assert) {
assert.expect(1);
const html = "<div class='coucou_test'></div>";
const view = await createView({
View: getHtmlView(html, "test"),
data: this.data,
model: "foo",
arch: "<test/>"
});
const avatar10 = new StandaloneM2OAvatarEmployee(view, 10);
const avatar20 = new StandaloneM2OAvatarEmployee(view, 20);
const avatar30 = new StandaloneM2OAvatarEmployee(view, [30, 'Bowser']);
await avatar10.appendTo(view.el.querySelector('.coucou_test'));
await avatar20.appendTo(view.el.querySelector('.coucou_test'));
await avatar30.appendTo(view.el.querySelector('.coucou_test'));
assert.deepEqual(
[...view.el.querySelectorAll('.o_field_many2one_avatar span')].map(el => el.innerText),
["Mario", "Luigi", "Bowser"]
);
view.destroy();
});
QUnit.test('standalone_m2o_avatar_employee: Owl view', async function (assert) {
assert.expect(1);
class Renderer extends AbstractRendererOwl { }
Renderer.template = xml`<div class='coucou_test'></div>`;
const view = await createView({
View: getOwlView(Renderer, "test"),
data: this.data,
model: "foo",
arch: "<test/>"
});
const avatar10 = new StandaloneM2OAvatarEmployee(view, 10);
const avatar20 = new StandaloneM2OAvatarEmployee(view, 20);
const avatar30 = new StandaloneM2OAvatarEmployee(view, [30, 'Bowser']);
await avatar10.appendTo(view.el.querySelector('.coucou_test'));
await avatar20.appendTo(view.el.querySelector('.coucou_test'));
await avatar30.appendTo(view.el.querySelector('.coucou_test'));
assert.deepEqual(
[...view.el.querySelectorAll('.o_field_many2one_avatar span')].map(el => el.innerText),
["Mario", "Luigi", "Bowser"]
);
view.destroy();
});
});
});
+2
View File
@@ -7,12 +7,14 @@
<script type="text/javascript" src="/hr/static/src/js/chat.js"></script>
<script type="text/javascript" src="/hr/static/src/js/language.js"></script>
<script type="text/javascript" src="/hr/static/src/js/many2one_avatar_employee.js"></script>
<script type="text/javascript" src="/hr/static/src/js/standalone_m2o_avatar_employee.js"></script>
</xpath>
</template>
<template id="qunit_suite" name="hr tests" inherit_id="web.qunit_suite_tests">
<xpath expr="." position="inside">
<script type="text/javascript" src="/hr/static/tests/many2one_avatar_employee_tests.js"></script>
<script type="text/javascript" src="/hr/static/tests/standalone_m2o_avatar_employee_tests.js"></script>
</xpath>
</template>
</odoo>