diff --git a/addons/hr/static/src/js/standalone_m2o_avatar_employee.js b/addons/hr/static/src/js/standalone_m2o_avatar_employee.js new file mode 100644 index 00000000000..64da43ecbb9 --- /dev/null +++ b/addons/hr/static/src/js/standalone_m2o_avatar_employee.js @@ -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; +}); diff --git a/addons/hr/static/tests/standalone_m2o_avatar_employee_tests.js b/addons/hr/static/tests/standalone_m2o_avatar_employee_tests.js new file mode 100644 index 00000000000..976cd34da50 --- /dev/null +++ b/addons/hr/static/tests/standalone_m2o_avatar_employee_tests.js @@ -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 = "
"; + const view = await createView({ + View: getHtmlView(html, "test"), + data: this.data, + model: "foo", + arch: "" + }); + + 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`
`; + + const view = await createView({ + View: getOwlView(Renderer, "test"), + data: this.data, + model: "foo", + arch: "" + }); + + 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(); + }); + }); +}); diff --git a/addons/hr/views/hr_templates.xml b/addons/hr/views/hr_templates.xml index 2cfac7e0cc8..d959b96506b 100644 --- a/addons/hr/views/hr_templates.xml +++ b/addons/hr/views/hr_templates.xml @@ -7,12 +7,14 @@ +