feat(plating): tree-editor import supports insert-before position
The import feature appended every imported node to the end of the target recipe. That's wrong for the common case — General Processing has Shipping as its last operation, so importing an Electroless Nickel pack should land BEFORE Shipping, not after it. The user would otherwise have to click Move Up dozens of times. Controller: /fp/recipe/node/import_children now accepts insert_before_id: null/missing → append at end (default, unchanged) 0 → insert at the start <positive id> → insert right before that top-level child Implementation reorders target's top-level children in one pass after Phase 1 creates the copies (placeholder sequence=0). Phase 2 splits existing vs. new, finds the anchor index in the existing list, and reassigns sequences 10/20/30/... across the merged list. Collisions on the old max_seq-based append strategy are eliminated. JS: state.importInsertBefore drives a new "Insert:" dropdown in the toolbar with options: — At the end — (default) — At the start — Before <each top-level child name> Smoke on entech (3-case): insert-before-middle, insert-at-start, insert-at-end all produce the expected ordering. fusion_plating → 19.0.7.2.0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -120,6 +120,11 @@ export class RecipeTreeEditor extends Component {
|
||||
importRecipeOptions: [],
|
||||
importRecipeId: null,
|
||||
importDedupe: true,
|
||||
// Insertion anchor for the imported nodes. Values:
|
||||
// "" → append at the end (default)
|
||||
// "0" → insert at the start
|
||||
// "<id>" → insert right before that existing top-level child
|
||||
importInsertBefore: "",
|
||||
importing: false,
|
||||
});
|
||||
|
||||
@@ -472,11 +477,21 @@ export class RecipeTreeEditor extends Component {
|
||||
}
|
||||
if (!this._recipeId) return;
|
||||
this.state.importing = true;
|
||||
// Map the UI anchor to the controller's insert_before_id contract:
|
||||
// "" → null (append at end)
|
||||
// "0" → 0 (insert at start)
|
||||
// "<id>" → int (insert before that top-level child)
|
||||
const rawBefore = this.state.importInsertBefore;
|
||||
const insertBeforeId =
|
||||
rawBefore === "" || rawBefore == null
|
||||
? null
|
||||
: parseInt(rawBefore, 10);
|
||||
try {
|
||||
const result = await rpc("/fp/recipe/node/import_children", {
|
||||
source_recipe_id: parseInt(this.state.importRecipeId, 10),
|
||||
target_parent_id: this._recipeId,
|
||||
dedupe_by_name: !!this.state.importDedupe,
|
||||
insert_before_id: insertBeforeId,
|
||||
});
|
||||
if (result && result.ok) {
|
||||
this.notification.add(
|
||||
@@ -485,6 +500,7 @@ export class RecipeTreeEditor extends Component {
|
||||
);
|
||||
this.state.importOpen = false;
|
||||
this.state.importRecipeId = null;
|
||||
this.state.importInsertBefore = "";
|
||||
await this.loadTree();
|
||||
} else {
|
||||
this.notification.add(result?.error || "Import failed.", { type: "warning" });
|
||||
@@ -496,6 +512,15 @@ export class RecipeTreeEditor extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience getter for the XML: the list of top-level children
|
||||
// currently under the open recipe, for the "Insert before" dropdown.
|
||||
// Falls back to [] on an unloaded tree.
|
||||
get topLevelChildren() {
|
||||
const root = this.state.tree;
|
||||
if (!root || !root.children) return [];
|
||||
return root.children;
|
||||
}
|
||||
|
||||
// ---- Navigation ---------------------------------------------------------
|
||||
|
||||
onBackToList() {
|
||||
|
||||
@@ -207,6 +207,17 @@
|
||||
<option t-att-value="r.id" t-esc="r.name"/>
|
||||
</t>
|
||||
</select>
|
||||
<label class="o_fp_re_import_label">Insert:</label>
|
||||
<select class="o_fp_re_import_select o_fp_re_import_pos"
|
||||
t-model="state.importInsertBefore">
|
||||
<option value="">At the end</option>
|
||||
<option value="0">At the start</option>
|
||||
<t t-foreach="topLevelChildren" t-as="c" t-key="c.id">
|
||||
<option t-att-value="c.id">
|
||||
Before <t t-esc="c.name"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
<label class="o_fp_re_import_dedupe">
|
||||
<input type="checkbox" t-model="state.importDedupe"/>
|
||||
Skip duplicate names
|
||||
|
||||
Reference in New Issue
Block a user