diff --git a/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml b/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml index 2269a570dcc..1041499adb8 100644 --- a/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml +++ b/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml @@ -3,7 +3,7 @@ 'bottom-start' - + diff --git a/addons/sale/static/src/js/product_catalog/kanban_record.js b/addons/sale/static/src/js/product_catalog/kanban_record.js index 85971172e32..ae80a7bca66 100644 --- a/addons/sale/static/src/js/product_catalog/kanban_record.js +++ b/addons/sale/static/src/js/product_catalog/kanban_record.js @@ -21,7 +21,7 @@ export class ProductCatalogKanbanRecord extends KanbanRecord { useSubEnv({ currencyId: this.props.record.context.product_catalog_currency_id, orderId: this.props.record.context.product_catalog_order_id, - productId: this.record.id.raw_value, + productId: this.props.record.resId, addProduct: this.addProduct.bind(this), removeProduct: this.removeProduct.bind(this), increaseQuantity: this.increaseQuantity.bind(this), diff --git a/addons/sale/static/src/js/product_catalog/kanban_record.xml b/addons/sale/static/src/js/product_catalog/kanban_record.xml index a32ab8da586..c3b3c506892 100644 --- a/addons/sale/static/src/js/product_catalog/kanban_record.xml +++ b/addons/sale/static/src/js/product_catalog/kanban_record.xml @@ -11,7 +11,7 @@ t-att-class="{'text-bg-primary': state.quantity || props.record.productCatalogData.readOnly}"> - diff --git a/addons/web/static/src/model/relational_model/utils.js b/addons/web/static/src/model/relational_model/utils.js index d4e9c5f522e..518325898dd 100644 --- a/addons/web/static/src/model/relational_model/utils.js +++ b/addons/web/static/src/model/relational_model/utils.js @@ -503,19 +503,28 @@ export function useRecordObserver(callback) { let alive = true; const fct = (props) => { const def = new Deferred(); + let firstCall = true; effect( - batched( - async (record) => { - if (!alive) { - // effect doesn't clean up when the component is unmounted. - // We must do it manually. - return; - } + async (record) => { + if (firstCall) { + firstCall = false; await callback(record); def.resolve(); - }, - () => new Promise((resolve) => window.requestAnimationFrame(resolve)) - ), + } else { + return batched( + async (record) => { + if (!alive) { + // effect doesn't clean up when the component is unmounted. + // We must do it manually. + return; + } + await callback(record); + def.resolve(); + }, + () => new Promise((resolve) => window.requestAnimationFrame(resolve)) + )(record); + } + }, [props.record] ); return def; diff --git a/addons/web/static/src/views/kanban/kanban_record.js b/addons/web/static/src/views/kanban/kanban_record.js index e1aa6d10fa6..d47e56684d2 100644 --- a/addons/web/static/src/views/kanban/kanban_record.js +++ b/addons/web/static/src/views/kanban/kanban_record.js @@ -1,7 +1,7 @@ /** @odoo-module **/ -import { evalDomain } from "@web/core/domain"; import { ColorList } from "@web/core/colorlist/colorlist"; +import { evalDomain } from "@web/core/domain"; import { Dropdown } from "@web/core/dropdown/dropdown"; import { DropdownItem } from "@web/core/dropdown/dropdown_item"; import { registry } from "@web/core/registry"; @@ -9,6 +9,7 @@ import { useTooltip } from "@web/core/tooltip/tooltip_hook"; import { useService } from "@web/core/utils/hooks"; import { sprintf } from "@web/core/utils/strings"; import { url } from "@web/core/utils/urls"; +import { useRecordObserver } from "@web/model/relational_model/utils"; import { Field } from "@web/views/fields/field"; import { fileTypeMagicWordMap, imageCacheKey } from "@web/views/fields/image/image_field"; import { ViewButton } from "@web/views/view_button/view_button"; @@ -24,7 +25,7 @@ import { KanbanCompiler } from "./kanban_compiler"; import { KanbanCoverImageDialog } from "./kanban_cover_image_dialog"; import { KanbanDropdownMenuWrapper } from "./kanban_dropdown_menu_wrapper"; -import { Component, onMounted, onWillUpdateProps, useRef } from "@odoo/owl"; +import { Component, onMounted, onWillUpdateProps, useRef, useState } from "@odoo/owl"; const { COLORS } = ColorList; const formatters = registry.category("formatters"); @@ -106,7 +107,13 @@ function getValue(record, fieldName) { } export function getFormattedRecord(record) { - const formattedRecord = {}; + const formattedRecord = { + id: { + value: record.resId, + raw_value: record.resId, + }, + }; + for (const fieldName of record.fieldNames) { formattedRecord[fieldName] = { value: getValue(record, fieldName), @@ -195,13 +202,21 @@ export class KanbanRecord extends Component { }); } - this.createRecordAndWidget(this.props); + this.dataState = useState({ record: {}, widget: {} }); + this.createWidget(this.props); + onWillUpdateProps(this.createWidget); + useRecordObserver((record) => + Object.assign(this.dataState.record, getFormattedRecord(record)) + ); this.rootRef = useRef("root"); onMounted(() => { // FIXME: this needs to be changed to an attribute on the root node... this.allowGlobalClick = !!this.rootRef.el.querySelector(ALLOW_GLOBAL_CLICK); }); - onWillUpdateProps(this.createRecordAndWidget); + } + + get record() { + return this.dataState.record; } getFormattedValue(fieldId) { @@ -211,20 +226,18 @@ export class KanbanRecord extends Component { } /** - * Assigns both "record" and "widget" properties on the kanban record. + * Assigns "widget" properties on the kanban record. * * @param {Object} props */ - createRecordAndWidget(props) { + createWidget(props) { const { archInfo, list } = props; const { activeActions } = archInfo; - - this.record = getFormattedRecord(this.props.record); // Widget const deletable = activeActions.delete && (!list.groupByField || list.groupByField.type !== "many2many"); const editable = activeActions.edit; - this.widget = { + this.dataState.widget = { deletable, editable, isHtmlEmpty, @@ -357,10 +370,10 @@ export class KanbanRecord extends Component { kanban_image: (...args) => getImageSrcFromRecordInfo(this.props.record, ...args), luxon, read_only_mode: this.props.readonly, - record: this.record, + record: this.dataState.record, selection_mode: this.props.forceGlobalClick, user_context: this.user.context, - widget: this.widget, + widget: this.dataState.widget, __comp__: Object.assign(Object.create(this), { this: this }), }; } diff --git a/addons/web/static/src/views/kanban/kanban_renderer.xml b/addons/web/static/src/views/kanban/kanban_renderer.xml index 75fb59f3d6a..9de68e279bf 100644 --- a/addons/web/static/src/views/kanban/kanban_renderer.xml +++ b/addons/web/static/src/views/kanban/kanban_renderer.xml @@ -125,7 +125,7 @@ -