diff --git a/addons/web/static/src/views/kanban/kanban_column_examples_dialog.js b/addons/web/static/src/views/kanban/kanban_column_examples_dialog.js index cae9b37b6ff..b9e59b56162 100644 --- a/addons/web/static/src/views/kanban/kanban_column_examples_dialog.js +++ b/addons/web/static/src/views/kanban/kanban_column_examples_dialog.js @@ -9,10 +9,15 @@ import { Component, useRef } from "@odoo/owl"; const random = (min, max) => Math.floor(Math.random() * (max - min) + min); class KanbanExamplesNotebookTemplate extends Component { + static defaultProps = { + columns: [], + foldedColumns: [], + }; setup() { this.columns = []; const hasBullet = this.props.bullets && this.props.bullets.length; - for (const title of this.props.columns) { + const allColumns = [...this.props.columns, ...this.props.foldedColumns]; + for (const title of allColumns) { const col = { title, records: [] }; this.columns.push(col); for (let i = 0; i < random(1, 5); i++) { diff --git a/addons/web/static/src/views/kanban/kanban_column_quick_create.js b/addons/web/static/src/views/kanban/kanban_column_quick_create.js index e32bbb7fcf7..b123e23d824 100644 --- a/addons/web/static/src/views/kanban/kanban_column_quick_create.js +++ b/addons/web/static/src/views/kanban/kanban_column_quick_create.js @@ -76,9 +76,14 @@ export class KanbanColumnQuickCreate extends Component { applyExamplesText: this.props.exampleData.applyExamplesText || this.env._t("Use This For My Kanban"), applyExamples: (index) => { - for (const groupName of this.props.exampleData.examples[index].columns) { + const { examples, foldField } = this.props.exampleData; + const { columns, foldedColumns = [] } = examples[index]; + for (const groupName of columns) { this.props.onValidate(groupName); } + for (const groupName of foldedColumns) { + this.props.onValidate(groupName, { [foldField]: true }, true); + } }, }); } diff --git a/addons/web/static/src/views/kanban/kanban_renderer.js b/addons/web/static/src/views/kanban/kanban_renderer.js index 71166c13d4f..aed78412b8c 100644 --- a/addons/web/static/src/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/views/kanban/kanban_renderer.js @@ -51,13 +51,17 @@ export function canQuickCreate(list) { } function validateColumnQuickCreateExamples(data) { - const { allowedGroupBys = [], examples = [] } = data; + const { allowedGroupBys = [], examples = [], foldField = "" } = data; if (!allowedGroupBys.length) { throw new Error("The example data must contain an array of allowed groupbys"); } if (!examples.length) { throw new Error("The example data must contain an array of examples"); } + const someHasFoldedColumns = examples.some(({ foldedColumns = [] }) => foldedColumns.length); + if (!foldField && someHasFoldedColumns) { + throw new Error("The example data must contain a fold field if there are folded columns"); + } } export class KanbanRenderer extends Component { diff --git a/addons/web/static/src/views/kanban/kanban_renderer.xml b/addons/web/static/src/views/kanban/kanban_renderer.xml index 203b853ec30..27662d43979 100644 --- a/addons/web/static/src/views/kanban/kanban_renderer.xml +++ b/addons/web/static/src/views/kanban/kanban_renderer.xml @@ -116,7 +116,7 @@ diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index d01eeb74228..9ff6d31c0b9 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -2272,8 +2272,8 @@ export class DynamicGroupList extends DynamicList { /** * @see {_createGroup} */ - async createGroup(groupName) { - await this.model.mutex.exec(() => this._createGroup(groupName)); + async createGroup(groupName, groupData, isFolded) { + await this.model.mutex.exec(() => this._createGroup(groupName, groupData, isFolded)); } /** @@ -2413,27 +2413,27 @@ export class DynamicGroupList extends DynamicList { /** * @param {string} groupName + * @param {{ [relatedFieldName: string]: any }} [groupData={}] + * @param {boolean} [isFolded=false] * @returns {Promise} */ - async _createGroup(groupName) { - const [id, displayName] = await this.model.orm.call( - this.groupByField.relation, - "name_create", - [groupName], - { context: this.context } - ); + async _createGroup(groupName, groupData = {}, isFolded = false) { + groupData = { ...groupData, name: groupName }; + const [id] = await this.model.orm.create(this.groupByField.relation, [groupData], { + context: this.context, + }); const [lastGroup] = this.groups.slice(-1); const group = this.model.createDataPoint("group", { ...this.commonGroupParams, count: 0, value: id, - displayName, + displayName: groupName, aggregates: {}, groupByField: this.groupByField, groupDomain: Domain.and([this.domain, [[this.groupByField.name, "=", id]]]).toList(), + isFolded, rawContext: this.rawContext, }); - group.isFolded = false; this.addGroup(group); if (lastGroup) { diff --git a/addons/web/static/tests/views/kanban_view_tests.js b/addons/web/static/tests/views/kanban_view_tests.js index e121af48a5d..a5bb2b8d733 100644 --- a/addons/web/static/tests/views/kanban_view_tests.js +++ b/addons/web/static/tests/views/kanban_view_tests.js @@ -2249,7 +2249,7 @@ QUnit.module("Views", (hooks) => { "web_search_read", // initial search_read (second column) "get_views", // get form view "onchange", // quick create - "create", // should perform a name_create to create the record + "create", // should perform a create to create the record "onchange", // reopen the quick create automatically "read", // read the created record ]); @@ -4292,7 +4292,7 @@ QUnit.module("Views", (hooks) => { "", groupBy: ["product_id"], async mockRPC(route, { method, model }) { - if (method === "name_create" && model === "product") { + if (method === "create" && model === "product") { await prom; } }, @@ -5687,7 +5687,7 @@ QUnit.module("Views", (hooks) => { "", groupBy: ["product_id"], async mockRPC(route, { method }) { - if (method === "name_create" || route === "/web/dataset/resequence") { + if (method === "create" || route === "/web/dataset/resequence") { assert.step(method || route); } }, @@ -5735,7 +5735,7 @@ QUnit.module("Views", (hooks) => { "o_column_folded", "the created column should not be folded" ); - assert.verifySteps(["name_create", "/web/dataset/resequence"]); + assert.verifySteps(["create", "/web/dataset/resequence"]); // fold and unfold the created column, and check that no RPCs are done (as there are no records) const clickColumnAction = await toggleColumnActions(2); @@ -6124,7 +6124,7 @@ QUnit.module("Views", (hooks) => { ); assert.deepEqual(resequencedIDs, [4, 3], "moved column should be resequenced accordingly"); - assert.verifySteps(["name_create"]); + assert.verifySteps(["create"]); }); QUnit.test("create a column, delete it and create another one", async (assert) => { @@ -6552,6 +6552,66 @@ QUnit.module("Views", (hooks) => { ); }); + QUnit.test("quick create column and examples: with folded columns", async (assert) => { + serverData.models.partner.records = []; + serverData.models.product.fields.folded = { string: "Folded", type: "boolean" }; + serviceRegistry.add("dialog", dialogService, { force: true }); + registry.category("kanban_examples").add("test", { + allowedGroupBys: ["product_id"], + foldField: "folded", + examples: [ + { + name: "A first example", + columns: ["not folded"], + foldedColumns: ["folded"], + description: "A weak description.", + }, + ], + }); + + const expectedGroups = ['[[{"name":"not folded"}]]', '[[{"folded":true,"name":"folded"}]]']; + await makeView({ + type: "kanban", + resModel: "partner", + serverData, + arch: /* xml */ ` + + + +
+
+
+ `, + groupBy: ["product_id"], + mockRPC(route, args) { + if (args?.method === "create") { + assert.step(`${args.method} (model: ${args.model})`); + assert.strictEqual(JSON.stringify(args.args), expectedGroups.shift()); + } + }, + }); + + // the quick create should already be unfolded as there are no records + assert.containsOnce(target, ".o_column_quick_create .o_quick_create_unfolded"); + + // click to see the examples + await click(target, ".o_column_quick_create .o_kanban_examples"); + + // apply the examples + assert.verifySteps([]); + await click(document.body, ".modal .modal-footer .btn.btn-primary"); + assert.verifySteps(["create (model: product)", "create (model: product)"]); + + // the applied examples should be visible + assert.containsN(target, ".o_kanban_group", 2); + assert.containsOnce(target, ".o_kanban_group:not(.o_column_folded)"); + assert.containsOnce(target, ".o_kanban_group.o_column_folded"); + assert.deepEqual( + [...target.querySelectorAll(".o_kanban_group")].map((e) => e.textContent), + ["not folded", "folded (0)"] + ); + }); + QUnit.test("quick create column's apply button's display text", async (assert) => { serviceRegistry.add("dialog", dialogService, { force: true }); const applyExamplesText = "Use This For My Test";