From 23c7c00d099270440c872f9638657f8a3b936153 Mon Sep 17 00:00:00 2001 From: les-adhoc Date: Fri, 28 Aug 2026 19:56:11 +0000 Subject: [PATCH] [IMP] project_ux: show sub-tasks when the "Is Sub-Task" filter is active The "Is Sub-Task" filter restricts the domain to parent_id != False, but the task list keeps sub-tasks hidden while the "Show Sub-Tasks" display mode is off: the model injects display_in_project = True, which is False for any sub-task sharing its parent's project. The list then comes back empty with no hint, so the sub-task looks like it does not exist. When the sub-task filter is active, drop the display_in_project leaf so the filter is honored and the sub-tasks show up, without requiring the user to enable the display mode by hand. The "Show Sub-Tasks" toggle is reflected as selected while the filter forces it, to avoid an inconsistent "off but showing" state. --- project_ux/__manifest__.py | 8 +++++- .../js/project_task_control_panel_patch.js | 23 ++++++++++++++++ .../src/js/project_task_list_model_patch.js | 25 ++++++++++++++++++ project_ux/static/src/js/subtask_domain.js | 26 +++++++++++++++++++ .../src/xml/project_task_control_panel.xml | 20 ++++++++++++++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 project_ux/static/src/js/project_task_control_panel_patch.js create mode 100644 project_ux/static/src/js/project_task_list_model_patch.js create mode 100644 project_ux/static/src/js/subtask_domain.js create mode 100644 project_ux/static/src/xml/project_task_control_panel.xml diff --git a/project_ux/__manifest__.py b/project_ux/__manifest__.py index 6feeced6..0740b8e8 100644 --- a/project_ux/__manifest__.py +++ b/project_ux/__manifest__.py @@ -19,7 +19,7 @@ ############################################################################## { "name": "Project UX", - "version": "19.0.2.1.0", + "version": "19.0.2.2.0", "category": "Project Management", "sequence": 14, "author": "ADHOC SA", @@ -35,6 +35,12 @@ "views/project_project_views.xml", "views/project_task_type_views.xml", ], + "assets": { + "web.assets_backend": [ + "project_ux/static/src/**/*.js", + "project_ux/static/src/**/*.xml", + ], + }, "demo": [], "installable": True, "auto_install": False, diff --git a/project_ux/static/src/js/project_task_control_panel_patch.js b/project_ux/static/src/js/project_task_control_panel_patch.js new file mode 100644 index 00000000..282913fa --- /dev/null +++ b/project_ux/static/src/js/project_task_control_panel_patch.js @@ -0,0 +1,23 @@ +import { patch } from "@web/core/utils/patch"; +import { ProjectTaskControlPanel } from "@project/views/project_task_control_panel/project_task_control_panel"; +import { hasSubtaskLeaf } from "./subtask_domain"; + +patch(ProjectTaskControlPanel.prototype, { + /** + * The "Is Sub-Task" filter forces sub-tasks to be visible: the model drops + * the `display_in_project` restriction while that filter is active (see + * project_task_list_model_patch). While it is active the "Show Sub-Tasks" + * toggle has no real effect. + */ + get isSubtaskFilterActive() { + return hasSubtaskLeaf(this.env.searchModel.domain); + }, + + /** + * State the toggle is painted with: also selected when the filter forces + * it, to avoid the confusing "off but showing sub-tasks" state. + */ + get effectiveShowSubtasks() { + return this.state.showSubtasks || this.isSubtaskFilterActive; + }, +}); diff --git a/project_ux/static/src/js/project_task_list_model_patch.js b/project_ux/static/src/js/project_task_list_model_patch.js new file mode 100644 index 00000000..413ebeb5 --- /dev/null +++ b/project_ux/static/src/js/project_task_list_model_patch.js @@ -0,0 +1,25 @@ +import { patch } from "@web/core/utils/patch"; +import { Domain } from "@web/core/domain"; +import { ProjectTaskRelationalModel } from "@project/views/project_task_relational_model"; +import { hasSubtaskLeaf } from "./subtask_domain"; + +patch(ProjectTaskRelationalModel.prototype, { + /** + * When the user filters explicitly by sub-tasks ("Is Sub-Task" filter), + * the core still hides them while the "Show Sub-Tasks" mode is off: it + * injects `display_in_project = True`, which is False for any sub-task + * sharing its parent's project. The result is an empty list with no hint, + * so the sub-task looks like it does not exist. + * + * If the sub-task filter is active, drop that leaf to honor the filter and + * show the sub-tasks without requiring the user to toggle the display mode + * by hand. + */ + _processSearchDomain(domain) { + const processed = super._processSearchDomain(domain); + if (hasSubtaskLeaf(domain)) { + return Domain.removeDomainLeaves(processed, ["display_in_project"]).toList({}); + } + return processed; + }, +}); diff --git a/project_ux/static/src/js/subtask_domain.js b/project_ux/static/src/js/subtask_domain.js new file mode 100644 index 00000000..570545c8 --- /dev/null +++ b/project_ux/static/src/js/subtask_domain.js @@ -0,0 +1,26 @@ +/** + * Whether a search domain explicitly restricts results to sub-tasks, i.e. it + * contains a `parent_id != False` leaf (as emitted by the "Is Sub-Task" + * filter). Walks the domain in list form, including nested sub-domains. + * + * @param {Array} domain domain in list form + * @returns {boolean} + */ +export function hasSubtaskLeaf(domain) { + if (!Array.isArray(domain)) { + return false; + } + for (const item of domain) { + if (!Array.isArray(item)) { + continue; + } + if (item.length === 3) { + if (item[0] === "parent_id" && item[1] === "!=" && item[2] === false) { + return true; + } + } else if (hasSubtaskLeaf(item)) { + return true; + } + } + return false; +} diff --git a/project_ux/static/src/xml/project_task_control_panel.xml b/project_ux/static/src/xml/project_task_control_panel.xml new file mode 100644 index 00000000..9c44022b --- /dev/null +++ b/project_ux/static/src/xml/project_task_control_panel.xml @@ -0,0 +1,20 @@ + + + + + + effectiveShowSubtasks ? 'selected' : '' + + + + + + effectiveShowSubtasks ? 'selected' : '' + + + +