From 03f41422dea6a204e0ec2801f1ca6710c30a3077 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Thu, 23 Apr 2026 08:08:55 -0400 Subject: [PATCH] =?UTF-8?q?fix(plating):=20tree=20editor=20=E2=80=94=20tit?= =?UTF-8?q?le=20wrapping=20+=20import=20hierarchy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs reported on the tree editor after the move/import feature shipped: 1. Card titles truncated to "Contrac…" because .o_fp_re_title had white-space: nowrap + text-overflow: ellipsis. Swapped to white-space: normal + overflow-wrap: anywhere so long names wrap onto multiple lines inside the card. Widened card max- width 380→460px and bumped min-width 240→260px so wrapped titles have room. 2. Import-children was flattening the tree — all operations AND their step children landed at the top level instead of staying nested under their operations. Root cause: src_node.copy({'parent_id': new_parent.id, ...}) on a _parent_store model behaved unpredictably — in some runs the override in copy_vals didn't stick and child recursion ended up with a wrong parent_id. Rewrote _copy_subtree to use copy_data() + Node.create() so parent_id is set explicitly and child_ids / parent_path are stripped (we recurse ourselves). Smoke verified on entech: General Processing (1 root + 5 ops + 7 steps = 13 nodes) imports with hierarchy bit-identical to source. fusion_plating → 19.0.7.1.0 Co-Authored-By: Claude Opus 4.7 (1M context) --- fusion_plating/fusion_plating/__manifest__.py | 2 +- .../controllers/recipe_controller.py | 29 +++++++++++++------ .../static/src/scss/recipe_tree_editor.scss | 17 +++++++---- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/fusion_plating/fusion_plating/__manifest__.py b/fusion_plating/fusion_plating/__manifest__.py index c30e4970..83279546 100644 --- a/fusion_plating/fusion_plating/__manifest__.py +++ b/fusion_plating/fusion_plating/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating', - 'version': '19.0.7.0.0', + 'version': '19.0.7.1.0', 'category': 'Manufacturing/Plating', 'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.', 'description': """ diff --git a/fusion_plating/fusion_plating/controllers/recipe_controller.py b/fusion_plating/fusion_plating/controllers/recipe_controller.py index d8a77e75..27cd1bf9 100644 --- a/fusion_plating/fusion_plating/controllers/recipe_controller.py +++ b/fusion_plating/fusion_plating/controllers/recipe_controller.py @@ -233,15 +233,26 @@ class FpRecipeController(http.Controller): max_seq = max((c.sequence for c in target.child_ids), default=0) def _copy_subtree(src_node, new_parent, base_seq): - """Deep-copy src_node under new_parent, recursing children.""" - copy_vals = { - 'parent_id': new_parent.id, - 'sequence': base_seq, - } - # copy() picks up every other field; we only override parent + seq. - new_node = src_node.copy(copy_vals) - # Recurse — child_ids of the copy are blank (Odoo doesn't - # deep-copy one2many children by default for this model) + """Deep-copy src_node under new_parent, recursing children. + + Uses copy_data() + manual create() rather than copy() so we + have full control over what's carried: + * strip child_ids (we recurse ourselves) + * strip parent_path (Odoo recomputes from parent_id) + * force parent_id + sequence to our target values + + The previous copy()-based version sometimes produced a + flattened tree because copy() on a _parent_store model can + leave parent_id pointed at the original source when the + override in copy_vals collides with the field's copy= flag. + copy_data() returns a plain dict — safer. + """ + [vals] = src_node.copy_data() + vals.pop('child_ids', None) + vals.pop('parent_path', None) + vals['parent_id'] = new_parent.id + vals['sequence'] = base_seq + new_node = Node.create(vals) for i, child in enumerate(src_node.child_ids.sorted('sequence'), 1): _copy_subtree(child, new_node, i * 10) return new_node diff --git a/fusion_plating/fusion_plating/static/src/scss/recipe_tree_editor.scss b/fusion_plating/fusion_plating/static/src/scss/recipe_tree_editor.scss index 083e4cc0..d33dad35 100644 --- a/fusion_plating/fusion_plating/static/src/scss/recipe_tree_editor.scss +++ b/fusion_plating/fusion_plating/static/src/scss/recipe_tree_editor.scss @@ -241,10 +241,10 @@ $re-line-w : 2px; display: inline-flex; align-items: center; gap: 10px; - min-width: 240px; - max-width: 380px; + min-width: 260px; + max-width: 460px; min-height: $re-card-h; - padding: 8px 12px; + padding: 10px 12px; background-color: #2b2f36; color: #f1f3f5; border-radius: 10px; @@ -343,10 +343,15 @@ $re-line-w : 2px; gap: 2px; } .o_fp_re_title { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + // Let long node names wrap onto multiple lines so the card shows + // the whole title (e.g. "Final Inspection / Packaging") instead + // of cutting to "Final I…". word-break handles CJK / no-space + // strings gracefully; line-height keeps the card compact. font-weight: 600; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; + line-height: 1.25; } .o_fp_re_meta { font-size: 0.72rem;