@crystaldesign/diva-backoffice 26.12.0-beta.24 → 26.12.0-beta.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (16) hide show
  1. package/build/esm/index.js +640 -1724
  2. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/backofficeToolset.d.ts +2 -0
  3. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/backofficeToolset.d.ts.map +1 -1
  4. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/contentToolset.d.ts +3 -2
  5. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/contentToolset.d.ts.map +1 -1
  6. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/mediaToolset.d.ts +3 -3
  7. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/mediaToolset.d.ts.map +1 -1
  8. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/navigationToolset.d.ts +3 -5
  9. package/build/types/backoffice/src/layout/Toolbar/Tools/DivaAgent/navigationToolset.d.ts.map +1 -1
  10. package/build/types/backoffice/src/tests/unit/layout/Toolbar/Tools/DivaAgent/agentToolNames.test.d.ts +2 -0
  11. package/build/types/backoffice/src/tests/unit/layout/Toolbar/Tools/DivaAgent/agentToolNames.test.d.ts.map +1 -0
  12. package/package.json +10 -10
  13. package/build/types/backoffice/src/tests/unit/layout/Toolbar/Tools/DivaAgent/agentToolDefs.test.d.ts +0 -2
  14. package/build/types/backoffice/src/tests/unit/layout/Toolbar/Tools/DivaAgent/agentToolDefs.test.d.ts.map +0 -1
  15. package/build/types/backoffice/src/tests/unit/layout/Toolbar/Tools/DivaAgent/navigationToolDefs.test.d.ts +0 -2
  16. package/build/types/backoffice/src/tests/unit/layout/Toolbar/Tools/DivaAgent/navigationToolDefs.test.d.ts.map +0 -1
@@ -51286,391 +51286,8 @@ function summarizeFailures(failed) {
51286
51286
  });
51287
51287
  }
51288
51288
 
51289
- /** Definitions of the navigation/grid tools this toolset executes — sent to the backend per turn. */
51290
- /** Argument names the model tends to use for a table (measured in live sessions) - declared on every tool that takes a `grid`. */
51291
- var GRID_ARG_ALIASES = {
51292
- table: 'grid',
51293
- gridId: 'grid'
51294
- };
51295
- var NAVIGATION_TOOL_DEFS = [{
51296
- name: 'listViews',
51297
- description: 'List the navigable backoffice views (permission-filtered menu + current editor sub-views) and the current location.',
51298
- input_schema: {
51299
- type: 'object',
51300
- properties: {}
51301
- }
51302
- }, {
51303
- name: 'navigateTo',
51304
- description: 'Navigate the backoffice to a view path from listViews, or to an editor path built from a record _id (a persistent 24-hex id, from the _id column) — NEVER the sessional rowId from readGridRows. The view and this chat reload and the turn ends automatically — announce the navigation to the user BEFORE calling.',
51305
- input_schema: {
51306
- type: 'object',
51307
- properties: {
51308
- path: {
51309
- type: 'string',
51310
- description: 'a path exactly as returned by listViews, or an editor path built from a record _id'
51311
- }
51312
- },
51313
- required: ['path']
51314
- },
51315
- endsTurn: true,
51316
- // Settled only once the requested view is mounted — the series view took 40 s on a slow tab.
51317
- settle: {
51318
- timeoutMs: 30000,
51319
- pathArgument: 'path'
51320
- }
51321
- }, {
51322
- name: 'reloadPlanner',
51323
- description: 'Discard the loaded planner instance(s) of the current catalog/package so the next planner use loads CURRENT data — call it after COMMITTED catalog-data changes BEFORE any planner verification (the instance was initialized with pre-change data; same effect as the configurator reload button). The turn ends automatically — announce it BEFORE calling.',
51324
- input_schema: {
51325
- type: 'object',
51326
- properties: {}
51327
- },
51328
- endsTurn: true
51329
- }, {
51330
- name: 'reloadPage',
51331
- description: 'FULL browser page reload of the backoffice (what the user does with F5) — the ONLY way a series/items.decisionRefs change or a media entry/gate change reaches the planner: reloadPlanner rebuilds the instance from the SAME pre-change article payload, a page reload fetches it anew. Refused while a table has staged, unapproved edits (a reload would lose them — let the user Übernehmen/Verwerfen first). The chat is persisted and reopens on this conversation; the turn ends automatically and an automatic "Continue." follows once the view is ready — announce the reload to the user BEFORE calling, and verify with listDecisions/getMediaInfo afterwards.',
51332
- input_schema: {
51333
- type: 'object',
51334
- properties: {}
51335
- },
51336
- endsTurn: true
51337
- }, {
51338
- name: 'listGrids',
51339
- description: 'List the tables currently on screen with their column field ids, headers, metadata and loaded row counts. Pass `grid` for ONE table, `compact` for field ids only; a table with more than 150 columns (the prices matrix grows one per finish) answers compact on its own and says so.',
51340
- input_schema: {
51341
- type: 'object',
51342
- properties: {
51343
- grid: {
51344
- type: 'string',
51345
- description: 'only this table (label or gridId from a previous listGrids)'
51346
- },
51347
- compact: {
51348
- type: 'boolean',
51349
- description: 'field ids only, no headers or metadata — readGridRows.columnMeta has the metadata of the columns you read'
51350
- }
51351
- }
51352
- },
51353
- argAliases: GRID_ARG_ALIASES
51354
- }, {
51355
- name: 'locateRow',
51356
- description: "Locate a row in an on-screen table: already-loaded rows are scrolled to and flashed directly (no filter); rows not loaded yet are found via a server-side column filter (filterApplied:true in the result — the filter narrows the visible table, clearGridFilter restores it). EXACT ALWAYS WINS: an equals match is tried first (numbers and text alike); only when NONE exists does it fall back to a loose contains/prefix candidate — the result then carries `exact:false` and the `note` says so explicitly, it is never disguised as a genuine hit (a contains-match on a KEY column can otherwise stand in for a value that was never actually there, e.g. serieNo '9' resolving to '99'). Pass `exact:true` to reject a loose candidate outright (matchedRows:0) instead of returning it. Optionally selects the match (main-table selection reveals the subtable). ALSO THE CHEAPEST RECORD READ: the returned `firstRow` carries the record fields including ones that are not grid columns at all (featureRefs, catalogId, the raw localized JSON of a name column) — useful fields first, and on very wide records `firstRowOmittedFields` names what did not fit — plus toolbarTools and gridsOnScreen in the same answer. For \"what does this record actually contain\" it beats readGridRows on completeness AND tokens; reach for readGridRows when you want MANY rows, for locateRow when you want ONE row whole. BULK READ: pass 'values' (an array) to fetch SEVERAL records by the same column in ONE call — on a fully loaded table the rows are read directly, otherwise they go to the server as ONE combined equals filter per 50 values (not one lookup per value, so 100 values cost two server round trips): one trimmed row per value, misses and values that hit no UNIQUE exact row listed separately, no selection, no loose matching. Use it whenever you would otherwise chain locateRow calls (collecting reference ids, pre-write checks), and hand over the WHOLE list — splitting it into batches of a handful only multiplies the calls.",
51357
- input_schema: {
51358
- type: 'object',
51359
- properties: {
51360
- grid: {
51361
- type: 'string',
51362
- description: 'table label from listGrids (default: first table)'
51363
- },
51364
- column: {
51365
- type: 'string',
51366
- description: 'column FIELD id from listGrids'
51367
- },
51368
- value: {
51369
- type: 'string',
51370
- description: 'value to search for — an EXACT (equals) match is tried first; only without one does this fall back to a loose contains/prefix candidate (see `exact` in the result)'
51371
- },
51372
- values: {
51373
- type: 'array',
51374
- items: {
51375
- type: 'string'
51376
- },
51377
- description: 'BULK READ: several values (a whole list, hundreds are fine) to locate in ONE call — one combined server filter per 50 values; returns one row per value plus the misses; no selection'
51378
- },
51379
- select: {
51380
- type: 'boolean',
51381
- description: 'also select the first matching row (default true; ignored for values[])'
51382
- },
51383
- exact: {
51384
- type: 'boolean',
51385
- description: 'when true, a loose (non-exact) candidate is rejected as matchedRows:0 instead of being returned (default false — a loose candidate is still returned, but flagged exact:false)'
51386
- }
51387
- },
51388
- required: ['column']
51389
- },
51390
- argAliases: _objectSpread$X(_objectSpread$X({}, GRID_ARG_ALIASES), {}, {
51391
- keyColumn: 'column',
51392
- keyValue: 'value'
51393
- })
51394
- }, {
51395
- name: 'openToolbarTool',
51396
- description: "Open a toolbar tool by its id (see TOOLBAR TOOLS / locateRow's toolbarTools) — e.g. a subtable revealed by selecting a row. Its table then appears in listGrids and locateRow can target it. Needed only ONCE per subtable: while it stays open, selecting a new parent row auto-refreshes it, so if it is already in locateRow's gridsOnScreen, readGridRows it directly instead of re-opening. ALWAYS VERIFY THE RESULT: the `ok` it returns means the click was dispatched, NOT that the table opened — read `gridsNowOnScreen`, which tells the truth. It CANNOT switch between SIBLING TABS of one bottom panel: a price feature group shows Finishes and Prozentuale Mehrpreise as two tabs, selecting the group auto-activates Finishes, and this tool cannot activate the other one (measured 2026-08-22 on both an empty group and one with 120 finishes — the finishes have nothing to do with it). Such a tab has to be clicked by the USER once; afterwards its grid registers normally (`percentagesurcharges`) and is fully readable and writable. So when `gridsNowOnScreen` does not list the table you asked for, do not retry — tell the user to click that tab.",
51397
- input_schema: {
51398
- type: 'object',
51399
- properties: {
51400
- id: {
51401
- type: 'string',
51402
- description: 'tool id from toolbarTools'
51403
- }
51404
- },
51405
- required: ['id']
51406
- },
51407
- // Declared, not hand-handled: an undeclared top-level argument is rejected by normalizeAndValidateInput
51408
- // before this toolset is dispatched at all, so a fallback inside the case could never run.
51409
- argAliases: {
51410
- toolId: 'id'
51411
- }
51412
- }, {
51413
- name: 'readGridRows',
51414
- description: "Read the ALREADY-LOADED rows of an on-screen table: stable rowId + the requested column values per row. THE way to know what is actually in the table (real keys, current values) before editing or reporting — never guess row keys. Server-side lazy tables only expose loaded rows (scroll/locateRow loads more). There is NO paging: `limit` truncates the loaded slice, it cannot fetch further rows, so a large table is not fully readable here — narrow it with a filter, use locateRow for one record, or getFeature/readColumnOptions for a feature's options. Requested columns that are not columns of the table are reported in `unknownColumns`/`fieldsNote` rather than dropped; a record field that is not a grid column (e.g. featureRefs) is only readable via locateRow(select:true).firstRow. `columns` in the answer lists what was RETURNED, not what the table has — without an explicit `columns` argument that is the first 10 leaf fields, and `columnsShown` says how many exist; NEVER conclude a column does not exist from its absence there (ask listGrids or name it explicitly). NEVER DIFF CATALOG STATE BY `lastUpdatedDate`: a server-side CASCADE writes records without stamping it and in places REMOVES the field, so the row that was changed can read OLDER than its untouched neighbour — measured on a condition row rewritten by a cascade, on the options it cleaned, and on a parent row after a subtable commit. Compare the VALUES you care about instead. SUBTABLE SHORTCUT: parentRow {grid, column, value, tool} selects the parent row, opens its subtable tool and reads THAT — same shape as in stageTableEdits, no locateRow/openToolbarTool round-trip.",
51415
- input_schema: {
51416
- type: 'object',
51417
- properties: {
51418
- grid: {
51419
- type: 'string',
51420
- description: 'table label from listGrids (default: first table; with parentRow: the subtable label, may be omitted)'
51421
- },
51422
- parentRow: {
51423
- type: 'object',
51424
- description: "OPTIONAL subtable prelude: select this row in its (parent) table and open its subtable toolbar tool, then read the subtable — replaces separate locateRow + openToolbarTool calls (e.g. {grid:'decisions', column:'decisionNo', value:'130', tool:'optionCombinations'})",
51425
- properties: {
51426
- grid: {
51427
- type: 'string',
51428
- description: 'the PARENT table label (default: first table)'
51429
- },
51430
- column: {
51431
- type: 'string',
51432
- description: 'parent column FIELD id to match'
51433
- },
51434
- value: {
51435
- type: 'string',
51436
- description: 'the EXACT value identifying the parent row — a loose/contains match is rejected, give the precise value or address the row a different way'
51437
- },
51438
- tool: {
51439
- type: 'string',
51440
- description: "the subtable's toolbar tool id (see toolbarTools / TOOLBAR TOOLS)"
51441
- }
51442
- },
51443
- required: ['column', 'value', 'tool']
51444
- },
51445
- columns: {
51446
- type: 'array',
51447
- items: {
51448
- type: 'string'
51449
- },
51450
- description: 'column FIELD ids to return (default: first columns). Localized columns need their language variant, e.g. featureClassName.DE'
51451
- },
51452
- limit: {
51453
- type: 'number',
51454
- description: 'max rows to RETURN from the already-loaded slice (default 200, capped at 500). NOT a page size — it cannot load rows the grid has not fetched'
51455
- }
51456
- }
51457
- },
51458
- argAliases: GRID_ARG_ALIASES
51459
- }, {
51460
- name: 'readColumnOptions',
51461
- description: "List the selectable options of a lookup column (its values come from the backend, like the column's dropdown editor). Returns {value, label} pairs — the VALUEs are what rules and stored cells reference; stage lookup edits with the VALUE(s), comma-separated on multi-select columns. 'search' narrows by key or display text. ALSO answers a table ACTION's value list: pass the ACTION NAME (from listGrids' actions) as `column` and it returns what runTableAction accepts for it — that is the headless form of the dialog the action's button opens, so never try to drive a modal.",
51462
- input_schema: {
51463
- type: 'object',
51464
- properties: {
51465
- grid: {
51466
- type: 'string',
51467
- description: 'table label from listGrids (default: first table)'
51468
- },
51469
- column: {
51470
- type: 'string',
51471
- description: 'the lookup column FIELD id, or the NAME of a table action from listGrids'
51472
- },
51473
- search: {
51474
- type: 'string',
51475
- description: 'optional filter (key or display text)'
51476
- },
51477
- exact: {
51478
- type: 'boolean',
51479
- description: 'only options whose VALUE or label EQUALS the search — the existence check a contains-match answers wrongly'
51480
- },
51481
- limit: {
51482
- type: 'number',
51483
- description: 'max options (default 50)'
51484
- }
51485
- },
51486
- required: ['column']
51487
- },
51488
- argAliases: GRID_ARG_ALIASES
51489
- }, {
51490
- name: 'stageTableEdits',
51491
- description: "Change table data WITH the user's approval, in bulk: cell edits, new rows and row removals are ALL staged at once (highlighted in the table, nothing saved yet), the user gets ONE Übernehmen/Verwerfen bar on the table, and only Übernehmen commits everything through the table's normal edit path. Rows are addressed by keyColumn+keyValue (a column value that is UNIQUE in the table, e.g. typeNo='ART_001' — the row is located for you, no locateRow/readGridRows round-trip) or by rowId from readGridRows; when a keyColumn value is NOT unique (e.g. a typeNo that recurs in the prices matrix) it cannot disambiguate — readGridRows and address those rows by rowId instead. MULTIPLE existing rows in ONE call (different keyValues, e.g. a whole batch of prices/retailArticleNr edits) are fully supported, including rows that are not yet loaded on screen (a big table like prices): each such row is located, staged and saved on its own — sequentially, before the next lookup runs, so one row is never lost to another row's server-side lookup — while the ONE approval for the whole call still covers everything; the trade-off is that the approval bar then shows a COUNT of intended changes instead of highlighted cells, because most rows are not loaded yet when the user has to decide. A LOOKUP cell write (e.g. items.decisionRefs) resolves an EXACT identity key (its decisionNo etc.) FIRST, before any label-text search runs — a short numeric key is never crowded out by unrelated rows whose label text happens to contain the same digits. SUBTABLE work in the same call: parentRow {grid, column, value, tool} selects the parent row, opens its subtable tool and targets it — pass it on EVERY subtable write, because WITHOUT it nothing re-binds the parent: the edit lands under the parent row the open subtable is bound to (whichever an earlier call left selected), named in the receipt as boundParentRow — check it before building on the write — and a subtable bound to no parent row REFUSES the write. CAUTION when the parent column DEFINES the subtable's columns (a decision's `featureRefs` drives its optioncombinations columns): changing it REBUILDS the subtable, and the rebuild can overrun a cell write that has not settled yet — an ESTABLISHED neighbour cell is emptied silently and nothing in the response reports the loss. So: set the parent column to its FINAL value in one edit, THEN write the subtable cells, THEN read them back — and never let a `featureRefs` edit directly follow a cell write; put a read between them and re-read after every rebuild. Removing a column from `featureRefs` DOES delete its values — nothing stays orphaned in the record, no cleanup ritual is needed. But the PLANNER resolves a decision's rows when its instance starts, so `getDecision` can still report the OLD condition long after the grid is correct: never treat an engine read as evidence about a change you just made — `reloadPlanner` first, then cross-read. The grid and the record are the truth here; the engine is a snapshot. For addRows: FIRST check the table's column metadata (listGrids) and fill EVERY column marked 'required' that is not marked 'defaulted' — one missing required column fails the ENTIRE staging. Blocks until the user decides. Put every related change into ONE call — but keep the payload MODERATE: a very large or deeply-nested addRows/edits array can exceed the function-call parse limit and fail as MALFORMED. Split big operations (a whole item list, dozens of finishes) across several calls, and build a new catalog TOP-DOWN (shell row first, navigate into the editor, then section by section) instead of one mega-call. One call stages at most 500 rows — not a server limit (a bulk table sends every staged row in ONE request) but a browser one, since every staged row is a live grid row; a payload cannot be sliced, so a bigger file is uploaded in parts of at most 500 rows and each part written in its own call (a dryRun is exempt: it can check a whole file at once, before you split it). WHICH ROUTE FOR NEW ROWS — decide by the COUNT before you type a single row, and count the rows the TASK names, not the ones you have typed so far: (1) a handful → addRows. (2) up to about fifty → addRowsTsv (a HEADER line of column field ids, then one tab-separated line per row): the same information without repeating every key. (3) MCP only — from about fifty rows on, and at any count for rows that already exist as a file, a script's or query's output or an export: your harness writes them to a file and posts it once to the payload route (your MCP endpoint URL with /mcp replaced by /bridge/payloads, same Bearer token — the `source` parameter says how), and you pass source:{payloadId} plus `mapping` for foreign column names; the call then costs the same for ten rows as for five hundred and you never read the rows into your context. Composing the rows rather than copying them changes nothing about which route they take — a list you can print from your shell is a file. In the in-app chat there is no upload, so such rows go as addRowsTsv. Rule of thumb: if writing the rows out would cost more tokens than the rest of the task, they go by reference. Run such a call once with dryRun:true — every row is checked before anything is staged, and the answer is counts plus the distinct problems",
51492
- input_schema: {
51493
- type: 'object',
51494
- properties: {
51495
- grid: {
51496
- type: 'string',
51497
- description: 'table label from listGrids (default: first table; with parentRow: the subtable label, may be omitted)'
51498
- },
51499
- parentRow: {
51500
- type: 'object',
51501
- description: "OPTIONAL subtable prelude: select this row in its (parent) table and open its subtable toolbar tool, then stage into the subtable — replaces separate locateRow + openToolbarTool calls (e.g. {grid:'pricefeaturegroups', column:'priceFeatureGroupNo', value:'1', tool:'priceFeatureGroupFinishes'})",
51502
- properties: {
51503
- grid: {
51504
- type: 'string',
51505
- description: 'the PARENT table label (default: first table)'
51506
- },
51507
- column: {
51508
- type: 'string',
51509
- description: 'parent column FIELD id to match'
51510
- },
51511
- value: {
51512
- type: 'string',
51513
- description: 'the EXACT value identifying the parent row — a loose/contains match is rejected, give the precise value or address the row a different way'
51514
- },
51515
- tool: {
51516
- type: 'string',
51517
- description: "the subtable's toolbar tool id (see toolbarTools / TOOLBAR TOOLS)"
51518
- }
51519
- },
51520
- required: ['column', 'value', 'tool']
51521
- },
51522
- source: {
51523
- type: 'object',
51524
- description: "ROWS BY REFERENCE (MCP only): the rows of a payload your own harness uploaded, instead of listing them here — the route for every batch from about fifty rows on, and for rows that already exist as a file, an export or a script's or query's output, at any count. POST them once, as a JSON array of row objects, to your MCP endpoint URL with its trailing /mcp replaced by /bridge/payloads (https://…/diva-agent/mcp → https://…/diva-agent/bridge/payloads) with the same bridge token your MCP connection is configured with (PAYLOAD_URL=\"${DIVA_BRIDGE_URL%/mcp}/bridge/payloads\"; curl -X POST \"$PAYLOAD_URL\" -H \"Authorization: Bearer $DIVA_BRIDGE_TOKEN\" -H 'Content-Type: application/json' --data-binary @rows.json, so neither the rows nor the token enter the conversation; those two environment variables are the only source for the URL and the token — never search config files, keychains or credential stores for them, and when they are unset ask the user in one line rather than typing the rows into the call), then name the returned id: {payloadId:'pl_…'}. The upload answer lists the payload's columns and three sample rows — check the shape there instead of reading the file. The call is then the same size for 10 rows as for 500. An upload takes at most 5 MB, one write stages at most 500 rows, and a payload cannot be sliced — so upload a bigger file in parts of at most 500 rows and name each part in its own call; you may hold ten payloads at a time (DELETE the ones you are done with). Combine with `mapping`, and run it once with dryRun:true to have every row checked.",
51525
- properties: {
51526
- payloadId: {
51527
- type: 'string',
51528
- description: 'id returned by the payload upload'
51529
- }
51530
- },
51531
- required: ['payloadId']
51532
- },
51533
- mapping: {
51534
- type: 'object',
51535
- description: "With `source`: source field name → this table's column FIELD id (e.g. {'Artikelnr':'typeNo','Bezeichnung':'name.DE'}). Every name must be a column of the payload (its upload answer lists them). A field the mapping does NOT name is left out, so a prepared file with extra columns needs no editing. Omit it when the payload already uses the table's field ids.",
51536
- additionalProperties: {
51537
- type: 'string'
51538
- }
51539
- },
51540
- addRowsTsv: {
51541
- type: 'string',
51542
- description: "The same rows as `addRows`, in spreadsheet shape: a HEADER line of column FIELD ids, then one tab-separated line per row (e.g. 'typeNo\\tsequenceNo\\nART_001\\t10\\nART_002\\t20'). Carries the same information without repeating the keys, which keeps a MODERATE batch — up to about fifty rows — inside one call; from there on the rows go through `source` instead of into the call. An empty cell leaves that column UNSET (its default applies), values may not contain tabs or newlines. Combines with addRows."
51543
- },
51544
- dryRun: {
51545
- type: 'boolean',
51546
- description: 'Report what WOULD happen and stage nothing: with addRows or a payload `source`, how many rows pass the column rules and which ones do not, as counts plus the failing rows. This is how you check rows you never read.'
51547
- },
51548
- edits: {
51549
- type: 'array',
51550
- description: 'cell changes on existing rows',
51551
- items: {
51552
- type: 'object',
51553
- properties: {
51554
- keyColumn: {
51555
- type: 'string',
51556
- description: 'column FIELD id whose value uniquely identifies the row (e.g. typeNo, serieNo, decisionNo)'
51557
- },
51558
- keyValue: {
51559
- type: 'string',
51560
- description: 'the unique value — the row is located for you (server-side if not loaded)'
51561
- },
51562
- rowId: {
51563
- type: 'string',
51564
- description: 'ALTERNATIVE addressing: stable row id from readGridRows'
51565
- },
51566
- column: {
51567
- type: 'string',
51568
- description: 'column FIELD id to change'
51569
- },
51570
- newValue: {
51571
- type: 'string',
51572
- description: "new value as text, parsed by the column itself like a typed value: numbers with '.' as decimal point and no thousands separators, dates as ISO 'YYYY-MM-DD', boolean columns true or false, enum columns the VALUE (or its label); empty string clears the cell; lookup columns: option VALUE(s) from readColumnOptions, comma-separated when multi-select. A value the column cannot hold is refused, never stored"
51573
- }
51574
- },
51575
- required: ['column', 'newValue']
51576
- }
51577
- },
51578
- addRows: {
51579
- type: 'array',
51580
- description: 'new rows to create (inserted as pending rows at the table top)',
51581
- items: {
51582
- type: 'object',
51583
- properties: {
51584
- values: {
51585
- type: 'object',
51586
- description: "column FIELD id → value. MUST cover every column listGrids marks 'required' (numbers, enums, texts alike — sequenceNo etc.), EXCEPT columns marked 'defaulted' (omit those, they fill themselves). NEVER include readOnly columns (they belong to a subtable or the server). Enum/lookup columns take ONLY their listed values (columnMeta.allowedValues / readColumnOptions) — never invent codes like 'MOEBEL'. Check the metadata BEFORE composing instead of learning the schema from validation errors. Never invent identity key values — take them from the user/task."
51587
- }
51588
- },
51589
- required: ['values']
51590
- }
51591
- },
51592
- removeRowIds: {
51593
- type: 'array',
51594
- items: {
51595
- type: 'string'
51596
- },
51597
- description: 'rows to DELETE (rowIds from readGridRows) — shown struck-through until the user approves'
51598
- },
51599
- removeRows: {
51600
- type: 'array',
51601
- description: 'rows to DELETE addressed by unique key (no rowId needed)',
51602
- items: {
51603
- type: 'object',
51604
- properties: {
51605
- keyColumn: {
51606
- type: 'string',
51607
- description: 'column FIELD id whose value uniquely identifies the row'
51608
- },
51609
- keyValue: {
51610
- type: 'string',
51611
- description: 'the unique value'
51612
- }
51613
- },
51614
- required: ['keyColumn', 'keyValue']
51615
- }
51616
- }
51617
- }
51618
- },
51619
- requiresEditPermission: true,
51620
- argAliases: GRID_ARG_ALIASES
51621
- }, {
51622
- name: 'runTableAction',
51623
- description: "Run a table-specific action listed under 'actions' in listGrids — view-defined operations beyond cell edits (e.g. adding a feature COLUMN to a decision's option combinations). Mutating actions show the user an approval bar on the table first — announce the action BEFORE calling; the tool blocks until the user decides. The target table must be ON SCREEN (in listGrids): for a SUBTABLE action — e.g. addColumn on a price feature group's finishes — first bring the subtable up (locateRow the parent row → openToolbarTool the subtable), then run the action on it; runTableAction has NO parentRow shortcut (unlike stageTableEdits). addColumn takes ONE key or a COMMA-LIST as input ('940,949'): all keys are validated up front, ONE approval covers them, then they are added sequentially. removeColumn drops ONE such column again: input = its field id ('optionsSetRefs.2305') or the bare key ('2305'); on a decision's option combinations and a price feature group's finishes/surcharges the server also strips that feature's cells from every row, on partlist positions the cells stay behind hidden. Every action DESCRIBES its own input in listGrids — read that text, never guess a shape; when the action offers a picker, readColumnOptions(<action name>) lists exactly what it accepts.",
51624
- input_schema: {
51625
- type: 'object',
51626
- properties: {
51627
- grid: {
51628
- type: 'string',
51629
- description: 'table label from listGrids (default: first table)'
51630
- },
51631
- action: {
51632
- type: 'string',
51633
- description: 'action name from listGrids actions'
51634
- },
51635
- input: {
51636
- type: 'string',
51637
- description: "the action's input — see its description"
51638
- }
51639
- },
51640
- required: ['action']
51641
- },
51642
- requiresEditPermission: true,
51643
- argAliases: _objectSpread$X(_objectSpread$X({}, GRID_ARG_ALIASES), {}, {
51644
- values: 'input'
51645
- })
51646
- }, {
51647
- name: 'clearGridFilter',
51648
- description: 'Remove the filters locateRow applied so the table shows all rows again. Do NOT call it right after a successful locateRow — the filter is what presents the match to the user.',
51649
- input_schema: {
51650
- type: 'object',
51651
- properties: {
51652
- grid: {
51653
- type: 'string',
51654
- description: 'table label from listGrids (default: first table)'
51655
- }
51656
- }
51657
- },
51658
- argAliases: GRID_ARG_ALIASES
51659
- }, {
51660
- name: 'discardStagedChanges',
51661
- description: 'Discard the STAGED, uncommitted changes of a table — the rescue for a partially rejected batch that left orphaned staging behind: while it sits there every further write to that table is refused and so is reloadPage, and until now only the user could clear it (Verwerfen). It drops agent-staged AND user-staged edits alike, so say what you are about to drop. This call itself sends nothing to the server — but the grid saves pending edits by itself when the user clicks outside it, and the receipt says so when that happened while the bar was open. Returns whether anything was pending.',
51662
- input_schema: {
51663
- type: 'object',
51664
- properties: {
51665
- grid: {
51666
- type: 'string',
51667
- description: 'table label from listGrids (default: first table)'
51668
- }
51669
- }
51670
- },
51671
- requiresEditPermission: true,
51672
- argAliases: GRID_ARG_ALIASES
51673
- }];
51289
+ /** The navigation/grid tools this toolset executes — defined by the diva AI service (tools/browser/navigation.ts). */
51290
+ var NAVIGATION_TOOL_NAMES = ['listViews', 'navigateTo', 'reloadPlanner', 'reloadPage', 'listGrids', 'locateRow', 'openToolbarTool', 'readGridRows', 'readColumnOptions', 'stageTableEdits', 'runTableAction', 'clearGridFilter', 'discardStagedChanges'];
51674
51291
 
51675
51292
  /** The editors' sub-views, mirroring the routers' permission gates: without the edit permission only the list view exists. */
51676
51293
  function permittedEditorViews(root) {
@@ -52489,7 +52106,7 @@ function bulkLocateRows(_x6, _x7, _x8, _x9) {
52489
52106
  /** Audit stamps come LAST so they never crowd payload fields out of the row preview. */
52490
52107
  function _bulkLocateRows() {
52491
52108
  _bulkLocateRows = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee15(api, column, values, deadline) {
52492
- var resolved, colDef, budget, result, numeric, judge, partlyLoaded, pending, _i16, _arr4, value, loaded, groups, chunkSize, _iterator27, _step27, _loop10;
52109
+ var resolved, colDef, budget, result, numeric, judge, partlyLoaded, pending, _i15, _arr4, value, loaded, groups, chunkSize, _iterator27, _step27, _loop10;
52493
52110
  return _regeneratorRuntime.wrap(function _callee15$(_context23) {
52494
52111
  while (1) switch (_context23.prev = _context23.next) {
52495
52112
  case 0:
@@ -52531,13 +52148,13 @@ function _bulkLocateRows() {
52531
52148
  // nothing about a second row further down, so such values go to the server like the unloaded ones.
52532
52149
  partlyLoaded = hasUnloadedDisplayedRows(api);
52533
52150
  pending = [];
52534
- _i16 = 0, _arr4 = _toConsumableArray(new Set(values));
52151
+ _i15 = 0, _arr4 = _toConsumableArray(new Set(values));
52535
52152
  case 13:
52536
- if (!(_i16 < _arr4.length)) {
52153
+ if (!(_i15 < _arr4.length)) {
52537
52154
  _context23.next = 23;
52538
52155
  break;
52539
52156
  }
52540
- value = _arr4[_i16];
52157
+ value = _arr4[_i15];
52541
52158
  if (!(colDef.cellDataType === 'number' && Number.isNaN(Number(value)))) {
52542
52159
  _context23.next = 18;
52543
52160
  break;
@@ -52548,7 +52165,7 @@ function _bulkLocateRows() {
52548
52165
  loaded = exactRowsOf(api, column, value, numeric(value));
52549
52166
  if (loaded.length > 1 || loaded.length === 1 && !partlyLoaded) judge(value, loaded, partlyLoaded);else pending.push(value);
52550
52167
  case 20:
52551
- _i16++;
52168
+ _i15++;
52552
52169
  _context23.next = 13;
52553
52170
  break;
52554
52171
  case 23:
@@ -53051,7 +52668,7 @@ function createNavigationToolset(ctx) {
53051
52668
  }();
53052
52669
  return {
53053
52670
  useCase: 'backoffice',
53054
- tools: NAVIGATION_TOOL_DEFS,
52671
+ toolNames: NAVIGATION_TOOL_NAMES,
53055
52672
  // Structural facts read fresh per turn; the backend formats them into its dynamic prompt sections.
53056
52673
  getFacts: function getFacts() {
53057
52674
  var _root$dataStore;
@@ -53136,52 +52753,45 @@ function createNavigationToolset(ctx) {
53136
52753
  },
53137
52754
  dispatch: function () {
53138
52755
  var _dispatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee11(name, input, signal, onProgress) {
53139
- var awaitingApproval, args, _i2, _Object$entries, _Object$entries$_i, alias, canonical, from, _allViews2, views, editorSubviews, _args$path, _root$navigationState2, _allViews3, _views, _editorSubviews, requested, dynamic, known, catalogIdIn, fromCatalog, toCatalog, only, entries, compactWanted, fullWanted, _args$value, _resolveGrid, entry, api, error, multiValues, filterBeforeBulk, deadline, bulk, _api$getFilterModel, rows, _bulk, missing, unverified, notUnique, notReached, filterBeforeLocate, located, _args$value2, matchedRows, _cellValueOf2, matchedValue, gridsOnScreen, subtableHint, trimmedFirstRow, revealNote, revealed, _args$id, openError, _entry$getHandle$getD, _entry$getHandle2, _lastNode$data, _entry$getHandle$hasP, _entry$getHandle3, _api$getFilterModel2, prelude, _resolveGrid2, _entry, _api, _error, waitedForRowsMs, previewCell, divaDefs, leafFields, _requested, columns, unknownColumns, limit, _rows, displayed, unsavedRowCount, i, _api$getDisplayedRowA, context, _i3, node, values, truncatedColumns, _iterator5, _step5, column, raw, columnMeta, lastNode, gridContext, hasCreatorRow, creatorRowLoaded, totalRowCount, dirty, filterModel, filteredBy, _ref26, _ref27, _staged$0$rowId, _staged$, _addedRows$, _outcome$committed, _root$navigationState3, _outcome$failed, _outcome$skipped, KNOWN_KEYS, ALIASES, unknownKeys, hints, edits, EDIT_KEYS, EDIT_ALIASES, editFaults, addRows, addRowsTsv, lines, header, duplicate, faults, removeRowIds, removeRows, editedRows, removedRows, intendedRowCount, _prelude, _resolveGrid3, _entry2, _api2, _error2, handle, explicitParentRow, mountedAfterFirst, isSubtable, parentBinding, boundParentRow, parentBindingNote, idColumnPresent, isUnloadedRecordId, reroutedRecordIds, _iterator6, _step6, _edit2, _i4, _arr2, rowId, serieScope, fmt, _divaDefs, checkCellInput, parserRefusal, parseRefusalOf, newRowEditability, newRowEditRefusal, typedValueOf, computedRefusalOf, writeCell, isLookupColumn, lookupWrite, staged, storedWrite, expectedValueOf, stagingNotes, failed, unchanged, removed, removedRecordIds, filterBeforeStaging, keyFilterApplied, restoreUserFilter, keyCache, resolveByKey, resolveTarget, applyEditToNode, columnDefFor, requiredFields, failures, editabilityUnverified, failedRows, problems, needsServerLookup, lookupKeyOf, lookupKeys, _iterator8, _step8, _edit3, _keyColumn2, _keyValue2, _iterator9, _step9, _removal, _keyColumn3, _keyValue3, _iterator10, _step10, edit, keyColumn, keyValue, _iterator11, _step11, removal, _keyColumn, _keyValue, mergedOutcome, mergeCommitOutcome, preApproved, intendedCount, _approved, _iterator12, _step12, _loop3, _ret3, filterWasChanged, _iterator14, _step14, _removal2, _target2, _target2$error, id, _iterator15, _step15, _edit4$column, _edit4, _column2, _target3, _target3$error, _node2, _rowId2, targets, _iterator16, _step16, _api2$getRowNode2, _rowId, addedRows, providedAddColumns, conditionedPosDefaults, lookupWriteCache, _loop4, _ret4, _i7, addSchemaHint, validationErrors, alreadySent, _iterator17, _step17, _api2$getRowNode12, _rowId3, rowErrors, focusNode, totalStaged, survivingOperations, approved, survived, survivedCount, trimEcho, finalOutcome, outcome, serverErrors, reported, isSessionRowId, sentValuesOf, lengthLimitNote, addError, _iterator18, _step18, failure, _iterator19, _step19, _rowId4, _iterator20, _step20, _api2$getRowNode13, _rowId5, _rowErrors, _i9, _addedRows, _api2$getRowNode5, a, outcomeIsEmpty, survivedAfterCommit, autoCommitted, autoCommittedOps, committedIds, failedIds, editTargets, addTargets, removalTargets, hasIdColumn, verifyDeadline, verifyDeadlineHit, filterBeforeVerify, verifyFilterApplied, probeServerRow, restoreVerifyFilter, verifiedChanges, verifiedAdds, verifiedRemovals, _iterator21, _step21, _loop5, _iterator22, _step22, target, probe, _iterator23, _step23, _target, _probe, appliedCount, livePath, editorPathFor, echoValues, withServerIds, addedRowsWithoutId, landedInSeries, foreignSeries, committedOps, confirmedCount, notCommittedRowIds, isEmptyCell, silentlyDropped, dirtyGrids, _root$navigationState4, _livePath$match, _livePath$match2, _ref44, _ref45, _livePath, packageBase, catalogBase, baseId, isPack, _root$webplannerInsta, destroyed, reloadTriggered, knownKeys, source, _action, _input, _entry3$getActions, _entry3$getActions2, _resolveGrid4, _entry3, _error3, _handle, actionName, actionInput, _addTargets, removeTargets, viewActions, available, approve, declined, autoNote, authorizedFetch, refreshAndSettle, unsettledNote, viewAction, mutating, cloneSettled, _catalogId, _handle$getApplicatio7, _handle$getApplicatio8, catalogId, importSettled, _handle$getApplicatio9, _handle$getApplicatio10, _params2$scope, _pricelistNode, app, serieNo, _params2, scope, key, parent, parentHandle, pricelistNode, patch, label, factors, pricelistRowId, factorOutcome, rejected, _handle$getApplicatio11, _handle$getApplicatio12, _app, pricesSettled, removeTargetIn, _target4, _header, live, saved, gone, attempt, rowsNote, _target5, keys, resolved, _iterator26, _step26, _loop8, _ret6, added, newColumns, _loop9, _i15, _resolved, decisionSubtableNote, partialNote, _column8, _search, _entry4$getActions, _entry4$getActions2, _enumDef$customParams, _data, _plainWords$sort$, _resolveGrid5, _entry4, _api3, _error4, _handle2, _column7, search, _limit, wantsExact, needle, equals, optionAction, _yield$optionAction$o, options, note, enumDef, enumData, _enumDef$customParams2, computedDef, savedRowsOnly, fields, _enumDef$cellDataType, firstRow, rowData, patternChars, plainWords, remoteSearch, matchLocally, fetchLimit, fetched, text, _options, fetchCapped, _defs$find$customPara, _defs$find, _handle2$getApplicati, _handle2$getApplicati2, defs, url, _rowFields, appScope, deps, hint, _resolveGrid6, _api4, _error5, _resolveGrid7, _entry5, _error6, _handle3, _label, _autoNote;
52756
+ var awaitingApproval, args, _allViews2, views, editorSubviews, _args$path, _root$navigationState2, _allViews3, _views, _editorSubviews, requested, dynamic, known, catalogIdIn, fromCatalog, toCatalog, only, entries, compactWanted, fullWanted, _args$value, _resolveGrid, entry, api, error, multiValues, filterBeforeBulk, deadline, bulk, _api$getFilterModel, rows, _bulk, missing, unverified, notUnique, notReached, filterBeforeLocate, located, _args$value2, matchedRows, _cellValueOf2, matchedValue, gridsOnScreen, subtableHint, trimmedFirstRow, revealNote, revealed, _args$id, openError, _entry$getHandle$getD, _entry$getHandle2, _lastNode$data, _entry$getHandle$hasP, _entry$getHandle3, _api$getFilterModel2, prelude, _resolveGrid2, _entry, _api, _error, waitedForRowsMs, previewCell, divaDefs, leafFields, _requested, columns, unknownColumns, limit, _rows, displayed, unsavedRowCount, i, _api$getDisplayedRowA, context, _i2, node, values, truncatedColumns, _iterator5, _step5, column, raw, columnMeta, lastNode, gridContext, hasCreatorRow, creatorRowLoaded, totalRowCount, dirty, filterModel, filteredBy, _ref26, _ref27, _staged$0$rowId, _staged$, _addedRows$, _outcome$committed, _root$navigationState3, _outcome$failed, _outcome$skipped, KNOWN_KEYS, ALIASES, unknownKeys, hints, edits, EDIT_KEYS, EDIT_ALIASES, editFaults, addRows, addRowsTsv, lines, header, duplicate, faults, removeRowIds, removeRows, editedRows, removedRows, intendedRowCount, _prelude, _resolveGrid3, _entry2, _api2, _error2, handle, explicitParentRow, mountedAfterFirst, isSubtable, parentBinding, boundParentRow, parentBindingNote, idColumnPresent, isUnloadedRecordId, reroutedRecordIds, _iterator6, _step6, _edit2, _i3, _arr2, rowId, serieScope, fmt, _divaDefs, checkCellInput, parserRefusal, parseRefusalOf, newRowEditability, newRowEditRefusal, typedValueOf, computedRefusalOf, writeCell, isLookupColumn, lookupWrite, staged, storedWrite, expectedValueOf, stagingNotes, failed, unchanged, removed, removedRecordIds, filterBeforeStaging, keyFilterApplied, restoreUserFilter, keyCache, resolveByKey, resolveTarget, applyEditToNode, columnDefFor, requiredFields, failures, editabilityUnverified, failedRows, problems, needsServerLookup, lookupKeyOf, lookupKeys, _iterator8, _step8, _edit3, _keyColumn2, _keyValue2, _iterator9, _step9, _removal, _keyColumn3, _keyValue3, _iterator10, _step10, edit, keyColumn, keyValue, _iterator11, _step11, removal, _keyColumn, _keyValue, mergedOutcome, mergeCommitOutcome, preApproved, intendedCount, _approved, _iterator12, _step12, _loop3, _ret3, filterWasChanged, _iterator14, _step14, _removal2, _target2, _target2$error, id, _iterator15, _step15, _edit4$column, _edit4, _column2, _target3, _target3$error, _node2, _rowId2, targets, _iterator16, _step16, _api2$getRowNode2, _rowId, addedRows, providedAddColumns, conditionedPosDefaults, lookupWriteCache, _loop4, _ret4, _i6, addSchemaHint, validationErrors, alreadySent, _iterator17, _step17, _api2$getRowNode12, _rowId3, rowErrors, focusNode, totalStaged, survivingOperations, approved, survived, survivedCount, trimEcho, finalOutcome, outcome, serverErrors, reported, isSessionRowId, sentValuesOf, lengthLimitNote, addError, _iterator18, _step18, failure, _iterator19, _step19, _rowId4, _iterator20, _step20, _api2$getRowNode13, _rowId5, _rowErrors, _i8, _addedRows, _api2$getRowNode5, a, outcomeIsEmpty, survivedAfterCommit, autoCommitted, autoCommittedOps, committedIds, failedIds, editTargets, addTargets, removalTargets, hasIdColumn, verifyDeadline, verifyDeadlineHit, filterBeforeVerify, verifyFilterApplied, probeServerRow, restoreVerifyFilter, verifiedChanges, verifiedAdds, verifiedRemovals, _iterator21, _step21, _loop5, _iterator22, _step22, target, probe, _iterator23, _step23, _target, _probe, appliedCount, livePath, editorPathFor, echoValues, withServerIds, addedRowsWithoutId, landedInSeries, foreignSeries, committedOps, confirmedCount, notCommittedRowIds, isEmptyCell, silentlyDropped, dirtyGrids, _root$navigationState4, _livePath$match, _livePath$match2, _ref44, _ref45, _livePath, packageBase, catalogBase, baseId, isPack, _root$webplannerInsta, destroyed, reloadTriggered, knownKeys, source, _action, _input, _entry3$getActions, _entry3$getActions2, _resolveGrid4, _entry3, _error3, _handle, actionName, actionInput, _addTargets, removeTargets, viewActions, available, approve, declined, autoNote, authorizedFetch, refreshAndSettle, unsettledNote, viewAction, mutating, cloneSettled, _catalogId, _handle$getApplicatio7, _handle$getApplicatio8, catalogId, importSettled, _handle$getApplicatio9, _handle$getApplicatio10, _params2$scope, _pricelistNode, app, serieNo, _params2, scope, key, parent, parentHandle, pricelistNode, patch, label, factors, pricelistRowId, factorOutcome, rejected, _handle$getApplicatio11, _handle$getApplicatio12, _app, pricesSettled, removeTargetIn, _target4, _header, live, saved, gone, attempt, rowsNote, _target5, keys, resolved, _iterator26, _step26, _loop8, _ret6, added, newColumns, _loop9, _i14, _resolved, decisionSubtableNote, partialNote, _column8, _search, _entry4$getActions, _entry4$getActions2, _enumDef$customParams, _data, _plainWords$sort$, _resolveGrid5, _entry4, _api3, _error4, _handle2, _column7, search, _limit, wantsExact, needle, equals, optionAction, _yield$optionAction$o, options, note, enumDef, enumData, _enumDef$customParams2, computedDef, savedRowsOnly, fields, _enumDef$cellDataType, firstRow, rowData, patternChars, plainWords, remoteSearch, matchLocally, fetchLimit, fetched, text, _options, fetchCapped, _defs$find$customPara, _defs$find, _handle2$getApplicati, _handle2$getApplicati2, defs, url, _rowFields, appScope, deps, hint, _resolveGrid6, _api4, _error5, _resolveGrid7, _entry5, _error6, _handle3, _label, _autoNote;
53140
52757
  return _regeneratorRuntime.wrap(function _callee11$(_context18) {
53141
52758
  while (1) switch (_context18.prev = _context18.next) {
53142
52759
  case 0:
53143
52760
  awaitingApproval = function awaitingApproval() {
53144
52761
  return onProgress === null || onProgress === void 0 ? void 0 : onProgress(root.t('backoffice.divaAgent.awaitingApproval'));
53145
52762
  };
53146
- args = input !== null && input !== void 0 ? input : {}; // In production the wrapper's alias layer has already done this; a direct dispatch (the test harness) has
53147
- // not. Applied from the SAME map the tool defs declare, so 'gridId' cannot fall through while 'table' works
53148
- // — silently resolving to the FIRST grid would hit the wrong table.
53149
- for (_i2 = 0, _Object$entries = Object.entries(GRID_ARG_ALIASES); _i2 < _Object$entries.length; _i2++) {
53150
- _Object$entries$_i = _slicedToArray(_Object$entries[_i2], 2), alias = _Object$entries$_i[0], canonical = _Object$entries$_i[1];
53151
- from = args[alias];
53152
- if (!args[canonical] && from) args[canonical] = from;
53153
- }
52763
+ args = input !== null && input !== void 0 ? input : {};
53154
52764
  _context18.t0 = name;
53155
- _context18.next = _context18.t0 === 'listViews' ? 6 : _context18.t0 === 'navigateTo' ? 8 : _context18.t0 === 'listGrids' ? 24 : _context18.t0 === 'locateRow' ? 31 : _context18.t0 === 'openToolbarTool' ? 86 : _context18.t0 === 'readGridRows' ? 92 : _context18.t0 === 'stageTableEdits' ? 142 : _context18.t0 === 'reloadPage' ? 557 : _context18.t0 === 'reloadPlanner' ? 562 : _context18.t0 === 'runTableAction' ? 576 : _context18.t0 === 'readColumnOptions' ? 827 : _context18.t0 === 'clearGridFilter' ? 896 : _context18.t0 === 'discardStagedChanges' ? 901 : 922;
52765
+ _context18.next = _context18.t0 === 'listViews' ? 5 : _context18.t0 === 'navigateTo' ? 7 : _context18.t0 === 'listGrids' ? 23 : _context18.t0 === 'locateRow' ? 30 : _context18.t0 === 'openToolbarTool' ? 85 : _context18.t0 === 'readGridRows' ? 91 : _context18.t0 === 'stageTableEdits' ? 141 : _context18.t0 === 'reloadPage' ? 556 : _context18.t0 === 'reloadPlanner' ? 561 : _context18.t0 === 'runTableAction' ? 575 : _context18.t0 === 'readColumnOptions' ? 826 : _context18.t0 === 'clearGridFilter' ? 895 : _context18.t0 === 'discardStagedChanges' ? 900 : 921;
53156
52766
  break;
53157
- case 6:
52767
+ case 5:
53158
52768
  _allViews2 = allViews(root, ctx), views = _allViews2.views, editorSubviews = _allViews2.editorSubviews;
53159
52769
  return _context18.abrupt("return", {
53160
52770
  currentPath: root.navigationState.path,
53161
52771
  views: views,
53162
52772
  editorSubviews: editorSubviews
53163
52773
  });
53164
- case 8:
52774
+ case 7:
53165
52775
  _allViews3 = allViews(root, ctx), _views = _allViews3.views, _editorSubviews = _allViews3.editorSubviews; // Models regularly prepend a leading slash — normalize instead of rejecting.
53166
52776
  requested = String((_args$path = args.path) !== null && _args$path !== void 0 ? _args$path : '').replace(/^\//, '');
53167
52777
  dynamic = isDynamicEditorPath(root, requested); // Thrown (not returned) so the failed call does NOT end the turn — the model corrects the path in the same turn.
53168
52778
  if (!(dynamic === 'bad-id')) {
53169
- _context18.next = 13;
52779
+ _context18.next = 12;
53170
52780
  break;
53171
52781
  }
53172
52782
  throw new Error("The id in '".concat(args.path, "' is not a record _id (24-hex) \u2014 it looks like a grid rowId. rowIds only address rows within a grid session; for editor paths read the row's _id column (readGridRows, after the row is saved) and use that."));
53173
- case 13:
52783
+ case 12:
53174
52784
  known = _views.some(function (view) {
53175
52785
  return view.path === requested;
53176
52786
  }) || _editorSubviews.some(function (view) {
53177
52787
  return view.path === requested;
53178
52788
  }) || dynamic === true;
53179
52789
  if (!(!requested || !known)) {
53180
- _context18.next = 16;
52790
+ _context18.next = 15;
53181
52791
  break;
53182
52792
  }
53183
52793
  throw new Error("Unknown path '".concat(args.path, "' \u2014 use a path from listViews (never guess paths)."));
53184
- case 16:
52794
+ case 15:
53185
52795
  // Direct catalog→catalog jumps crash the router while the old planner state is mounted — force the two-step via the list.
53186
52796
  catalogIdIn = function catalogIdIn(path) {
53187
52797
  var _exec2;
@@ -53190,11 +52800,11 @@ function createNavigationToolset(ctx) {
53190
52800
  fromCatalog = catalogIdIn((_root$navigationState2 = root.navigationState.path) !== null && _root$navigationState2 !== void 0 ? _root$navigationState2 : '');
53191
52801
  toCatalog = catalogIdIn(requested);
53192
52802
  if (!(fromCatalog && toCatalog && fromCatalog !== toCatalog)) {
53193
- _context18.next = 21;
52803
+ _context18.next = 20;
53194
52804
  break;
53195
52805
  }
53196
52806
  throw new Error("Direct switch into ANOTHER catalog (".concat(fromCatalog, " \u2192 ").concat(toCatalog, ") is blocked: with the current catalog's planner state mounted it has crashed the router and the agent bridge. ") + "Go via the list instead: navigateTo 'catalogs/idmeditor/catalogs' first (unmounts the editor cleanly), THEN navigateTo the target catalog's sub-view.");
53197
- case 21:
52807
+ case 20:
53198
52808
  // Deferred so the turn persists BEFORE the unmount; the pending marker suppresses the auto-'Continue.' in the gap.
53199
52809
  pendingAgentNavigation.set(requested);
53200
52810
  setTimeout(function () {
@@ -53206,16 +52816,16 @@ function createNavigationToolset(ctx) {
53206
52816
  ok: true,
53207
52817
  note: "Navigation triggered — this turn ends here; an automatic 'Continue.' follows after arrival."
53208
52818
  });
53209
- case 24:
52819
+ case 23:
53210
52820
  only = args.grid ? resolveGrid(args.grid) : undefined;
53211
52821
  if (!(only !== null && only !== void 0 && only.error || only && !only.entry)) {
53212
- _context18.next = 27;
52822
+ _context18.next = 26;
53213
52823
  break;
53214
52824
  }
53215
52825
  return _context18.abrupt("return", {
53216
52826
  error: only.error
53217
52827
  });
53218
- case 27:
52828
+ case 26:
53219
52829
  entries = only !== null && only !== void 0 && only.entry ? [only.entry] : root.gridRegistry.entries;
53220
52830
  compactWanted = (input === null || input === void 0 ? void 0 : input.compact) === true; // An explicit compact:false on ONE table overrides the size guard — the caller asked for the metadata and pays for it.
53221
52831
  fullWanted = (input === null || input === void 0 ? void 0 : input.compact) === false && !!(only !== null && only !== void 0 && only.entry);
@@ -53290,41 +52900,41 @@ function createNavigationToolset(ctx) {
53290
52900
  });
53291
52901
  })
53292
52902
  });
53293
- case 31:
52903
+ case 30:
53294
52904
  _resolveGrid = resolveGrid(args.grid), entry = _resolveGrid.entry, api = _resolveGrid.api, error = _resolveGrid.error;
53295
52905
  if (!(error || !api || !entry)) {
53296
- _context18.next = 34;
52906
+ _context18.next = 33;
53297
52907
  break;
53298
52908
  }
53299
52909
  return _context18.abrupt("return", {
53300
52910
  error: error
53301
52911
  });
53302
- case 34:
52912
+ case 33:
53303
52913
  // BULK READ: one call instead of a locateRow chain. Read-only — the pre-bulk filter model is restored before returning.
53304
52914
  multiValues = Array.isArray(input === null || input === void 0 ? void 0 : input.values) ? input.values.map(String) : undefined;
53305
52915
  if (!(multiValues !== null && multiValues !== void 0 && multiValues.length)) {
53306
- _context18.next = 55;
52916
+ _context18.next = 54;
53307
52917
  break;
53308
52918
  }
53309
52919
  filterBeforeBulk = api.getFilterModel(); // Time budget: running past the call timeout leaves this handler blocking the serialized call queue.
53310
52920
  deadline = Date.now() + 14000;
53311
- _context18.prev = 38;
53312
- _context18.next = 41;
52921
+ _context18.prev = 37;
52922
+ _context18.next = 40;
53313
52923
  return bulkLocateRows(api, args.column, multiValues, deadline);
53314
- case 41:
52924
+ case 40:
53315
52925
  bulk = _context18.sent;
53316
- _context18.next = 48;
52926
+ _context18.next = 47;
53317
52927
  break;
53318
- case 44:
53319
- _context18.prev = 44;
53320
- _context18.t1 = _context18["catch"](38);
52928
+ case 43:
52929
+ _context18.prev = 43;
52930
+ _context18.t1 = _context18["catch"](37);
53321
52931
  // A lookup that failed AFTER its filter went out (a column that takes no equals filter) must not leave the
53322
52932
  // user's own filter wiped — setFilterModel replaces the whole model, not just this column's part.
53323
52933
  if (JSON.stringify((_api$getFilterModel = api.getFilterModel()) !== null && _api$getFilterModel !== void 0 ? _api$getFilterModel : {}) !== JSON.stringify(filterBeforeBulk !== null && filterBeforeBulk !== void 0 ? filterBeforeBulk : {})) api.setFilterModel(Object.keys(filterBeforeBulk !== null && filterBeforeBulk !== void 0 ? filterBeforeBulk : {}).length ? filterBeforeBulk : null);
53324
52934
  return _context18.abrupt("return", {
53325
52935
  error: _context18.t1 instanceof Error ? _context18.t1.message : String(_context18.t1)
53326
52936
  });
53327
- case 48:
52937
+ case 47:
53328
52938
  // Row previews BEFORE the filter goes back — the grid recycles its nodes on a refilter.
53329
52939
  rows = bulk.hits.map(function (_ref17) {
53330
52940
  var _trimmed$row;
@@ -53339,14 +52949,14 @@ function createNavigationToolset(ctx) {
53339
52949
  } : {});
53340
52950
  }); // A pure read must not leave lookup filters behind — restore what was active before.
53341
52951
  if (!bulk.filterApplied) {
53342
- _context18.next = 53;
52952
+ _context18.next = 52;
53343
52953
  break;
53344
52954
  }
53345
52955
  api.setFilterModel(Object.keys(filterBeforeBulk !== null && filterBeforeBulk !== void 0 ? filterBeforeBulk : {}).length ? filterBeforeBulk : null);
53346
52956
  // The settle wait lives inside the budget too — the model is restored either way.
53347
- _context18.next = 53;
52957
+ _context18.next = 52;
53348
52958
  return waitForRows(api, Math.max(0, deadline - Date.now()));
53349
- case 53:
52959
+ case 52:
53350
52960
  _bulk = bulk, missing = _bulk.missing, unverified = _bulk.unverified, notUnique = _bulk.notUnique, notReached = _bulk.notReached;
53351
52961
  return _context18.abrupt("return", _objectSpread$X(_objectSpread$X(_objectSpread$X(_objectSpread$X(_objectSpread$X({
53352
52962
  rows: rows
@@ -53361,33 +52971,33 @@ function createNavigationToolset(ctx) {
53361
52971
  } : {}), {}, {
53362
52972
  note: "".concat(rows.length, "/").concat(multiValues.length, " located") + (bulk.serverLookups ? " in ".concat(bulk.serverLookups, " server lookup(s) of up to ").concat(BULK_LOOKUP_CHUNK, " values each.") : ' from the loaded rows, no server lookup needed.') + (missing.length ? " Missing values did NOT match — check them for typos before concluding they don't exist." : '') + (unverified.length ? " UNVERIFIED values have NO verdict \u2014 that is not a miss: their server lookup did not answer within ".concat(LOOKUP_WAIT_MS / 1000, " s, or the batch matched more rows than the table loads at once. Look them up again (smaller batches, once the tab is idle), never conclude they do not exist.") : '') + (notUnique.length ? ' notUnique values match SEVERAL rows (matches = how many carry the exact value) — never use them as a reference id; locateRow such a value on its own (its filter then shows every row carrying it) and readGridRows those rows.' : '') + (notReached.length ? " TIME BUDGET HIT: ".concat(notReached.length, " value(s) were NOT looked up \u2014 call again with just those.") : ' No filter was left behind.')
53363
52973
  }));
53364
- case 55:
52974
+ case 54:
53365
52975
  if (!(((_args$value = args.value) !== null && _args$value !== void 0 ? _args$value : '') === '')) {
53366
- _context18.next = 57;
52976
+ _context18.next = 56;
53367
52977
  break;
53368
52978
  }
53369
52979
  return _context18.abrupt("return", {
53370
52980
  error: "Provide 'value' (one row) or 'values' (bulk read)."
53371
52981
  });
53372
- case 57:
52982
+ case 56:
53373
52983
  // Captured before the lookup: a rejected loose hit must hand the user's OWN filter back, not an empty one.
53374
52984
  filterBeforeLocate = api.getFilterModel();
53375
- _context18.prev = 58;
53376
- _context18.next = 61;
52985
+ _context18.prev = 57;
52986
+ _context18.next = 60;
53377
52987
  return locateRowCore(api, args.column, String((_args$value2 = args.value) !== null && _args$value2 !== void 0 ? _args$value2 : ''), args.select !== false);
53378
- case 61:
52988
+ case 60:
53379
52989
  located = _context18.sent;
53380
- _context18.next = 67;
52990
+ _context18.next = 66;
53381
52991
  break;
53382
- case 64:
53383
- _context18.prev = 64;
53384
- _context18.t2 = _context18["catch"](58);
52992
+ case 63:
52993
+ _context18.prev = 63;
52994
+ _context18.t2 = _context18["catch"](57);
53385
52995
  return _context18.abrupt("return", {
53386
52996
  error: _context18.t2 instanceof Error ? _context18.t2.message : String(_context18.t2)
53387
52997
  });
53388
- case 67:
52998
+ case 66:
53389
52999
  if (located.node) {
53390
- _context18.next = 69;
53000
+ _context18.next = 68;
53391
53001
  break;
53392
53002
  }
53393
53003
  return _context18.abrupt("return", _objectSpread$X(_objectSpread$X({
@@ -53397,34 +53007,34 @@ function createNavigationToolset(ctx) {
53397
53007
  } : {}), {}, {
53398
53008
  note: located.lookupTimedOut ? "The server filter for ".concat(args.column, " = '").concat(args.value, "' did NOT answer within ").concat(LOOKUP_WAIT_MS / 1000, " s \u2014 this is NOT proof that the row is missing (a busy or stuck grid). Retry once the tab is idle; the lookup filter is already removed.") : "No row matched ".concat(args.column, " ~ '").concat(args.value, "'. The lookup filter is already removed \u2014 do NOT call clearGridFilter, it would drop a filter the user set.")
53399
53009
  }));
53400
- case 69:
53010
+ case 68:
53401
53011
  matchedRows = located.filterApplied ? countDisplayedRealRows(api) : located.loadedMatches; // `exact:true` requires a genuine hit — a loose (contains/prefix) one is reported as NOT FOUND rather
53402
53012
  // than handed back disguised as the requested value (serieNo '9' resolving to '99').
53403
53013
  if (!(args.exact && !located.exact)) {
53404
- _context18.next = 77;
53014
+ _context18.next = 76;
53405
53015
  break;
53406
53016
  }
53407
53017
  matchedValue = String((_cellValueOf2 = cellValueOf(api, located.node, located.column)) !== null && _cellValueOf2 !== void 0 ? _cellValueOf2 : '');
53408
53018
  if (!located.filterApplied) {
53409
- _context18.next = 76;
53019
+ _context18.next = 75;
53410
53020
  break;
53411
53021
  }
53412
53022
  api.setFilterModel(Object.keys(filterBeforeLocate !== null && filterBeforeLocate !== void 0 ? filterBeforeLocate : {}).length ? filterBeforeLocate : null);
53413
- _context18.next = 76;
53023
+ _context18.next = 75;
53414
53024
  return waitForRows(api);
53415
- case 76:
53025
+ case 75:
53416
53026
  return _context18.abrupt("return", {
53417
53027
  matchedRows: 0,
53418
53028
  note: "No EXACT match for ".concat(args.column, " = '").concat(args.value, "' \u2014 the closest candidate was '").concat(matchedValue, "' (").concat(matchedRows, " loose candidate(s) total, none exact). Nothing was selected.")
53419
53029
  });
53420
- case 77:
53030
+ case 76:
53421
53031
  if (!(args.select !== false)) {
53422
- _context18.next = 80;
53032
+ _context18.next = 79;
53423
53033
  break;
53424
53034
  }
53425
- _context18.next = 80;
53035
+ _context18.next = 79;
53426
53036
  return sleep(400);
53427
- case 80:
53037
+ case 79:
53428
53038
  // A subtable already on screen re-renders in place, so only openToolbarTool for one NOT yet listed.
53429
53039
  gridsOnScreen = root.gridRegistry.entries.map(function (e) {
53430
53040
  return e.label;
@@ -53455,56 +53065,56 @@ function createNavigationToolset(ctx) {
53455
53065
  gridsOnScreen: gridsOnScreen,
53456
53066
  note: (located.exact ? '' : "NOT AN EXACT MATCH: ".concat(args.column, " = '").concat(args.value, "' was requested but this row's value is different (see firstRow) \u2014 ") + "it only matched loosely. Do not treat this as proof that '".concat(args.value, "' exists; pass exact:true to require a genuine hit instead of the closest candidate. ")) + (located.filterApplied ? 'VERIFY via firstRow that this is really the requested entity. LEAVE the filter active — it is what shows the user the match; clearGridFilter only when the user is done with this row or before locating something else.' : 'The row was already loaded — scrolled to and highlighted WITHOUT filtering (matchedRows counts the loaded rows; more may exist server-side). No filter to clear.') + subtableHint + revealNote
53457
53067
  }));
53458
- case 86:
53068
+ case 85:
53459
53069
  openError = openToolbarToolById(String((_args$id = args.id) !== null && _args$id !== void 0 ? _args$id : ''));
53460
53070
  if (!openError) {
53461
- _context18.next = 89;
53071
+ _context18.next = 88;
53462
53072
  break;
53463
53073
  }
53464
53074
  throw new Error(openError);
53465
- case 89:
53466
- _context18.next = 91;
53075
+ case 88:
53076
+ _context18.next = 90;
53467
53077
  return sleep(400);
53468
- case 91:
53078
+ case 90:
53469
53079
  return _context18.abrupt("return", {
53470
53080
  ok: true,
53471
53081
  gridsNowOnScreen: root.gridRegistry.entries.map(function (entry) {
53472
53082
  return entry.label;
53473
53083
  })
53474
53084
  });
53475
- case 92:
53476
- _context18.next = 94;
53085
+ case 91:
53086
+ _context18.next = 93;
53477
53087
  return applyParentRowPrelude(input, args);
53478
- case 94:
53088
+ case 93:
53479
53089
  prelude = _context18.sent;
53480
53090
  if (!prelude) {
53481
- _context18.next = 97;
53091
+ _context18.next = 96;
53482
53092
  break;
53483
53093
  }
53484
53094
  return _context18.abrupt("return", prelude);
53485
- case 97:
53095
+ case 96:
53486
53096
  _resolveGrid2 = resolveGrid(args.grid), _entry = _resolveGrid2.entry, _api = _resolveGrid2.api, _error = _resolveGrid2.error;
53487
53097
  if (!(_error || !_api || !_entry)) {
53488
- _context18.next = 100;
53098
+ _context18.next = 99;
53489
53099
  break;
53490
53100
  }
53491
53101
  return _context18.abrupt("return", {
53492
53102
  error: _error
53493
53103
  });
53494
- case 100:
53104
+ case 99:
53495
53105
  if (!isRealRow(_api.getDisplayedRowAtIndex(0))) {
53496
- _context18.next = 104;
53106
+ _context18.next = 103;
53497
53107
  break;
53498
53108
  }
53499
53109
  _context18.t3 = 0;
53500
- _context18.next = 107;
53501
- break;
53502
- case 104:
53503
53110
  _context18.next = 106;
53111
+ break;
53112
+ case 103:
53113
+ _context18.next = 105;
53504
53114
  return waitForRows(_api);
53505
- case 106:
53115
+ case 105:
53506
53116
  _context18.t3 = _context18.sent;
53507
- case 107:
53117
+ case 106:
53508
53118
  waitedForRowsMs = _context18.t3;
53509
53119
  previewCell = function previewCell(column, v, truncatedColumns) {
53510
53120
  if (v == null || _typeof(v) !== 'object') return v;
@@ -53543,19 +53153,19 @@ function createNavigationToolset(ctx) {
53543
53153
  context = (_api$getDisplayedRowA = _api.getDisplayedRowAtIndex(i)) === null || _api$getDisplayedRowA === void 0 || (_api$getDisplayedRowA = _api$getDisplayedRowA.data) === null || _api$getDisplayedRowA === void 0 ? void 0 : _api$getDisplayedRowA.__diva_context;
53544
53154
  if (context !== null && context !== void 0 && context.isNew && !context.isEmpty) unsavedRowCount += 1;
53545
53155
  }
53546
- _i3 = 0;
53547
- case 120:
53548
- if (!(_i3 < displayed && _rows.length < limit)) {
53549
- _context18.next = 132;
53156
+ _i2 = 0;
53157
+ case 119:
53158
+ if (!(_i2 < displayed && _rows.length < limit)) {
53159
+ _context18.next = 131;
53550
53160
  break;
53551
53161
  }
53552
- node = _api.getDisplayedRowAtIndex(_i3);
53162
+ node = _api.getDisplayedRowAtIndex(_i2);
53553
53163
  if (!(!isRealRow(node) || !node.id)) {
53554
- _context18.next = 124;
53164
+ _context18.next = 123;
53555
53165
  break;
53556
53166
  }
53557
- return _context18.abrupt("continue", 129);
53558
- case 124:
53167
+ return _context18.abrupt("continue", 128);
53168
+ case 123:
53559
53169
  values = {};
53560
53170
  truncatedColumns = [];
53561
53171
  _iterator5 = _createForOfIteratorHelper$r(columns);
@@ -53576,11 +53186,11 @@ function createNavigationToolset(ctx) {
53576
53186
  }, truncatedColumns.length ? {
53577
53187
  truncatedColumns: truncatedColumns
53578
53188
  } : {}));
53579
- case 129:
53580
- _i3++;
53581
- _context18.next = 120;
53189
+ case 128:
53190
+ _i2++;
53191
+ _context18.next = 119;
53582
53192
  break;
53583
- case 132:
53193
+ case 131:
53584
53194
  columnMeta = columns.map(function (field) {
53585
53195
  return _objectSpread$X({
53586
53196
  column: field
@@ -53624,7 +53234,7 @@ function createNavigationToolset(ctx) {
53624
53234
  countNote: dirty ? 'This table has UNCOMMITTED staged rows, so totalRowCount is inflated by them — do not report it as the row count; enumerate, or reload the page first.' : undefined,
53625
53235
  note: _rows.length === 0 ? "The table has 0 loaded rows after polling ".concat(waitedForRowsMs, " ms for its first block \u2014 its prefilter (serie/catalog selection) yields no data here. This is not a loading race any more: treat it as empty; re-read only if you changed the selection/filter or navigated since.") : "Returned ".concat(_rows.length, " of ").concat(totalRowCount, " rows").concat(_rows.length < totalRowCount ? _rows.length === limit ? " \u2014 the `limit` (".concat(limit, ") cut the slice: re-call with a higher limit (max 500) for more. For COUNTS always report totalRowCount, never the returned slice") : ' — the rest is not loaded client-side (server-side lazy table; scrolling or a filter loads more). For COUNTS always report totalRowCount, never the returned slice' : '', ". For stageTableEdits you can address rows directly by keyColumn/keyValue (unique value) \u2014 rowId is the fallback for rows without a unique key.")
53626
53236
  }));
53627
- case 142:
53237
+ case 141:
53628
53238
  // A misspelled top-level key would be dropped in silence and `grid` would default to the wrong table.
53629
53239
  KNOWN_KEYS = ['grid', 'edits', 'addRows', 'removeRowIds', 'removeRows', 'parentRow', 'addRowsTsv', 'source', 'mapping', 'dryRun'];
53630
53240
  ALIASES = {
@@ -53635,18 +53245,18 @@ function createNavigationToolset(ctx) {
53635
53245
  }; // Over the MCP bridge a `source` and its `mapping` are replaced by the payload's rows before the call ever
53636
53246
  // reaches here. Arriving unexpanded means this is the in-app agent, which has no payload store of its own.
53637
53247
  if (!(input !== null && input !== void 0 && input.source || input !== null && input !== void 0 && input.mapping)) {
53638
- _context18.next = 146;
53248
+ _context18.next = 145;
53639
53249
  break;
53640
53250
  }
53641
53251
  return _context18.abrupt("return", {
53642
53252
  error: "A payload `source` (and its `mapping`) only works over the MCP bridge, where the service resolves it into rows. In this chat, pass the rows as addRows or addRowsTsv, with the table's own column ids. Nothing was staged."
53643
53253
  });
53644
- case 146:
53254
+ case 145:
53645
53255
  unknownKeys = Object.keys(input !== null && input !== void 0 ? input : {}).filter(function (key) {
53646
53256
  return !KNOWN_KEYS.includes(key);
53647
53257
  });
53648
53258
  if (!unknownKeys.length) {
53649
- _context18.next = 150;
53259
+ _context18.next = 149;
53650
53260
  break;
53651
53261
  }
53652
53262
  hints = unknownKeys.map(function (key) {
@@ -53655,7 +53265,7 @@ function createNavigationToolset(ctx) {
53655
53265
  return _context18.abrupt("return", {
53656
53266
  error: "Unknown parameter(s) ".concat(hints.join(', '), ". stageTableEdits takes: ").concat(KNOWN_KEYS.join(', '), ". Nothing was staged.")
53657
53267
  });
53658
- case 150:
53268
+ case 149:
53659
53269
  edits = Array.isArray(input === null || input === void 0 ? void 0 : input.edits) ? input.edits : []; // A missing `newValue` would coerce to '' — the documented "clear the cell" — and wipe the cell in silence.
53660
53270
  EDIT_KEYS = ['rowId', 'keyColumn', 'keyValue', 'column', 'newValue'];
53661
53271
  EDIT_ALIASES = {
@@ -53678,13 +53288,13 @@ function createNavigationToolset(ctx) {
53678
53288
  return ["edits[".concat(index, "] ").concat(faults.filter(Boolean).join(' and '))];
53679
53289
  });
53680
53290
  if (!editFaults.length) {
53681
- _context18.next = 156;
53291
+ _context18.next = 155;
53682
53292
  break;
53683
53293
  }
53684
53294
  return _context18.abrupt("return", {
53685
53295
  error: "".concat(editFaults.join('; '), ". Each edit takes: ").concat(EDIT_KEYS.join(', '), " \u2014 newValue is required (an empty string clears the cell). Nothing was staged.")
53686
53296
  });
53687
- case 156:
53297
+ case 155:
53688
53298
  // Entries without the `values` wrapper are unambiguous — treat the entry AS the values.
53689
53299
  addRows = (Array.isArray(input === null || input === void 0 ? void 0 : input.addRows) ? input.addRows : []).map(function (row) {
53690
53300
  return row && _typeof(row) === 'object' && !('values' in row) && Object.keys(row).length ? {
@@ -53696,7 +53306,7 @@ function createNavigationToolset(ctx) {
53696
53306
  // left out of that row, so its default (or 'required' complaint) behaves as if it had never been mentioned.
53697
53307
  addRowsTsv = typeof (input === null || input === void 0 ? void 0 : input.addRowsTsv) === 'string' ? input.addRowsTsv : undefined;
53698
53308
  if (!(addRowsTsv !== undefined)) {
53699
- _context18.next = 171;
53309
+ _context18.next = 170;
53700
53310
  break;
53701
53311
  }
53702
53312
  lines = addRowsTsv.split('\n').map(function (line) {
@@ -53707,13 +53317,13 @@ function createNavigationToolset(ctx) {
53707
53317
  // Exactly one empty tail is the final newline; a second one is a blank row the caller wrote and gets its fault.
53708
53318
  if (lines.length && lines[lines.length - 1] === '') lines.pop();
53709
53319
  if (!(lines.length < 2)) {
53710
- _context18.next = 163;
53320
+ _context18.next = 162;
53711
53321
  break;
53712
53322
  }
53713
53323
  return _context18.abrupt("return", {
53714
53324
  error: "addRowsTsv needs a HEADER line of column field ids and at least one row line, tab-separated (e.g. 'typeNo\\tsequenceNo' then 'ART_001\\t10'). Nothing was staged."
53715
53325
  });
53716
- case 163:
53326
+ case 162:
53717
53327
  header = lines[0].split('\t').map(function (cell) {
53718
53328
  return cell.trim();
53719
53329
  });
@@ -53721,13 +53331,13 @@ function createNavigationToolset(ctx) {
53721
53331
  return cell && header.indexOf(cell) !== index;
53722
53332
  });
53723
53333
  if (!(!header.every(Boolean) || duplicate)) {
53724
- _context18.next = 167;
53334
+ _context18.next = 166;
53725
53335
  break;
53726
53336
  }
53727
53337
  return _context18.abrupt("return", {
53728
53338
  error: duplicate ? "addRowsTsv names the column '".concat(duplicate, "' twice in its header line. Nothing was staged.") : 'addRowsTsv has an empty column name in its header line. Nothing was staged.'
53729
53339
  });
53730
- case 167:
53340
+ case 166:
53731
53341
  faults = [];
53732
53342
  lines.slice(1).forEach(function (line, index) {
53733
53343
  if (!line.trim()) {
@@ -53755,19 +53365,19 @@ function createNavigationToolset(ctx) {
53755
53365
  });
53756
53366
  });
53757
53367
  if (!faults.length) {
53758
- _context18.next = 171;
53368
+ _context18.next = 170;
53759
53369
  break;
53760
53370
  }
53761
53371
  return _context18.abrupt("return", {
53762
53372
  error: "addRowsTsv: ".concat(faults.slice(0, 5).join('; ')).concat(faults.length > 5 ? "; and ".concat(faults.length - 5, " more") : '', ". Every row line needs exactly one cell per header column (an empty cell leaves that column unset). Nothing was staged.")
53763
53373
  });
53764
- case 171:
53374
+ case 170:
53765
53375
  removeRowIds = _toConsumableArray(new Set((Array.isArray(input === null || input === void 0 ? void 0 : input.removeRowIds) ? input.removeRowIds : []).map(String)));
53766
53376
  removeRows = Array.isArray(input === null || input === void 0 ? void 0 : input.removeRows) ? input.removeRows : []; // A dry run must NEVER reach the staging path below. It only knows how to check NEW rows: entered on
53767
53377
  // `dryRun && addRows.length`, a dry run carrying only edits or removals used to fall through and was staged,
53768
53378
  // approved and committed for real. A mixed call would check the rows and write the rest — refused as well.
53769
53379
  if (!(input !== null && input !== void 0 && input.dryRun && (!addRows.length || edits.length || removeRowIds.length || removeRows.length))) {
53770
- _context18.next = 175;
53380
+ _context18.next = 174;
53771
53381
  break;
53772
53382
  }
53773
53383
  return _context18.abrupt("return", {
@@ -53775,7 +53385,7 @@ function createNavigationToolset(ctx) {
53775
53385
  dryRun: true,
53776
53386
  error: 'A dry run checks NEW rows only (addRows, addRowsTsv or a payload `source`)' + (addRows.length ? ', and this call also carries edits or removals, which it would not check. ' : ', and this call carries none. ') + 'Nothing was staged. Re-send without dryRun to apply edits or removals, or send only the rows to check.'
53777
53387
  });
53778
- case 175:
53388
+ case 174:
53779
53389
  // The cap counts ROWS on screen: two edits on one row are one live grid row, so each row counts once however
53780
53390
  // many of its cells change.
53781
53391
  editedRows = new Set(edits.map(function (edit) {
@@ -53789,7 +53399,7 @@ function createNavigationToolset(ctx) {
53789
53399
  intendedRowCount = editedRows.size + addRows.length + removeRowIds.length + removedRows.size; // A dry run stages nothing, so the browser limit does not apply to it — checking a big payload in one go is
53790
53400
  // exactly how an agent finds out it has to split, and what to fix before it does.
53791
53401
  if (!(intendedRowCount > WRITE_ROW_LIMIT && !(input !== null && input !== void 0 && input.dryRun))) {
53792
- _context18.next = 180;
53402
+ _context18.next = 179;
53793
53403
  break;
53794
53404
  }
53795
53405
  return _context18.abrupt("return", {
@@ -53797,47 +53407,47 @@ function createNavigationToolset(ctx) {
53797
53407
  intendedRowCount: intendedRowCount,
53798
53408
  limit: WRITE_ROW_LIMIT
53799
53409
  });
53800
- case 180:
53410
+ case 179:
53801
53411
  if (!(!edits.length && !addRows.length && !removeRowIds.length && !removeRows.length)) {
53802
- _context18.next = 182;
53412
+ _context18.next = 181;
53803
53413
  break;
53804
53414
  }
53805
53415
  throw new Error('Provide edits: [{rowId | keyColumn+keyValue, column, newValue}], addRows: [{values}], removeRowIds and/or removeRows: [{keyColumn, keyValue}] — key addressing locates the row for you (unique value of any column), rowIds come from readGridRows.');
53806
- case 182:
53807
- _context18.next = 184;
53416
+ case 181:
53417
+ _context18.next = 183;
53808
53418
  return applyParentRowPrelude(input, args);
53809
- case 184:
53419
+ case 183:
53810
53420
  _prelude = _context18.sent;
53811
53421
  if (!_prelude) {
53812
- _context18.next = 187;
53422
+ _context18.next = 186;
53813
53423
  break;
53814
53424
  }
53815
53425
  return _context18.abrupt("return", _prelude);
53816
- case 187:
53426
+ case 186:
53817
53427
  _resolveGrid3 = resolveGrid(args.grid), _entry2 = _resolveGrid3.entry, _api2 = _resolveGrid3.api, _error2 = _resolveGrid3.error;
53818
53428
  if (!(_error2 || !_api2 || !_entry2)) {
53819
- _context18.next = 190;
53429
+ _context18.next = 189;
53820
53430
  break;
53821
53431
  }
53822
53432
  return _context18.abrupt("return", {
53823
53433
  error: _error2
53824
53434
  });
53825
- case 190:
53435
+ case 189:
53826
53436
  handle = _entry2.getHandle();
53827
53437
  if (handle) {
53828
- _context18.next = 193;
53438
+ _context18.next = 192;
53829
53439
  break;
53830
53440
  }
53831
53441
  return _context18.abrupt("return", {
53832
53442
  error: "Table '".concat(_entry2.label, "' is not ready.")
53833
53443
  });
53834
- case 193:
53444
+ case 192:
53835
53445
  if (!handle.hasPendingChanges()) {
53836
- _context18.next = 195;
53446
+ _context18.next = 194;
53837
53447
  break;
53838
53448
  }
53839
53449
  throw new Error('This table already has uncommitted (staged) changes — wait for the pending decision or ask the user to save/discard their manual edits first.');
53840
- case 195:
53450
+ case 194:
53841
53451
  // Without parentRow the write lands under the parent the subtable is bound to — the one an earlier call left
53842
53452
  // selected. Only the subtable's own declaration names it; without one the write is refused, never guessed.
53843
53453
  explicitParentRow = !!(input !== null && input !== void 0 && input.parentRow); // Mount order is the fallback for a subtable whose module declares no parent (media refs, the assortment item
@@ -53848,13 +53458,13 @@ function createNavigationToolset(ctx) {
53848
53458
  isSubtable = explicitParentRow || !!_entry2.getBoundParent || mountedAfterFirst;
53849
53459
  parentBinding = explicitParentRow ? undefined : declaredParentBinding(_entry2);
53850
53460
  if (!(parentBinding !== null && parentBinding !== void 0 && parentBinding.refusal)) {
53851
- _context18.next = 201;
53461
+ _context18.next = 200;
53852
53462
  break;
53853
53463
  }
53854
53464
  return _context18.abrupt("return", {
53855
53465
  error: parentBinding.refusal
53856
53466
  });
53857
- case 201:
53467
+ case 200:
53858
53468
  boundParentRow = parentBinding === null || parentBinding === void 0 ? void 0 : parentBinding.parent;
53859
53469
  parentBindingNote = boundParentRow ? " SUBTABLE WRITE WITHOUT parentRow: bound to the parent row this subtable is showing \u2014 '".concat(boundParentRow.grid, "' ").concat(boundParentRow.column, " = '").concat(boundParentRow.value, "' (boundParentRow). Verify that is the intended parent; pass parentRow to bind explicitly.") : mountedAfterFirst && !explicitParentRow && !_entry2.getBoundParent ? ' SUBTABLE WRITE WITHOUT parentRow: this table declares no parent binding, so the parent row it landed under cannot be named here — verify it in the table before building on the write.' : ''; // A record _id offered as rowId — partlistpos hands the _id out AS the rowId, and locateRow.firstRow._id is the
53860
53470
  // same value — is a valid address once its node is loaded. When it is not (the subtable re-rendered, a filter
@@ -53881,41 +53491,41 @@ function createNavigationToolset(ctx) {
53881
53491
  } finally {
53882
53492
  _iterator6.f();
53883
53493
  }
53884
- _i4 = 0, _arr2 = _toConsumableArray(removeRowIds);
53885
- case 209:
53886
- if (!(_i4 < _arr2.length)) {
53887
- _context18.next = 219;
53494
+ _i3 = 0, _arr2 = _toConsumableArray(removeRowIds);
53495
+ case 208:
53496
+ if (!(_i3 < _arr2.length)) {
53497
+ _context18.next = 218;
53888
53498
  break;
53889
53499
  }
53890
- rowId = _arr2[_i4];
53500
+ rowId = _arr2[_i3];
53891
53501
  if (isUnloadedRecordId(rowId)) {
53892
- _context18.next = 213;
53502
+ _context18.next = 212;
53893
53503
  break;
53894
53504
  }
53895
- return _context18.abrupt("continue", 216);
53896
- case 213:
53505
+ return _context18.abrupt("continue", 215);
53506
+ case 212:
53897
53507
  removeRowIds.splice(removeRowIds.indexOf(rowId), 1);
53898
53508
  removeRows.push({
53899
53509
  keyColumn: '_id',
53900
53510
  keyValue: rowId
53901
53511
  });
53902
53512
  reroutedRecordIds += 1;
53903
- case 216:
53904
- _i4++;
53905
- _context18.next = 209;
53513
+ case 215:
53514
+ _i3++;
53515
+ _context18.next = 208;
53906
53516
  break;
53907
- case 219:
53517
+ case 218:
53908
53518
  // Hard stop for CREATES when the serie scope is unresolved — the row would be filed wherever the endpoint defaults to.
53909
53519
  serieScope = serieScopeOf(_entry2, handle);
53910
53520
  if (!(addRows.length && serieScope && !serieScope.serieId)) {
53911
- _context18.next = 222;
53521
+ _context18.next = 221;
53912
53522
  break;
53913
53523
  }
53914
53524
  return _context18.abrupt("return", {
53915
53525
  error: "'".concat(_entry2.label, "' belongs to ONE serie (its endpoint is /series/<id>/\u2026) and NO serie is selected, so a new row would be filed wherever the view defaults to \u2014 usually the FIRST serie (serie 0, the components serie). Nothing was staged."),
53916
53526
  fix: 'selectSerie(<serieNo>) first — listSeries shows the numbers and the current selection — then re-send this call unchanged.'
53917
53527
  });
53918
- case 222:
53528
+ case 221:
53919
53529
  fmt = function fmt(v) {
53920
53530
  return v == null ? undefined : _typeof(v) === 'object' ? JSON.stringify(v).slice(0, 80) : v;
53921
53531
  }; // The AG col def loses the DIVA custom props (editable/required/customParams) — check the DIVA def too.
@@ -54693,7 +54303,7 @@ function createNavigationToolset(ctx) {
54693
54303
  // for rows that came from a payload: the agent never read them, so this is its only way to check them — and
54694
54304
  // the answer stays small, counts plus the failing rows, however many rows there are.
54695
54305
  if (!(input !== null && input !== void 0 && input.dryRun && addRows.length)) {
54696
- _context18.next = 259;
54306
+ _context18.next = 258;
54697
54307
  break;
54698
54308
  }
54699
54309
  requiredFields = _divaDefs.filter(function (definition) {
@@ -54715,9 +54325,9 @@ function createNavigationToolset(ctx) {
54715
54325
  var judged = [];
54716
54326
  var _loop2 = function _loop2() {
54717
54327
  var _parseRefusalOf;
54718
- var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i5], 2),
54719
- column = _Object$entries2$_i[0],
54720
- rawValue = _Object$entries2$_i[1];
54328
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i4], 2),
54329
+ column = _Object$entries$_i[0],
54330
+ rawValue = _Object$entries$_i[1];
54721
54331
  if (isLookupColumn(column)) {
54722
54332
  var _customParams, _divaDefs$find3, _params$additionalMap;
54723
54333
  usable = true;
@@ -54771,14 +54381,14 @@ function createNavigationToolset(ctx) {
54771
54381
  usable = true;
54772
54382
  },
54773
54383
  _ret2;
54774
- for (var _i5 = 0, _Object$entries2 = Object.entries(rawValues); _i5 < _Object$entries2.length; _i5++) {
54384
+ for (var _i4 = 0, _Object$entries = Object.entries(rawValues); _i4 < _Object$entries.length; _i4++) {
54775
54385
  _ret2 = _loop2();
54776
54386
  if (_ret2 === 0) continue;
54777
54387
  }
54778
54388
  // Pass 2 asks each row rule about the proposed row. A refused column counts as not provided, exactly as
54779
54389
  // a cell the write path refuses never reaches the row.
54780
- for (var _i6 = 0, _judged = judged; _i6 < _judged.length; _i6++) {
54781
- var _column = _judged[_i6];
54390
+ for (var _i5 = 0, _judged = judged; _i5 < _judged.length; _i5++) {
54391
+ var _column = _judged[_i5];
54782
54392
  var verdict = newRowEditability(_column, candidate);
54783
54393
  if (verdict === 'refused') {
54784
54394
  failures.push({
@@ -54834,7 +54444,7 @@ function createNavigationToolset(ctx) {
54834
54444
  return "'".concat(column, "'");
54835
54445
  }).join(', '), " (editabilityUnverified) \u2014 its rule needs grid context a dry run does not have, so the real call may still refuse it. ") : '. ') + "Row numbers count the addRows list (a payload's rows follow the rows listed in the call), then the addRowsTsv lines. " + 'Re-send without dryRun to stage and commit.' + (addRows.length > WRITE_ROW_LIMIT ? " NOTE: ".concat(addRows.length, " rows exceed the ").concat(WRITE_ROW_LIMIT, "-row limit of ONE write \u2014 split them across calls.") : '')
54836
54446
  }));
54837
- case 259:
54447
+ case 258:
54838
54448
  /** Mirrors locateRowCore's own loaded-rows check (read-only) — never mutates the filter itself. */
54839
54449
  needsServerLookup = function needsServerLookup(keyColumn, keyValue) {
54840
54450
  var colDef = columnDefFor(keyColumn);
@@ -54938,24 +54548,24 @@ function createNavigationToolset(ctx) {
54938
54548
  };
54939
54549
  preApproved = false;
54940
54550
  if (!(lookupKeys.size > 0)) {
54941
- _context18.next = 307;
54551
+ _context18.next = 306;
54942
54552
  break;
54943
54553
  }
54944
54554
  intendedCount = edits.length + addRows.length + removeRowIds.length + removeRows.length;
54945
54555
  if (!ctx.autoApprove) awaitingApproval();
54946
54556
  _context18.t4 = ctx.autoApprove;
54947
54557
  if (_context18.t4) {
54948
- _context18.next = 278;
54558
+ _context18.next = 277;
54949
54559
  break;
54950
54560
  }
54951
- _context18.next = 277;
54561
+ _context18.next = 276;
54952
54562
  return _entry2.requestAgentApproval(intendedCount, "".concat(intendedCount, " change(s) \u2014 ").concat(lookupKeys.size, " row(s) must be located first"), signal);
54953
- case 277:
54563
+ case 276:
54954
54564
  _context18.t4 = _context18.sent;
54955
- case 278:
54565
+ case 277:
54956
54566
  _approved = _context18.t4;
54957
54567
  if (_approved) {
54958
- _context18.next = 282;
54568
+ _context18.next = 281;
54959
54569
  break;
54960
54570
  }
54961
54571
  restoreUserFilter();
@@ -54964,10 +54574,10 @@ function createNavigationToolset(ctx) {
54964
54574
  stagedCount: 0,
54965
54575
  note: 'The user DECLINED the change — nothing was staged or saved. Do not retry; ask what to do instead.'
54966
54576
  });
54967
- case 282:
54577
+ case 281:
54968
54578
  preApproved = true;
54969
54579
  _iterator12 = _createForOfIteratorHelper$r(lookupKeys.values());
54970
- _context18.prev = 284;
54580
+ _context18.prev = 283;
54971
54581
  _loop3 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop3() {
54972
54582
  var _step12$value, keyColumn, keyValue, target, _target$error, node, rowId, rowEdits, rowRemovals, _node$data3, _iterator13, _step13, _edit$column, _edit;
54973
54583
  return _regeneratorRuntime.wrap(function _loop3$(_context7) {
@@ -55062,116 +54672,116 @@ function createNavigationToolset(ctx) {
55062
54672
  }, _loop3, null, [[22, 32, 35, 38]]);
55063
54673
  });
55064
54674
  _iterator12.s();
55065
- case 287:
54675
+ case 286:
55066
54676
  if ((_step12 = _iterator12.n()).done) {
55067
- _context18.next = 294;
54677
+ _context18.next = 293;
55068
54678
  break;
55069
54679
  }
55070
- return _context18.delegateYield(_loop3(), "t5", 289);
55071
- case 289:
54680
+ return _context18.delegateYield(_loop3(), "t5", 288);
54681
+ case 288:
55072
54682
  _ret3 = _context18.t5;
55073
54683
  if (!(_ret3 === 0)) {
55074
- _context18.next = 292;
54684
+ _context18.next = 291;
55075
54685
  break;
55076
54686
  }
55077
- return _context18.abrupt("continue", 292);
55078
- case 292:
55079
- _context18.next = 287;
54687
+ return _context18.abrupt("continue", 291);
54688
+ case 291:
54689
+ _context18.next = 286;
55080
54690
  break;
55081
- case 294:
55082
- _context18.next = 299;
54691
+ case 293:
54692
+ _context18.next = 298;
55083
54693
  break;
55084
- case 296:
55085
- _context18.prev = 296;
55086
- _context18.t6 = _context18["catch"](284);
54694
+ case 295:
54695
+ _context18.prev = 295;
54696
+ _context18.t6 = _context18["catch"](283);
55087
54697
  _iterator12.e(_context18.t6);
55088
- case 299:
55089
- _context18.prev = 299;
54698
+ case 298:
54699
+ _context18.prev = 298;
55090
54700
  _iterator12.f();
55091
- return _context18.finish(299);
55092
- case 302:
54701
+ return _context18.finish(298);
54702
+ case 301:
55093
54703
  // Bring the loaded window back to what the caller had before more edits (possibly rowId-addressed,
55094
54704
  // always assumed already-loaded) rely on it — restoreUserFilter only mutates when a lookup above
55095
54705
  // actually changed something, and the grid needs a moment to settle after a filter change.
55096
54706
  filterWasChanged = keyFilterApplied;
55097
54707
  restoreUserFilter();
55098
54708
  if (!filterWasChanged) {
55099
- _context18.next = 307;
54709
+ _context18.next = 306;
55100
54710
  break;
55101
54711
  }
55102
- _context18.next = 307;
54712
+ _context18.next = 306;
55103
54713
  return waitForRows(_api2);
55104
- case 307:
54714
+ case 306:
55105
54715
  // Key-addressed removals resolve to rowIds before the edit loop (conflicts are checked against the final id list).
55106
54716
  // Rows already resolved+staged+committed by the sequential lookup pass above are skipped here.
55107
54717
  _iterator14 = _createForOfIteratorHelper$r(removeRows);
55108
- _context18.prev = 308;
54718
+ _context18.prev = 307;
55109
54719
  _iterator14.s();
55110
- case 310:
54720
+ case 309:
55111
54721
  if ((_step14 = _iterator14.n()).done) {
55112
- _context18.next = 324;
54722
+ _context18.next = 323;
55113
54723
  break;
55114
54724
  }
55115
54725
  _removal2 = _step14.value;
55116
54726
  if (!((_removal2 === null || _removal2 === void 0 ? void 0 : _removal2.keyColumn) != null && (_removal2 === null || _removal2 === void 0 ? void 0 : _removal2.keyValue) != null && lookupKeys.has(lookupKeyOf(String(_removal2.keyColumn), String(_removal2.keyValue))))) {
55117
- _context18.next = 314;
54727
+ _context18.next = 313;
55118
54728
  break;
55119
54729
  }
55120
- return _context18.abrupt("continue", 322);
55121
- case 314:
55122
- _context18.next = 316;
54730
+ return _context18.abrupt("continue", 321);
54731
+ case 313:
54732
+ _context18.next = 315;
55123
54733
  return resolveTarget(_removal2);
55124
- case 316:
54734
+ case 315:
55125
54735
  _target2 = _context18.sent;
55126
54736
  if (!(_target2.error || !_target2.node)) {
55127
- _context18.next = 320;
54737
+ _context18.next = 319;
55128
54738
  break;
55129
54739
  }
55130
54740
  failed.push({
55131
54741
  rowId: _target2.label,
55132
54742
  error: (_target2$error = _target2.error) !== null && _target2$error !== void 0 ? _target2$error : 'Row not found.'
55133
54743
  });
55134
- return _context18.abrupt("continue", 322);
55135
- case 320:
54744
+ return _context18.abrupt("continue", 321);
54745
+ case 319:
55136
54746
  id = String(_target2.node.id);
55137
54747
  if (!removeRowIds.includes(id)) removeRowIds.push(id);
55138
- case 322:
55139
- _context18.next = 310;
54748
+ case 321:
54749
+ _context18.next = 309;
55140
54750
  break;
55141
- case 324:
55142
- _context18.next = 329;
54751
+ case 323:
54752
+ _context18.next = 328;
55143
54753
  break;
55144
- case 326:
55145
- _context18.prev = 326;
55146
- _context18.t7 = _context18["catch"](308);
54754
+ case 325:
54755
+ _context18.prev = 325;
54756
+ _context18.t7 = _context18["catch"](307);
55147
54757
  _iterator14.e(_context18.t7);
55148
- case 329:
55149
- _context18.prev = 329;
54758
+ case 328:
54759
+ _context18.prev = 328;
55150
54760
  _iterator14.f();
55151
- return _context18.finish(329);
55152
- case 332:
54761
+ return _context18.finish(328);
54762
+ case 331:
55153
54763
  _iterator15 = _createForOfIteratorHelper$r(edits);
55154
- _context18.prev = 333;
54764
+ _context18.prev = 332;
55155
54765
  _iterator15.s();
55156
- case 335:
54766
+ case 334:
55157
54767
  if ((_step15 = _iterator15.n()).done) {
55158
- _context18.next = 355;
54768
+ _context18.next = 354;
55159
54769
  break;
55160
54770
  }
55161
54771
  _edit4 = _step15.value;
55162
54772
  if (!((_edit4 === null || _edit4 === void 0 ? void 0 : _edit4.rowId) == null && (_edit4 === null || _edit4 === void 0 ? void 0 : _edit4.keyColumn) != null && (_edit4 === null || _edit4 === void 0 ? void 0 : _edit4.keyValue) != null && lookupKeys.has(lookupKeyOf(String(_edit4.keyColumn), String(_edit4.keyValue))))) {
55163
- _context18.next = 339;
54773
+ _context18.next = 338;
55164
54774
  break;
55165
54775
  }
55166
- return _context18.abrupt("continue", 353);
55167
- case 339:
54776
+ return _context18.abrupt("continue", 352);
54777
+ case 338:
55168
54778
  _column2 = String((_edit4$column = _edit4 === null || _edit4 === void 0 ? void 0 : _edit4.column) !== null && _edit4$column !== void 0 ? _edit4$column : '');
55169
- _context18.next = 342;
54779
+ _context18.next = 341;
55170
54780
  return resolveTarget(_edit4);
55171
- case 342:
54781
+ case 341:
55172
54782
  _target3 = _context18.sent;
55173
54783
  if (!(_target3.error || !_target3.node)) {
55174
- _context18.next = 346;
54784
+ _context18.next = 345;
55175
54785
  break;
55176
54786
  }
55177
54787
  failed.push({
@@ -55179,12 +54789,12 @@ function createNavigationToolset(ctx) {
55179
54789
  column: _column2,
55180
54790
  error: (_target3$error = _target3.error) !== null && _target3$error !== void 0 ? _target3$error : 'Row not found.'
55181
54791
  });
55182
- return _context18.abrupt("continue", 353);
55183
- case 346:
54792
+ return _context18.abrupt("continue", 352);
54793
+ case 345:
55184
54794
  _node2 = _target3.node;
55185
54795
  _rowId2 = String(_node2.id);
55186
54796
  if (!removeRowIds.includes(_rowId2)) {
55187
- _context18.next = 351;
54797
+ _context18.next = 350;
55188
54798
  break;
55189
54799
  }
55190
54800
  failed.push({
@@ -55192,25 +54802,25 @@ function createNavigationToolset(ctx) {
55192
54802
  column: _column2,
55193
54803
  error: 'This row is also being removed — edit OR remove a row, not both.'
55194
54804
  });
55195
- return _context18.abrupt("continue", 353);
55196
- case 351:
55197
- _context18.next = 353;
54805
+ return _context18.abrupt("continue", 352);
54806
+ case 350:
54807
+ _context18.next = 352;
55198
54808
  return applyEditToNode(_node2, _rowId2, _column2, _edit4 === null || _edit4 === void 0 ? void 0 : _edit4.newValue);
55199
- case 353:
55200
- _context18.next = 335;
54809
+ case 352:
54810
+ _context18.next = 334;
55201
54811
  break;
55202
- case 355:
55203
- _context18.next = 360;
54812
+ case 354:
54813
+ _context18.next = 359;
55204
54814
  break;
55205
- case 357:
55206
- _context18.prev = 357;
55207
- _context18.t8 = _context18["catch"](333);
54815
+ case 356:
54816
+ _context18.prev = 356;
54817
+ _context18.t8 = _context18["catch"](332);
55208
54818
  _iterator15.e(_context18.t8);
55209
- case 360:
55210
- _context18.prev = 360;
54819
+ case 359:
54820
+ _context18.prev = 359;
55211
54821
  _iterator15.f();
55212
- return _context18.finish(360);
55213
- case 363:
54822
+ return _context18.finish(359);
54823
+ case 362:
55214
54824
  targets = removeRowIds.filter(function (rowId) {
55215
54825
  if (isRealRow(_api2.getRowNode(rowId))) return true;
55216
54826
  failed.push({
@@ -55231,36 +54841,36 @@ function createNavigationToolset(ctx) {
55231
54841
  _iterator16.f();
55232
54842
  }
55233
54843
  if (!targets.length) {
55234
- _context18.next = 370;
54844
+ _context18.next = 369;
55235
54845
  break;
55236
54846
  }
55237
- _context18.next = 369;
54847
+ _context18.next = 368;
55238
54848
  return handle.stageRemoveRows(targets);
55239
- case 369:
54849
+ case 368:
55240
54850
  removed.push.apply(removed, _toConsumableArray(targets));
55241
- case 370:
54851
+ case 369:
55242
54852
  addedRows = [];
55243
54853
  /** Columns the AGENT provided per added row — lookup writes drag companion fields into `values`. */
55244
54854
  providedAddColumns = new Map();
55245
54855
  conditionedPosDefaults = 0;
55246
54856
  lookupWriteCache = new Map();
55247
54857
  _loop4 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop4() {
55248
- var _addRows$_i7$values, _addRows$_i, _handle$getApplicatio5, _handle$getApplicatio6;
55249
- var rawValues, plainCols, lookupCols, bad, _i10, _Object$entries4, _Object$entries4$_i, _column3, rawValue, check, provided, _loop6, _i11, _lookupCols, hasField, requiredMissing, seed, newId, values, _i12, _plainCols, _plainCols$_i, _column4, text, ok, appData, rowFields, rowDepsOf, lookupColumns, _loop7, _ret5, _api2$getRowNode$data, _api2$getRowNode9, finished, _iterator25, _step25, _divaDefOf3, _step25$value, _column5, _text, isPosCountRow, _ok2, _api2$getRowNode$data2, _api2$getRowNode10, _finished, _i13, _arr3, _divaDefOf4, _column6, editableFn, locked;
54858
+ var _addRows$_i6$values, _addRows$_i, _handle$getApplicatio5, _handle$getApplicatio6;
54859
+ var rawValues, plainCols, lookupCols, bad, _i9, _Object$entries3, _Object$entries3$_i, _column3, rawValue, check, provided, _loop6, _i10, _lookupCols, hasField, requiredMissing, seed, newId, values, _i11, _plainCols, _plainCols$_i, _column4, text, ok, appData, rowFields, rowDepsOf, lookupColumns, _loop7, _ret5, _api2$getRowNode$data, _api2$getRowNode9, finished, _iterator25, _step25, _divaDefOf3, _step25$value, _column5, _text, isPosCountRow, _ok2, _api2$getRowNode$data2, _api2$getRowNode10, _finished, _i12, _arr3, _divaDefOf4, _column6, editableFn, locked;
55250
54860
  return _regeneratorRuntime.wrap(function _loop4$(_context12) {
55251
54861
  while (1) switch (_context12.prev = _context12.next) {
55252
54862
  case 0:
55253
- rawValues = (_addRows$_i7$values = (_addRows$_i = addRows[_i7]) === null || _addRows$_i === void 0 ? void 0 : _addRows$_i.values) !== null && _addRows$_i7$values !== void 0 ? _addRows$_i7$values : {};
54863
+ rawValues = (_addRows$_i6$values = (_addRows$_i = addRows[_i6]) === null || _addRows$_i === void 0 ? void 0 : _addRows$_i.values) !== null && _addRows$_i6$values !== void 0 ? _addRows$_i6$values : {};
55254
54864
  plainCols = [];
55255
54865
  lookupCols = [];
55256
54866
  bad = false; // Every plain column is checked before anything is staged; the table parses them once the row exists.
55257
- _i10 = 0, _Object$entries4 = Object.entries(rawValues);
54867
+ _i9 = 0, _Object$entries3 = Object.entries(rawValues);
55258
54868
  case 5:
55259
- if (!(_i10 < _Object$entries4.length)) {
54869
+ if (!(_i9 < _Object$entries3.length)) {
55260
54870
  _context12.next = 19;
55261
54871
  break;
55262
54872
  }
55263
- _Object$entries4$_i = _slicedToArray(_Object$entries4[_i10], 2), _column3 = _Object$entries4$_i[0], rawValue = _Object$entries4$_i[1];
54873
+ _Object$entries3$_i = _slicedToArray(_Object$entries3[_i9], 2), _column3 = _Object$entries3$_i[0], rawValue = _Object$entries3$_i[1];
55264
54874
  if (!isLookupColumn(_column3)) {
55265
54875
  _context12.next = 10;
55266
54876
  break;
@@ -55279,7 +54889,7 @@ function createNavigationToolset(ctx) {
55279
54889
  break;
55280
54890
  }
55281
54891
  failed.push({
55282
- rowId: "addRows[".concat(_i7, "]"),
54892
+ rowId: "addRows[".concat(_i6, "]"),
55283
54893
  column: _column3,
55284
54894
  error: check.error
55285
54895
  });
@@ -55288,7 +54898,7 @@ function createNavigationToolset(ctx) {
55288
54898
  case 15:
55289
54899
  if (check.text !== '') plainCols.push([_column3, check.text]);
55290
54900
  case 16:
55291
- _i10++;
54901
+ _i9++;
55292
54902
  _context12.next = 5;
55293
54903
  break;
55294
54904
  case 19:
@@ -55303,7 +54913,7 @@ function createNavigationToolset(ctx) {
55303
54913
  break;
55304
54914
  }
55305
54915
  failed.push({
55306
- rowId: "addRows[".concat(_i7, "]"),
54916
+ rowId: "addRows[".concat(_i6, "]"),
55307
54917
  error: 'No usable values — provide at least one column value.'
55308
54918
  });
55309
54919
  return _context12.abrupt("return", 0);
@@ -55321,7 +54931,7 @@ function createNavigationToolset(ctx) {
55321
54931
  return _regeneratorRuntime.wrap(function _loop6$(_context10) {
55322
54932
  while (1) switch (_context10.prev = _context10.next) {
55323
54933
  case 0:
55324
- _lookupCols$_i = _slicedToArray(_lookupCols[_i11], 1), column = _lookupCols$_i[0];
54934
+ _lookupCols$_i = _slicedToArray(_lookupCols[_i10], 1), column = _lookupCols$_i[0];
55325
54935
  provided.add(column);
55326
54936
  params = (_divaDefs$find$custom = (_divaDefs$find4 = _divaDefs.find(function (d) {
55327
54937
  return d.field === column;
@@ -55344,15 +54954,15 @@ function createNavigationToolset(ctx) {
55344
54954
  }
55345
54955
  }, _loop6);
55346
54956
  });
55347
- _i11 = 0, _lookupCols = lookupCols;
54957
+ _i10 = 0, _lookupCols = lookupCols;
55348
54958
  case 27:
55349
- if (!(_i11 < _lookupCols.length)) {
54959
+ if (!(_i10 < _lookupCols.length)) {
55350
54960
  _context12.next = 32;
55351
54961
  break;
55352
54962
  }
55353
54963
  return _context12.delegateYield(_loop6(), "t0", 29);
55354
54964
  case 29:
55355
- _i11++;
54965
+ _i10++;
55356
54966
  _context12.next = 27;
55357
54967
  break;
55358
54968
  case 32:
@@ -55373,7 +54983,7 @@ function createNavigationToolset(ctx) {
55373
54983
  break;
55374
54984
  }
55375
54985
  failed.push({
55376
- rowId: "addRows[".concat(_i7, "]"),
54986
+ rowId: "addRows[".concat(_i6, "]"),
55377
54987
  error: "Missing required column(s): ".concat(requiredMissing.join(', '), ".")
55378
54988
  });
55379
54989
  return _context12.abrupt("return", 0);
@@ -55397,19 +55007,19 @@ function createNavigationToolset(ctx) {
55397
55007
  break;
55398
55008
  }
55399
55009
  failed.push({
55400
- rowId: "addRows[".concat(_i7, "]"),
55010
+ rowId: "addRows[".concat(_i6, "]"),
55401
55011
  error: 'This table does not support creating rows (no create endpoint).'
55402
55012
  });
55403
55013
  return _context12.abrupt("return", 0);
55404
55014
  case 45:
55405
55015
  values = _objectSpread$X({}, seed);
55406
- _i12 = 0, _plainCols = plainCols;
55016
+ _i11 = 0, _plainCols = plainCols;
55407
55017
  case 47:
55408
- if (!(_i12 < _plainCols.length)) {
55018
+ if (!(_i11 < _plainCols.length)) {
55409
55019
  _context12.next = 60;
55410
55020
  break;
55411
55021
  }
55412
- _plainCols$_i = _slicedToArray(_plainCols[_i12], 2), _column4 = _plainCols$_i[0], text = _plainCols$_i[1];
55022
+ _plainCols$_i = _slicedToArray(_plainCols[_i11], 2), _column4 = _plainCols$_i[0], text = _plainCols$_i[1];
55413
55023
  _context12.next = 51;
55414
55024
  return writeCell(newId, _column4, text);
55415
55025
  case 51:
@@ -55419,7 +55029,7 @@ function createNavigationToolset(ctx) {
55419
55029
  break;
55420
55030
  }
55421
55031
  failed.push({
55422
- rowId: "addRows[".concat(_i7, "]"),
55032
+ rowId: "addRows[".concat(_i6, "]"),
55423
55033
  column: _column4,
55424
55034
  error: ok
55425
55035
  });
@@ -55428,7 +55038,7 @@ function createNavigationToolset(ctx) {
55428
55038
  case 56:
55429
55039
  values[_column4] = cellValueOf(_api2, _api2.getRowNode(newId), _column4);
55430
55040
  case 57:
55431
- _i12++;
55041
+ _i11++;
55432
55042
  _context12.next = 47;
55433
55043
  break;
55434
55044
  case 60:
@@ -55456,7 +55066,7 @@ function createNavigationToolset(ctx) {
55456
55066
  });
55457
55067
  _loop7 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop7() {
55458
55068
  var _api2$getRowNode$data3, _api2$getRowNode11, _lookupWriteCache$get;
55459
- var readyIdx, _lookupCols$splice$, column, rawValue, missingDeps, providers, lookupRowData, lookupCacheKey, res, write, _i14, _Object$entries5, _res$data, _Object$entries5$_i, key, value;
55069
+ var readyIdx, _lookupCols$splice$, column, rawValue, missingDeps, providers, lookupRowData, lookupCacheKey, res, write, _i13, _Object$entries4, _res$data, _Object$entries4$_i, key, value;
55460
55070
  return _regeneratorRuntime.wrap(function _loop7$(_context11) {
55461
55071
  while (1) switch (_context11.prev = _context11.next) {
55462
55072
  case 0:
@@ -55484,7 +55094,7 @@ function createNavigationToolset(ctx) {
55484
55094
  return provider !== null && provider !== void 0 && provider.field && provider.field !== column ? "'".concat(provider.field, "'") : "'".concat(dep, "'");
55485
55095
  });
55486
55096
  failed.push({
55487
- rowId: "addRows[".concat(_i7, "]"),
55097
+ rowId: "addRows[".concat(_i6, "]"),
55488
55098
  column: column,
55489
55099
  error: "Column '".concat(column, "' is a lookup whose option list depends on ").concat(providers.join(' + '), " \u2014 set that column in the SAME row (its value resolves the list).")
55490
55100
  });
@@ -55519,7 +55129,7 @@ function createNavigationToolset(ctx) {
55519
55129
  break;
55520
55130
  }
55521
55131
  failed.push({
55522
- rowId: "addRows[".concat(_i7, "]"),
55132
+ rowId: "addRows[".concat(_i6, "]"),
55523
55133
  column: column,
55524
55134
  error: res.error
55525
55135
  });
@@ -55528,8 +55138,8 @@ function createNavigationToolset(ctx) {
55528
55138
  case 23:
55529
55139
  // On a NEW row an undefined write-shape entry means "leave empty" — skip it so it does not clobber a provided key.
55530
55140
  write = {};
55531
- for (_i14 = 0, _Object$entries5 = Object.entries((_res$data = res.data) !== null && _res$data !== void 0 ? _res$data : {}); _i14 < _Object$entries5.length; _i14++) {
55532
- _Object$entries5$_i = _slicedToArray(_Object$entries5[_i14], 2), key = _Object$entries5$_i[0], value = _Object$entries5$_i[1];
55141
+ for (_i13 = 0, _Object$entries4 = Object.entries((_res$data = res.data) !== null && _res$data !== void 0 ? _res$data : {}); _i13 < _Object$entries4.length; _i13++) {
55142
+ _Object$entries4$_i = _slicedToArray(_Object$entries4[_i13], 2), key = _Object$entries4$_i[0], value = _Object$entries4$_i[1];
55533
55143
  if (value !== undefined) write[key] = value;
55534
55144
  }
55535
55145
  _context11.t1 = Object.keys(write).length;
@@ -55549,7 +55159,7 @@ function createNavigationToolset(ctx) {
55549
55159
  break;
55550
55160
  }
55551
55161
  failed.push({
55552
- rowId: "addRows[".concat(_i7, "]"),
55162
+ rowId: "addRows[".concat(_i6, "]"),
55553
55163
  column: column,
55554
55164
  error: 'Staging failed (row disappeared?).'
55555
55165
  });
@@ -55612,7 +55222,7 @@ function createNavigationToolset(ctx) {
55612
55222
  break;
55613
55223
  }
55614
55224
  failed.push({
55615
- rowId: "addRows[".concat(_i7, "]"),
55225
+ rowId: "addRows[".concat(_i6, "]"),
55616
55226
  column: _column5,
55617
55227
  error: _ok2
55618
55228
  });
@@ -55641,17 +55251,17 @@ function createNavigationToolset(ctx) {
55641
55251
  }
55642
55252
  _finished = (_api2$getRowNode$data2 = (_api2$getRowNode10 = _api2.getRowNode(newId)) === null || _api2$getRowNode10 === void 0 ? void 0 : _api2$getRowNode10.data) !== null && _api2$getRowNode$data2 !== void 0 ? _api2$getRowNode$data2 : values; // Lookup columns too: `lookupWrite` never evaluates the rule, so a lookup a creatable table locks on the
55643
55253
  // finished row (a parent key chosen by another column) would otherwise reach the server unchecked.
55644
- _i13 = 0, _arr3 = [].concat(_toConsumableArray(plainCols.map(function (_ref40) {
55254
+ _i12 = 0, _arr3 = [].concat(_toConsumableArray(plainCols.map(function (_ref40) {
55645
55255
  var _ref41 = _slicedToArray(_ref40, 1),
55646
55256
  field = _ref41[0];
55647
55257
  return field;
55648
55258
  })), _toConsumableArray(lookupColumns));
55649
55259
  case 103:
55650
- if (!(_i13 < _arr3.length)) {
55260
+ if (!(_i12 < _arr3.length)) {
55651
55261
  _context12.next = 118;
55652
55262
  break;
55653
55263
  }
55654
- _column6 = _arr3[_i13];
55264
+ _column6 = _arr3[_i12];
55655
55265
  editableFn = (_divaDefOf4 = divaDefOf(_divaDefs, _column6)) === null || _divaDefOf4 === void 0 ? void 0 : _divaDefOf4.editable;
55656
55266
  if (!(typeof editableFn !== 'function')) {
55657
55267
  _context12.next = 108;
@@ -55674,14 +55284,14 @@ function createNavigationToolset(ctx) {
55674
55284
  return _context12.abrupt("continue", 115);
55675
55285
  case 112:
55676
55286
  failed.push({
55677
- rowId: "addRows[".concat(_i7, "]"),
55287
+ rowId: "addRows[".concat(_i6, "]"),
55678
55288
  column: _column6,
55679
55289
  error: "Column '".concat(_column6, "' is not editable on this row (row-dependent rule) \u2014 the row's other values rule it out; check the table's description.")
55680
55290
  });
55681
55291
  bad = true;
55682
55292
  return _context12.abrupt("break", 118);
55683
55293
  case 115:
55684
- _i13++;
55294
+ _i12++;
55685
55295
  _context12.next = 103;
55686
55296
  break;
55687
55297
  case 118:
@@ -55705,25 +55315,25 @@ function createNavigationToolset(ctx) {
55705
55315
  }
55706
55316
  }, _loop4, null, [[75, 94, 97, 100]]);
55707
55317
  });
55708
- _i7 = 0;
55709
- case 376:
55710
- if (!(_i7 < addRows.length)) {
55711
- _context18.next = 384;
55318
+ _i6 = 0;
55319
+ case 375:
55320
+ if (!(_i6 < addRows.length)) {
55321
+ _context18.next = 383;
55712
55322
  break;
55713
55323
  }
55714
- return _context18.delegateYield(_loop4(), "t9", 378);
55715
- case 378:
55324
+ return _context18.delegateYield(_loop4(), "t9", 377);
55325
+ case 377:
55716
55326
  _ret4 = _context18.t9;
55717
55327
  if (!(_ret4 === 0)) {
55718
- _context18.next = 381;
55328
+ _context18.next = 380;
55719
55329
  break;
55720
55330
  }
55721
- return _context18.abrupt("continue", 381);
55722
- case 381:
55723
- _i7++;
55724
- _context18.next = 376;
55331
+ return _context18.abrupt("continue", 380);
55332
+ case 380:
55333
+ _i6++;
55334
+ _context18.next = 375;
55725
55335
  break;
55726
- case 384:
55336
+ case 383:
55727
55337
  // Any add failed → return the table's FULL add schema so the next attempt has everything.
55728
55338
  addSchemaHint = function addSchemaHint() {
55729
55339
  if (!addRows.length) return '';
@@ -55740,7 +55350,7 @@ function createNavigationToolset(ctx) {
55740
55350
  return " ADD SCHEMA of '".concat(_entry2.label, "' \u2014 required: ").concat(req.join(', ') || 'none').concat(defaulted.length ? "; defaulted (OMIT): ".concat(defaulted.join(', ')) : '', ". Enum/lookup columns take only their listed values (listGrids/readColumnOptions).");
55741
55351
  };
55742
55352
  if (!(!staged.length && !addedRows.length && !removed.length)) {
55743
- _context18.next = 388;
55353
+ _context18.next = 387;
55744
55354
  break;
55745
55355
  }
55746
55356
  restoreUserFilter();
@@ -55751,7 +55361,7 @@ function createNavigationToolset(ctx) {
55751
55361
  failed: failed.length ? summarizeFailures(failed) : undefined,
55752
55362
  note: unchanged.length ? 'NOTHING was staged: every proposed value equals the current cell value (the change may already have been applied earlier). Tell the user the data already matches — do NOT claim you changed anything.' : "Nothing could be staged \u2014 nothing to approve. Fix the failures (fresh readGridRows) and try again.".concat(failed.length ? addSchemaHint() : '')
55753
55363
  });
55754
- case 388:
55364
+ case 387:
55755
55365
  // The table would silently skip invalid staged rows on save — surface that as a failure instead of a fake success.
55756
55366
  validationErrors = []; // Rows the sequential lookup pass already sent carry the SERVER's verdict (a rejection leaves the same
55757
55367
  // error markers) — that is reported as a server error below, not as a validation failure of the rest.
@@ -55763,20 +55373,20 @@ function createNavigationToolset(ctx) {
55763
55373
  })), _toConsumableArray(addedRows.map(function (a) {
55764
55374
  return a.rowId;
55765
55375
  })))));
55766
- _context18.prev = 391;
55376
+ _context18.prev = 390;
55767
55377
  _iterator17.s();
55768
- case 393:
55378
+ case 392:
55769
55379
  if ((_step17 = _iterator17.n()).done) {
55770
- _context18.next = 401;
55380
+ _context18.next = 400;
55771
55381
  break;
55772
55382
  }
55773
55383
  _rowId3 = _step17.value;
55774
55384
  if (!alreadySent.has(_rowId3)) {
55775
- _context18.next = 397;
55385
+ _context18.next = 396;
55776
55386
  break;
55777
55387
  }
55778
- return _context18.abrupt("continue", 399);
55779
- case 397:
55388
+ return _context18.abrupt("continue", 398);
55389
+ case 396:
55780
55390
  rowErrors = (_api2$getRowNode12 = _api2.getRowNode(_rowId3)) === null || _api2$getRowNode12 === void 0 || (_api2$getRowNode12 = _api2$getRowNode12.data) === null || _api2$getRowNode12 === void 0 || (_api2$getRowNode12 = _api2$getRowNode12.__diva_context) === null || _api2$getRowNode12 === void 0 ? void 0 : _api2$getRowNode12.errors;
55781
55391
  if (Array.isArray(rowErrors) && rowErrors.length) {
55782
55392
  validationErrors.push({
@@ -55786,28 +55396,28 @@ function createNavigationToolset(ctx) {
55786
55396
  })
55787
55397
  });
55788
55398
  }
55789
- case 399:
55790
- _context18.next = 393;
55399
+ case 398:
55400
+ _context18.next = 392;
55791
55401
  break;
55792
- case 401:
55793
- _context18.next = 406;
55402
+ case 400:
55403
+ _context18.next = 405;
55794
55404
  break;
55795
- case 403:
55796
- _context18.prev = 403;
55797
- _context18.t10 = _context18["catch"](391);
55405
+ case 402:
55406
+ _context18.prev = 402;
55407
+ _context18.t10 = _context18["catch"](390);
55798
55408
  _iterator17.e(_context18.t10);
55799
- case 406:
55800
- _context18.prev = 406;
55409
+ case 405:
55410
+ _context18.prev = 405;
55801
55411
  _iterator17.f();
55802
- return _context18.finish(406);
55803
- case 409:
55412
+ return _context18.finish(405);
55413
+ case 408:
55804
55414
  if (!validationErrors.length) {
55805
- _context18.next = 414;
55415
+ _context18.next = 413;
55806
55416
  break;
55807
55417
  }
55808
- _context18.next = 412;
55418
+ _context18.next = 411;
55809
55419
  return handle.rollback();
55810
- case 412:
55420
+ case 411:
55811
55421
  restoreUserFilter();
55812
55422
  // Rows resolved by the sequential lookup pass above commit individually, BEFORE this check runs —
55813
55423
  // a validation failure in the rest of the batch cannot roll those back, so "everything was reverted"
@@ -55822,7 +55432,7 @@ function createNavigationToolset(ctx) {
55822
55432
  failed: failed.length ? summarizeFailures(failed) : undefined,
55823
55433
  note: mergedOutcome.committed.length ? "".concat(mergedOutcome.committed.length, " row(s) addressed by keyColumn/keyValue were already COMMITTED individually before this validation failure (each such row is located, staged and saved on its own, to avoid losing it to a later filter change) \u2014 do NOT re-send those, see committedRowIds. The REST of the batch failed validation and was reverted: fix the listed problems and try ONE new stageTableEdits call for just those.").concat(addSchemaHint()) : "NOTHING was staged for approval: some rows fail the table's validation (everything was reverted). Fix the listed problems \u2014 e.g. fill the required columns \u2014 and try ONE new stageTableEdits call.".concat(addSchemaHint())
55824
55434
  }));
55825
- case 414:
55435
+ case 413:
55826
55436
  // Bring the first staged row into view; staged cells/rows are highlighted.
55827
55437
  focusNode = _api2.getRowNode((_ref26 = (_ref27 = (_staged$0$rowId = (_staged$ = staged[0]) === null || _staged$ === void 0 ? void 0 : _staged$.rowId) !== null && _staged$0$rowId !== void 0 ? _staged$0$rowId : removed[0]) !== null && _ref27 !== void 0 ? _ref27 : (_addedRows$ = addedRows[0]) === null || _addedRows$ === void 0 ? void 0 : _addedRows$.rowId) !== null && _ref26 !== void 0 ? _ref26 : '');
55828
55438
  if ((focusNode === null || focusNode === void 0 ? void 0 : focusNode.rowIndex) != null) _api2.ensureIndexVisible(focusNode.rowIndex, 'middle');
@@ -55854,27 +55464,27 @@ function createNavigationToolset(ctx) {
55854
55464
  if (!ctx.autoApprove && !preApproved) awaitingApproval();
55855
55465
  _context18.t11 = ctx.autoApprove || preApproved;
55856
55466
  if (_context18.t11) {
55857
- _context18.next = 424;
55467
+ _context18.next = 423;
55858
55468
  break;
55859
55469
  }
55860
- _context18.next = 423;
55470
+ _context18.next = 422;
55861
55471
  return _entry2.requestAgentApproval(totalStaged, undefined, signal);
55862
- case 423:
55472
+ case 422:
55863
55473
  _context18.t11 = _context18.sent;
55864
- case 424:
55474
+ case 423:
55865
55475
  approved = _context18.t11;
55866
55476
  if (approved) {
55867
- _context18.next = 434;
55477
+ _context18.next = 433;
55868
55478
  break;
55869
55479
  }
55870
- _context18.next = 428;
55480
+ _context18.next = 427;
55871
55481
  return handle.rollback();
55872
- case 428:
55482
+ case 427:
55873
55483
  survived = survivingOperations();
55874
55484
  survivedCount = survived.changes.length + survived.addedRowIds.length + survived.removedRowIds.length;
55875
55485
  restoreUserFilter();
55876
55486
  if (survivedCount) {
55877
- _context18.next = 433;
55487
+ _context18.next = 432;
55878
55488
  break;
55879
55489
  }
55880
55490
  return _context18.abrupt("return", {
@@ -55883,7 +55493,7 @@ function createNavigationToolset(ctx) {
55883
55493
  failed: failed.length ? summarizeFailures(failed) : undefined,
55884
55494
  note: 'The user DISCARDED the staged changes — nothing was saved. Do NOT re-stage the same values; ask what to adjust instead.'
55885
55495
  });
55886
- case 433:
55496
+ case 432:
55887
55497
  return _context18.abrupt("return", {
55888
55498
  applied: true,
55889
55499
  appliedCount: survivedCount,
@@ -55900,7 +55510,7 @@ function createNavigationToolset(ctx) {
55900
55510
  failed: failed.length ? summarizeFailures(failed) : undefined,
55901
55511
  note: 'The user DISCARDED the staged changes, but the table had ALREADY SAVED the listed operations before the decision arrived ' + '(it saves pending edits by itself when the user clicks outside the grid), so the rollback found nothing to revert. ' + 'Report EXACTLY these operations as live on the server and ask the user whether to undo them — do NOT re-send them, and do not claim the discard took effect.'
55902
55512
  });
55903
- case 434:
55513
+ case 433:
55904
55514
  // Trim the echoed row: drop `*DisplayTexts` mirrors, collapse localized objects to one language.
55905
55515
  trimEcho = function trimEcho(values) {
55906
55516
  var isLocalized = function isLocalized(v) {
@@ -55909,20 +55519,20 @@ function createNavigationToolset(ctx) {
55909
55519
  });
55910
55520
  };
55911
55521
  var out = {};
55912
- for (var _i8 = 0, _Object$entries3 = Object.entries(values); _i8 < _Object$entries3.length; _i8++) {
55522
+ for (var _i7 = 0, _Object$entries2 = Object.entries(values); _i7 < _Object$entries2.length; _i7++) {
55913
55523
  var _localized$DE;
55914
- var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i8], 2),
55915
- key = _Object$entries3$_i[0],
55916
- value = _Object$entries3$_i[1];
55524
+ var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i7], 2),
55525
+ key = _Object$entries2$_i[0],
55526
+ value = _Object$entries2$_i[1];
55917
55527
  if (/DisplayTexts?$/.test(key)) continue;
55918
55528
  var localized = value;
55919
55529
  out[key] = isLocalized(value) ? (_localized$DE = localized.DE) !== null && _localized$DE !== void 0 ? _localized$DE : Object.values(localized)[0] : value;
55920
55530
  }
55921
55531
  return out;
55922
55532
  }; // The commit REPORTS what the server confirmed; grid state cannot (a vanished rejected row gets no marker).
55923
- _context18.next = 437;
55533
+ _context18.next = 436;
55924
55534
  return handle.commitStagedChanges();
55925
- case 437:
55535
+ case 436:
55926
55536
  finalOutcome = _context18.sent;
55927
55537
  // Rows resolved by the sequential lookup pass above were already committed individually — merge
55928
55538
  // their outcomes in. When that pass never ran (the common case), this is exactly `finalOutcome`.
@@ -56037,8 +55647,8 @@ function createNavigationToolset(ctx) {
56037
55647
  } finally {
56038
55648
  _iterator20.f();
56039
55649
  }
56040
- for (_i9 = 0, _addedRows = addedRows; _i9 < _addedRows.length; _i9++) {
56041
- a = _addedRows[_i9];
55650
+ for (_i8 = 0, _addedRows = addedRows; _i8 < _addedRows.length; _i8++) {
55651
+ a = _addedRows[_i8];
56042
55652
  if ((_api2$getRowNode5 = _api2.getRowNode(a.rowId)) !== null && _api2$getRowNode5 !== void 0 && (_api2$getRowNode5 = _api2$getRowNode5.data) !== null && _api2$getRowNode5 !== void 0 && (_api2$getRowNode5 = _api2$getRowNode5.__diva_context) !== null && _api2$getRowNode5 !== void 0 && _api2$getRowNode5.isNew) {
56043
55653
  addError(a.rowId, ['Row was NOT saved — the commit skipped it (it stayed pending).']);
56044
55654
  }
@@ -56049,12 +55659,12 @@ function createNavigationToolset(ctx) {
56049
55659
  survivedAfterCommit = outcomeIsEmpty ? survivingOperations() : undefined;
56050
55660
  autoCommitted = !!survivedAfterCommit && survivedAfterCommit.changes.length + survivedAfterCommit.addedRowIds.length + survivedAfterCommit.removedRowIds.length > 0;
56051
55661
  if (!(outcomeIsEmpty && !autoCommitted && !serverErrors.length)) {
56052
- _context18.next = 461;
55662
+ _context18.next = 460;
56053
55663
  break;
56054
55664
  }
56055
- _context18.next = 459;
55665
+ _context18.next = 458;
56056
55666
  return handle.rollback();
56057
- case 459:
55667
+ case 458:
56058
55668
  restoreUserFilter();
56059
55669
  return _context18.abrupt("return", {
56060
55670
  applied: false,
@@ -56062,13 +55672,13 @@ function createNavigationToolset(ctx) {
56062
55672
  failed: failed.length ? summarizeFailures(failed) : undefined,
56063
55673
  note: 'NOTHING was saved: the commit reported no row as saved or rejected, and the grid holds none of the staged values any more ' + '(the table dropped the pending edits before they were sent). Do NOT report this as done — re-read the rows (readGridRows) and stage the batch again.'
56064
55674
  });
56065
- case 461:
55675
+ case 460:
56066
55676
  autoCommittedOps = autoCommitted ? survivedAfterCommit : undefined;
56067
55677
  committedIds = new Set(autoCommittedOps ? [].concat(_toConsumableArray(autoCommittedOps.changes.map(function (change) {
56068
55678
  return change.rowId;
56069
55679
  })), _toConsumableArray(autoCommittedOps.addedRowIds), _toConsumableArray(autoCommittedOps.removedRowIds)) : (_outcome$committed = outcome === null || outcome === void 0 ? void 0 : outcome.committed) !== null && _outcome$committed !== void 0 ? _outcome$committed : []);
56070
55680
  if (!serverErrors.length) {
56071
- _context18.next = 543;
55681
+ _context18.next = 542;
56072
55682
  break;
56073
55683
  }
56074
55684
  failedIds = new Set(serverErrors.map(function (s) {
@@ -56101,9 +55711,9 @@ function createNavigationToolset(ctx) {
56101
55711
  _id: removedRecordIds.get(rowId)
56102
55712
  };
56103
55713
  }); // Clear the rejected leftovers (they would block the next staging).
56104
- _context18.next = 470;
55714
+ _context18.next = 469;
56105
55715
  return handle.rollback();
56106
- case 470:
55716
+ case 469:
56107
55717
  restoreUserFilter();
56108
55718
  // Partial failure: neither the commit report nor the rollback is reliable — read the server back per operation.
56109
55719
  hasIdColumn = !!_api2.getColumnDef('_id'); // A COUNT budget bounded nothing: one probe can spend three 8s row-waits, so 25 of them ran for ten
@@ -56190,9 +55800,9 @@ function createNavigationToolset(ctx) {
56190
55800
  verifiedChanges = [];
56191
55801
  verifiedAdds = [];
56192
55802
  verifiedRemovals = [];
56193
- _context18.prev = 481;
55803
+ _context18.prev = 480;
56194
55804
  _iterator21 = _createForOfIteratorHelper$r(editTargets);
56195
- _context18.prev = 483;
55805
+ _context18.prev = 482;
56196
55806
  _loop5 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop5() {
56197
55807
  var _expectedValueOf, _target$from;
56198
55808
  var target, probe, serverValue, serverState;
@@ -56237,47 +55847,47 @@ function createNavigationToolset(ctx) {
56237
55847
  }, _loop5);
56238
55848
  });
56239
55849
  _iterator21.s();
56240
- case 486:
55850
+ case 485:
56241
55851
  if ((_step21 = _iterator21.n()).done) {
56242
- _context18.next = 492;
55852
+ _context18.next = 491;
56243
55853
  break;
56244
55854
  }
56245
- return _context18.delegateYield(_loop5(), "t12", 488);
56246
- case 488:
55855
+ return _context18.delegateYield(_loop5(), "t12", 487);
55856
+ case 487:
56247
55857
  if (!_context18.t12) {
56248
- _context18.next = 490;
55858
+ _context18.next = 489;
56249
55859
  break;
56250
55860
  }
56251
- return _context18.abrupt("continue", 490);
56252
- case 490:
56253
- _context18.next = 486;
55861
+ return _context18.abrupt("continue", 489);
55862
+ case 489:
55863
+ _context18.next = 485;
56254
55864
  break;
56255
- case 492:
56256
- _context18.next = 497;
55865
+ case 491:
55866
+ _context18.next = 496;
56257
55867
  break;
56258
- case 494:
56259
- _context18.prev = 494;
56260
- _context18.t13 = _context18["catch"](483);
55868
+ case 493:
55869
+ _context18.prev = 493;
55870
+ _context18.t13 = _context18["catch"](482);
56261
55871
  _iterator21.e(_context18.t13);
56262
- case 497:
56263
- _context18.prev = 497;
55872
+ case 496:
55873
+ _context18.prev = 496;
56264
55874
  _iterator21.f();
56265
- return _context18.finish(497);
56266
- case 500:
55875
+ return _context18.finish(496);
55876
+ case 499:
56267
55877
  _iterator22 = _createForOfIteratorHelper$r(addTargets);
56268
- _context18.prev = 501;
55878
+ _context18.prev = 500;
56269
55879
  _iterator22.s();
56270
- case 503:
55880
+ case 502:
56271
55881
  if ((_step22 = _iterator22.n()).done) {
56272
- _context18.next = 511;
55882
+ _context18.next = 510;
56273
55883
  break;
56274
55884
  }
56275
55885
  target = _step22.value;
56276
- _context18.next = 507;
55886
+ _context18.next = 506;
56277
55887
  return probeServerRow(target._id, function () {
56278
55888
  return true;
56279
55889
  });
56280
- case 507:
55890
+ case 506:
56281
55891
  probe = _context18.sent;
56282
55892
  verifiedAdds.push(_objectSpread$X(_objectSpread$X({
56283
55893
  rowId: target.rowId,
@@ -56287,60 +55897,60 @@ function createNavigationToolset(ctx) {
56287
55897
  } : {}), {}, {
56288
55898
  serverState: probe.state === 'found' ? 'applied' : probe.state === 'missing' ? 'reverted' : 'unknown'
56289
55899
  }));
56290
- case 509:
56291
- _context18.next = 503;
55900
+ case 508:
55901
+ _context18.next = 502;
56292
55902
  break;
56293
- case 511:
56294
- _context18.next = 516;
55903
+ case 510:
55904
+ _context18.next = 515;
56295
55905
  break;
56296
- case 513:
56297
- _context18.prev = 513;
56298
- _context18.t14 = _context18["catch"](501);
55906
+ case 512:
55907
+ _context18.prev = 512;
55908
+ _context18.t14 = _context18["catch"](500);
56299
55909
  _iterator22.e(_context18.t14);
56300
- case 516:
56301
- _context18.prev = 516;
55910
+ case 515:
55911
+ _context18.prev = 515;
56302
55912
  _iterator22.f();
56303
- return _context18.finish(516);
56304
- case 519:
55913
+ return _context18.finish(515);
55914
+ case 518:
56305
55915
  _iterator23 = _createForOfIteratorHelper$r(removalTargets);
56306
- _context18.prev = 520;
55916
+ _context18.prev = 519;
56307
55917
  _iterator23.s();
56308
- case 522:
55918
+ case 521:
56309
55919
  if ((_step23 = _iterator23.n()).done) {
56310
- _context18.next = 530;
55920
+ _context18.next = 529;
56311
55921
  break;
56312
55922
  }
56313
55923
  _target = _step23.value;
56314
- _context18.next = 526;
55924
+ _context18.next = 525;
56315
55925
  return probeServerRow(_target._id, function () {
56316
55926
  return true;
56317
55927
  });
56318
- case 526:
55928
+ case 525:
56319
55929
  _probe = _context18.sent;
56320
55930
  verifiedRemovals.push({
56321
55931
  rowId: _target.rowId,
56322
55932
  serverState: _probe.state === 'missing' ? 'applied' : _probe.state === 'found' ? 'reverted' : 'unknown'
56323
55933
  });
56324
- case 528:
56325
- _context18.next = 522;
55934
+ case 527:
55935
+ _context18.next = 521;
56326
55936
  break;
56327
- case 530:
56328
- _context18.next = 535;
55937
+ case 529:
55938
+ _context18.next = 534;
56329
55939
  break;
56330
- case 532:
56331
- _context18.prev = 532;
56332
- _context18.t15 = _context18["catch"](520);
55940
+ case 531:
55941
+ _context18.prev = 531;
55942
+ _context18.t15 = _context18["catch"](519);
56333
55943
  _iterator23.e(_context18.t15);
56334
- case 535:
56335
- _context18.prev = 535;
55944
+ case 534:
55945
+ _context18.prev = 534;
56336
55946
  _iterator23.f();
56337
- return _context18.finish(535);
56338
- case 538:
56339
- _context18.prev = 538;
55947
+ return _context18.finish(534);
55948
+ case 537:
55949
+ _context18.prev = 537;
56340
55950
  // The table belongs to the user again before we answer, whatever the probes did.
56341
55951
  restoreVerifyFilter();
56342
- return _context18.finish(538);
56343
- case 541:
55952
+ return _context18.finish(537);
55953
+ case 540:
56344
55954
  appliedCount = [].concat(verifiedChanges, verifiedAdds, verifiedRemovals).filter(function (v) {
56345
55955
  return v.serverState === 'applied';
56346
55956
  }).length;
@@ -56365,7 +55975,7 @@ function createNavigationToolset(ctx) {
56365
55975
  failed: failed.length ? summarizeFailures(failed) : undefined,
56366
55976
  note: 'The SERVER REJECTED the listed rows. Every other operation was READ BACK from the server — its `serverState` is the truth: ' + 'applied = the effect IS on the server (do NOT re-send it), reverted = re-send it after fixing the rejection cause, ' + 'unknown = verify with readGridRows/locateRow before re-sending. Never re-send an applied or unknown operation blindly — that is how silent duplicates happen.' + (verifyDeadlineHit ? ' The read-back ran out of time, so some `unknown`s mean UNCHECKED rather than unanswered — check those yourself before deciding.' : '') + parentBindingNote
56367
55977
  }));
56368
- case 543:
55978
+ case 542:
56369
55979
  // Return the real _id so references are not built from grid rowIds; catalogs/packages list rows are new EDITORS.
56370
55980
  livePath = (_root$navigationState3 = root.navigationState.path) !== null && _root$navigationState3 !== void 0 ? _root$navigationState3 : '';
56371
55981
  editorPathFor = function editorPathFor(id) {
@@ -56490,7 +56100,7 @@ function createNavigationToolset(ctx) {
56490
56100
  // The serie by NUMBER AND NAME, not by 24-hex id — the thing to check is whether this is serie 0.
56491
56101
  serieScope && (addedRows.length || staged.length || removed.length) ? " SERIE-SCOPED TABLE: these rows belong to ".concat(serieLabelOf(serieScope), " \u2014 the serie the VIEW's selector held, which AUTO-SELECTS THE FIRST serie when nobody chose one").concat(addedRows.length ? ', so a new row can land in the components serie without anyone deciding that' : '', ". CONFIRM it is the serie you meant before continuing.").concat(foreignSeries.length ? " MISMATCH: the saved record(s) report serieId ".concat(foreignSeries.join(', '), ", which is NOT this view's scope \u2014 read the rows back before doing anything else.") : '') : '') + (removed.length ? ' REMOVALS: inbound references are NOT cleaned up. Deleting an entity leaves dead pointers in decisions (featureRefs + condition columns), price feature groups + their finishes conditions, option-group membership, partlistpos.itemRefTypeNo, items.featureClassRefNo and items.partListRef, plus formula keys inside action strings — measured on all of these. Two of them make the planner THROW on init (a missing feature class, a missing formula). Only option keys inside decision condition/action cells are cleaned, and a deleted PRICE FEATURE GROUP is the one clean case (its matrix column goes with it). So after any delete, read the referrers yourself; nothing warns you. ' + 'lintCatalog finds most of them AFTER a reloadPlanner — but NOT a dead items.featureClassRefNo, because that article throws during init and never enters the snapshot it lints. For that one check the EDITOR: on the items view, readGridRows({grid:"items", columns:["typeNo","featureClassRefNo"]}) and compare against readColumnOptions({grid:"items", column:"featureClassRefNo"}), which lists the classes that still exist. Same approach for partlistpos.itemRefTypeNo against the items list.' : '') + ' Loaded planner instances still hold PRE-change data — reloadPlanner before verifying these changes in the planner.' + (stagingNotes.length ? " HOUSE-STYLE NOTES: ".concat(stagingNotes.join(' ')) : '')
56492
56102
  }));
56493
- case 557:
56103
+ case 556:
56494
56104
  // Thrown (not returned) so the refusal does NOT end the turn — the model tells the user to decide on the staged edits first.
56495
56105
  dirtyGrids = root.gridRegistry.entries.filter(function (entry) {
56496
56106
  var _entry$getHandle4;
@@ -56499,11 +56109,11 @@ function createNavigationToolset(ctx) {
56499
56109
  return entry.label;
56500
56110
  });
56501
56111
  if (!dirtyGrids.length) {
56502
- _context18.next = 560;
56112
+ _context18.next = 559;
56503
56113
  break;
56504
56114
  }
56505
56115
  throw new Error("Page reload refused: table(s) ".concat(dirtyGrids.join(', '), " still carry staged, unapproved edits that a reload would silently drop. Ask the user to \xDCbernehmen or Verwerfen them first, then call reloadPage again."));
56506
- case 560:
56116
+ case 559:
56507
56117
  // Deferred so the tool result reaches the chat and the turn is persisted (the stored endedByTool record is what
56508
56118
  // triggers the automatic 'Continue.' after the reload) before the document unloads.
56509
56119
  setTimeout(function () {
@@ -56515,29 +56125,29 @@ function createNavigationToolset(ctx) {
56515
56125
  pageReload: true,
56516
56126
  note: "Full page reload triggered — this turn ends here. The chat reopens on this conversation and an automatic 'Continue.' follows once the view is ready (if the agent panel is not open after the reload, it fires when the user opens it). Every planner instance is rebuilt from a FRESH article payload, so decisionRefs and media changes are now in effect — verify with listDecisions / getMediaInfo, do not assume."
56517
56127
  });
56518
- case 562:
56128
+ case 561:
56519
56129
  _livePath = (_root$navigationState4 = root.navigationState.path) !== null && _root$navigationState4 !== void 0 ? _root$navigationState4 : '';
56520
56130
  packageBase = (_livePath$match = _livePath.match(/catalogs\/idmeditor\/packages\/([^/]+)/)) === null || _livePath$match === void 0 ? void 0 : _livePath$match[1];
56521
56131
  catalogBase = (_livePath$match2 = _livePath.match(/catalogs\/idmeditor\/catalogs\/([^/]+)/)) === null || _livePath$match2 === void 0 ? void 0 : _livePath$match2[1];
56522
56132
  baseId = (_ref44 = (_ref45 = packageBase !== null && packageBase !== void 0 ? packageBase : catalogBase) !== null && _ref45 !== void 0 ? _ref45 : ctx.packageId) !== null && _ref44 !== void 0 ? _ref44 : ctx.catalogId;
56523
56133
  if (baseId) {
56524
- _context18.next = 568;
56134
+ _context18.next = 567;
56525
56135
  break;
56526
56136
  }
56527
56137
  return _context18.abrupt("return", {
56528
56138
  error: 'No catalog/package context — nothing to reload.'
56529
56139
  });
56530
- case 568:
56140
+ case 567:
56531
56141
  // Package views load the ENRICHER pack, catalog views the raw IDM catalog.
56532
56142
  isPack = baseId === packageBase || !packageBase && !catalogBase && baseId === ctx.packageId;
56533
56143
  _root$webplannerInsta = root.webplannerInstanceStore.invalidateByBase(baseId), destroyed = _root$webplannerInsta.destroyed, reloadTriggered = _root$webplannerInsta.reloadTriggered, knownKeys = _root$webplannerInsta.knownKeys;
56534
56144
  source = isPack ? "PACKAGE ".concat(baseId, " (enricher pack: pricelist factors and manual prices APPLY)") : "CATALOG ".concat(baseId, " (raw IDM catalog: enricher pricelists do NOT apply \u2014 to verify pack prices, navigateTo the package view first, then reloadPlanner there)"); // A base matching no instance key invalidates nothing — report that instead of claiming the discard happened.
56535
56145
  if (!(!destroyed && !reloadTriggered)) {
56536
- _context18.next = 575;
56146
+ _context18.next = 574;
56537
56147
  break;
56538
56148
  }
56539
56149
  if (knownKeys.length) {
56540
- _context18.next = 574;
56150
+ _context18.next = 573;
56541
56151
  break;
56542
56152
  }
56543
56153
  return _context18.abrupt("return", {
@@ -56547,7 +56157,7 @@ function createNavigationToolset(ctx) {
56547
56157
  environmentUnchanged: true,
56548
56158
  note: "NOTHING TO RELOAD \u2014 no planner instance is loaded for ".concat(baseId, ", so there was no stale snapshot to discard. The next planner use loads CURRENT data from ").concat(source, ".")
56549
56159
  });
56550
- case 574:
56160
+ case 573:
56551
56161
  return _context18.abrupt("return", {
56552
56162
  ok: false,
56553
56163
  destroyed: destroyed,
@@ -56556,32 +56166,32 @@ function createNavigationToolset(ctx) {
56556
56166
  knownKeys: knownKeys,
56557
56167
  error: "Nothing was invalidated: no loaded planner belongs to '".concat(baseId, "'. Loaded instance keys are [").concat(knownKeys.join(', '), "] ") + "(key = catalogId|serieNo|itemTypeNo|language). A key whose first segment is EMPTY or differs from '".concat(baseId, "' means the ") + "configurator was mounted without the catalog binding \u2014 reload the page to re-bind, then reloadPlanner again. Do NOT treat " + "planner reads as current until this succeeds."
56558
56168
  });
56559
- case 575:
56169
+ case 574:
56560
56170
  return _context18.abrupt("return", {
56561
56171
  ok: true,
56562
56172
  destroyed: destroyed,
56563
56173
  reloadTriggered: reloadTriggered,
56564
56174
  note: "Planner instances were discarded \u2014 the next planner use loads CURRENT data from ".concat(source) + (reloadTriggered ? ' (the open configurator reloads itself, and its stale instance is destroyed rather than re-adopted)' : '') + ". The turn ends here; an automatic 'Continue.' follows."
56565
56175
  });
56566
- case 576:
56176
+ case 575:
56567
56177
  _resolveGrid4 = resolveGrid(args.grid), _entry3 = _resolveGrid4.entry, _error3 = _resolveGrid4.error;
56568
56178
  if (!(_error3 || !_entry3)) {
56569
- _context18.next = 579;
56179
+ _context18.next = 578;
56570
56180
  break;
56571
56181
  }
56572
56182
  return _context18.abrupt("return", {
56573
56183
  error: _error3
56574
56184
  });
56575
- case 579:
56185
+ case 578:
56576
56186
  _handle = _entry3.getHandle();
56577
56187
  if (_handle) {
56578
- _context18.next = 582;
56188
+ _context18.next = 581;
56579
56189
  break;
56580
56190
  }
56581
56191
  return _context18.abrupt("return", {
56582
56192
  error: "Table '".concat(_entry3.label, "' is not ready.")
56583
56193
  });
56584
- case 582:
56194
+ case 581:
56585
56195
  actionName = String((_action = input === null || input === void 0 ? void 0 : input.action) !== null && _action !== void 0 ? _action : '');
56586
56196
  actionInput = String((_input = input === null || input === void 0 ? void 0 : input.input) !== null && _input !== void 0 ? _input : '').trim();
56587
56197
  _addTargets = _handle.getDivaColumnDefs().filter(isHeaderAddColumn);
@@ -56593,13 +56203,13 @@ function createNavigationToolset(ctx) {
56593
56203
  return action.name;
56594
56204
  })));
56595
56205
  if (available.includes(actionName)) {
56596
- _context18.next = 590;
56206
+ _context18.next = 589;
56597
56207
  break;
56598
56208
  }
56599
56209
  return _context18.abrupt("return", {
56600
56210
  error: "Action '".concat(actionName, "' is not available on '").concat(_entry3.label, "' \u2014 this table has: ").concat(available.join(', ') || 'no actions', " (listGrids shows each table's actions).")
56601
56211
  });
56602
- case 590:
56212
+ case 589:
56603
56213
  approve = /*#__PURE__*/function () {
56604
56214
  var _ref46 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee8(label) {
56605
56215
  return _regeneratorRuntime.wrap(function _callee8$(_context13) {
@@ -56707,336 +56317,336 @@ function createNavigationToolset(ctx) {
56707
56317
  return action.name === actionName;
56708
56318
  });
56709
56319
  if (!viewAction) {
56710
- _context18.next = 618;
56320
+ _context18.next = 617;
56711
56321
  break;
56712
56322
  }
56713
56323
  mutating = viewAction.mutating !== false;
56714
56324
  _context18.t16 = mutating;
56715
56325
  if (!_context18.t16) {
56716
- _context18.next = 604;
56326
+ _context18.next = 603;
56717
56327
  break;
56718
56328
  }
56719
- _context18.next = 603;
56329
+ _context18.next = 602;
56720
56330
  return approve("".concat(actionName, ": ").concat(actionInput || '(no input)'));
56721
- case 603:
56331
+ case 602:
56722
56332
  _context18.t16 = !_context18.sent;
56723
- case 604:
56333
+ case 603:
56724
56334
  if (!_context18.t16) {
56725
- _context18.next = 606;
56335
+ _context18.next = 605;
56726
56336
  break;
56727
56337
  }
56728
56338
  return _context18.abrupt("return", declined);
56729
- case 606:
56730
- _context18.prev = 606;
56339
+ case 605:
56340
+ _context18.prev = 605;
56731
56341
  _context18.t17 = "";
56732
- _context18.next = 610;
56342
+ _context18.next = 609;
56733
56343
  return viewAction.run(actionInput);
56734
- case 610:
56344
+ case 609:
56735
56345
  _context18.t18 = _context18.sent;
56736
56346
  _context18.t19 = _context18.t17.concat.call(_context18.t17, _context18.t18).concat(mutating ? autoNote : '');
56737
56347
  return _context18.abrupt("return", {
56738
56348
  applied: true,
56739
56349
  note: _context18.t19
56740
56350
  });
56741
- case 615:
56742
- _context18.prev = 615;
56743
- _context18.t20 = _context18["catch"](606);
56351
+ case 614:
56352
+ _context18.prev = 614;
56353
+ _context18.t20 = _context18["catch"](605);
56744
56354
  return _context18.abrupt("return", {
56745
56355
  error: _context18.t20 instanceof Error ? _context18.t20.message : String(_context18.t20)
56746
56356
  });
56747
- case 618:
56357
+ case 617:
56748
56358
  if (!(actionName === 'cloneCatalog')) {
56749
- _context18.next = 637;
56359
+ _context18.next = 636;
56750
56360
  break;
56751
56361
  }
56752
56362
  if (isRecordId(actionInput)) {
56753
- _context18.next = 621;
56363
+ _context18.next = 620;
56754
56364
  break;
56755
56365
  }
56756
56366
  return _context18.abrupt("return", {
56757
56367
  error: "input must be the catalog's _id (24-hex) — read it from the _id column (readGridRows)."
56758
56368
  });
56759
- case 621:
56760
- _context18.next = 623;
56369
+ case 620:
56370
+ _context18.next = 622;
56761
56371
  return approve("cloneCatalog: ".concat(actionInput));
56762
- case 623:
56372
+ case 622:
56763
56373
  if (_context18.sent) {
56764
- _context18.next = 625;
56374
+ _context18.next = 624;
56765
56375
  break;
56766
56376
  }
56767
56377
  return _context18.abrupt("return", declined);
56768
- case 625:
56769
- _context18.prev = 625;
56770
- _context18.next = 628;
56378
+ case 624:
56379
+ _context18.prev = 624;
56380
+ _context18.next = 627;
56771
56381
  return authorizedFetch("".concat(root.configurationStore.apiConfig.idmService, "/catalogs/").concat(actionInput, "/clone"), 'POST', '{}');
56772
- case 628:
56773
- _context18.next = 633;
56382
+ case 627:
56383
+ _context18.next = 632;
56774
56384
  break;
56775
- case 630:
56776
- _context18.prev = 630;
56777
- _context18.t21 = _context18["catch"](625);
56385
+ case 629:
56386
+ _context18.prev = 629;
56387
+ _context18.t21 = _context18["catch"](624);
56778
56388
  return _context18.abrupt("return", {
56779
56389
  error: _context18.t21 instanceof Error ? _context18.t21.message : String(_context18.t21)
56780
56390
  });
56781
- case 633:
56782
- _context18.next = 635;
56391
+ case 632:
56392
+ _context18.next = 634;
56783
56393
  return refreshAndSettle();
56784
- case 635:
56394
+ case 634:
56785
56395
  cloneSettled = _context18.sent;
56786
56396
  return _context18.abrupt("return", {
56787
56397
  applied: true,
56788
56398
  note: "Catalog cloned server-side \u2014 the table refreshes; the copy appears as a new row (readGridRows to find it and REPORT its name + _id).".concat(autoNote).concat(cloneSettled ? '' : unsettledNote)
56789
56399
  });
56790
- case 637:
56400
+ case 636:
56791
56401
  if (!(actionName === 'importGlobalFeatures')) {
56792
- _context18.next = 657;
56402
+ _context18.next = 656;
56793
56403
  break;
56794
56404
  }
56795
56405
  catalogId = String((_catalogId = ((_handle$getApplicatio7 = (_handle$getApplicatio8 = _handle.getApplicationData) === null || _handle$getApplicatio8 === void 0 ? void 0 : _handle$getApplicatio8.call(_handle)) !== null && _handle$getApplicatio7 !== void 0 ? _handle$getApplicatio7 : {}).catalogId) !== null && _catalogId !== void 0 ? _catalogId : '');
56796
56406
  if (catalogId) {
56797
- _context18.next = 641;
56407
+ _context18.next = 640;
56798
56408
  break;
56799
56409
  }
56800
56410
  return _context18.abrupt("return", {
56801
56411
  error: 'No catalog context on this table.'
56802
56412
  });
56803
- case 641:
56804
- _context18.next = 643;
56413
+ case 640:
56414
+ _context18.next = 642;
56805
56415
  return approve('importGlobalFeatures');
56806
- case 643:
56416
+ case 642:
56807
56417
  if (_context18.sent) {
56808
- _context18.next = 645;
56418
+ _context18.next = 644;
56809
56419
  break;
56810
56420
  }
56811
56421
  return _context18.abrupt("return", declined);
56812
- case 645:
56813
- _context18.prev = 645;
56814
- _context18.next = 648;
56422
+ case 644:
56423
+ _context18.prev = 644;
56424
+ _context18.next = 647;
56815
56425
  return authorizedFetch("".concat(root.configurationStore.apiConfig.idmService, "/catalogs/").concat(catalogId, "/features/global"), 'POST');
56816
- case 648:
56817
- _context18.next = 653;
56426
+ case 647:
56427
+ _context18.next = 652;
56818
56428
  break;
56819
- case 650:
56820
- _context18.prev = 650;
56821
- _context18.t22 = _context18["catch"](645);
56429
+ case 649:
56430
+ _context18.prev = 649;
56431
+ _context18.t22 = _context18["catch"](644);
56822
56432
  return _context18.abrupt("return", {
56823
56433
  error: _context18.t22 instanceof Error ? _context18.t22.message : String(_context18.t22)
56824
56434
  });
56825
- case 653:
56826
- _context18.next = 655;
56435
+ case 652:
56436
+ _context18.next = 654;
56827
56437
  return refreshAndSettle();
56828
- case 655:
56438
+ case 654:
56829
56439
  importSettled = _context18.sent;
56830
56440
  return _context18.abrupt("return", {
56831
56441
  applied: true,
56832
56442
  note: "Global features imported \u2014 the table refreshes with the added feature rows.".concat(autoNote).concat(importSettled ? '' : unsettledNote)
56833
56443
  });
56834
- case 657:
56444
+ case 656:
56835
56445
  if (!(actionName === 'setPriceFactor' || actionName === 'setPriceFactorPriority')) {
56836
- _context18.next = 718;
56446
+ _context18.next = 717;
56837
56447
  break;
56838
56448
  }
56839
56449
  app = (_handle$getApplicatio9 = (_handle$getApplicatio10 = _handle.getApplicationData) === null || _handle$getApplicatio10 === void 0 ? void 0 : _handle$getApplicatio10.call(_handle)) !== null && _handle$getApplicatio9 !== void 0 ? _handle$getApplicatio9 : {};
56840
56450
  serieNo = Number(app.serieNo);
56841
- _context18.prev = 660;
56451
+ _context18.prev = 659;
56842
56452
  _params2 = JSON.parse(actionInput || '{}');
56843
- _context18.next = 667;
56453
+ _context18.next = 666;
56844
56454
  break;
56845
- case 664:
56846
- _context18.prev = 664;
56847
- _context18.t23 = _context18["catch"](660);
56455
+ case 663:
56456
+ _context18.prev = 663;
56457
+ _context18.t23 = _context18["catch"](659);
56848
56458
  return _context18.abrupt("return", {
56849
56459
  error: "input must be a JSON object — listGrids shows this action's exact shape."
56850
56460
  });
56851
- case 667:
56461
+ case 666:
56852
56462
  scope = String((_params2$scope = _params2.scope) !== null && _params2$scope !== void 0 ? _params2$scope : '');
56853
56463
  if (scope in PRICE_FACTOR_FIELDS) {
56854
- _context18.next = 670;
56464
+ _context18.next = 669;
56855
56465
  break;
56856
56466
  }
56857
56467
  return _context18.abrupt("return", {
56858
56468
  error: "scope must be one of: ".concat(Object.keys(PRICE_FACTOR_FIELDS).join(', '), ".")
56859
56469
  });
56860
- case 670:
56470
+ case 669:
56861
56471
  key = _params2.key === undefined ? undefined : String(_params2.key); // The factor maps live on the PRICELIST record — the write goes through the parent pricelists grid row.
56862
56472
  parent = resolveGrid('pricelists');
56863
56473
  if (!(parent.error || !parent.entry || !parent.api)) {
56864
- _context18.next = 674;
56474
+ _context18.next = 673;
56865
56475
  break;
56866
56476
  }
56867
56477
  return _context18.abrupt("return", {
56868
56478
  error: "The parent 'pricelists' table must be on screen for factor actions."
56869
56479
  });
56870
- case 674:
56480
+ case 673:
56871
56481
  parentHandle = parent.entry.getHandle();
56872
56482
  if (parentHandle) {
56873
- _context18.next = 677;
56483
+ _context18.next = 676;
56874
56484
  break;
56875
56485
  }
56876
56486
  return _context18.abrupt("return", {
56877
56487
  error: "Table 'pricelists' is not ready."
56878
56488
  });
56879
- case 677:
56489
+ case 676:
56880
56490
  parent.api.forEachNode(function (node) {
56881
56491
  var _node$data4;
56882
56492
  if (((_node$data4 = node.data) === null || _node$data4 === void 0 ? void 0 : _node$data4._id) === app.pricelistId) pricelistNode = node;
56883
56493
  });
56884
56494
  if ((_pricelistNode = pricelistNode) !== null && _pricelistNode !== void 0 && _pricelistNode.id) {
56885
- _context18.next = 680;
56495
+ _context18.next = 679;
56886
56496
  break;
56887
56497
  }
56888
56498
  return _context18.abrupt("return", {
56889
56499
  error: "Pricelist ".concat(app.pricelistId, " is not loaded in the 'pricelists' table.")
56890
56500
  });
56891
- case 680:
56892
- _context18.prev = 680;
56501
+ case 679:
56502
+ _context18.prev = 679;
56893
56503
  if (!(actionName === 'setPriceFactor')) {
56894
- _context18.next = 689;
56504
+ _context18.next = 688;
56895
56505
  break;
56896
56506
  }
56897
56507
  factors = _params2.factors;
56898
56508
  if (!(!Array.isArray(factors) || factors.some(function (f) {
56899
56509
  return typeof f !== 'number' || !Number.isFinite(f) || f <= 0;
56900
56510
  }))) {
56901
- _context18.next = 685;
56511
+ _context18.next = 684;
56902
56512
  break;
56903
56513
  }
56904
56514
  return _context18.abrupt("return", {
56905
56515
  error: 'factors must be an array of positive numbers (>1 = factor, <1 = discount fraction, e.g. 0.95 = 5% off); [] clears the entry.'
56906
56516
  });
56907
- case 685:
56517
+ case 684:
56908
56518
  patch = applyPriceFactor(pricelistNode.data, serieNo, scope, key, factors);
56909
56519
  label = "setPriceFactor ".concat(scope).concat(key ? " ".concat(key) : '', " \u2192 [").concat(factors.join('; '), "] (Serie ").concat(serieNo, ")");
56910
- _context18.next = 695;
56520
+ _context18.next = 694;
56911
56521
  break;
56912
- case 689:
56522
+ case 688:
56913
56523
  if (!(typeof _params2.priority !== 'boolean')) {
56914
- _context18.next = 691;
56524
+ _context18.next = 690;
56915
56525
  break;
56916
56526
  }
56917
56527
  return _context18.abrupt("return", {
56918
56528
  error: 'priority must be true or false.'
56919
56529
  });
56920
- case 691:
56530
+ case 690:
56921
56531
  if (key) {
56922
- _context18.next = 693;
56532
+ _context18.next = 692;
56923
56533
  break;
56924
56534
  }
56925
56535
  return _context18.abrupt("return", {
56926
56536
  error: 'key is required (the pfg id / price group).'
56927
56537
  });
56928
- case 693:
56538
+ case 692:
56929
56539
  patch = applyPriceFactorPriority(pricelistNode.data, serieNo, scope, key, _params2.priority);
56930
56540
  label = "setPriceFactorPriority ".concat(scope, " ").concat(key, " \u2192 ").concat(_params2.priority, " (Serie ").concat(serieNo, ")");
56931
- case 695:
56932
- _context18.next = 700;
56541
+ case 694:
56542
+ _context18.next = 699;
56933
56543
  break;
56934
- case 697:
56935
- _context18.prev = 697;
56936
- _context18.t24 = _context18["catch"](680);
56544
+ case 696:
56545
+ _context18.prev = 696;
56546
+ _context18.t24 = _context18["catch"](679);
56937
56547
  return _context18.abrupt("return", {
56938
56548
  error: _context18.t24 instanceof Error ? _context18.t24.message : String(_context18.t24)
56939
56549
  });
56940
- case 700:
56941
- _context18.next = 702;
56550
+ case 699:
56551
+ _context18.next = 701;
56942
56552
  return approve(label);
56943
- case 702:
56553
+ case 701:
56944
56554
  if (_context18.sent) {
56945
- _context18.next = 704;
56555
+ _context18.next = 703;
56946
56556
  break;
56947
56557
  }
56948
56558
  return _context18.abrupt("return", declined);
56949
- case 704:
56559
+ case 703:
56950
56560
  pricelistRowId = pricelistNode.id;
56951
- _context18.next = 707;
56561
+ _context18.next = 706;
56952
56562
  return parentHandle.setNodeDataValue(pricelistRowId, patch, {
56953
56563
  suppressAutoCommit: true
56954
56564
  });
56955
- case 707:
56565
+ case 706:
56956
56566
  if (_context18.sent) {
56957
- _context18.next = 709;
56567
+ _context18.next = 708;
56958
56568
  break;
56959
56569
  }
56960
56570
  return _context18.abrupt("return", {
56961
56571
  error: 'The pricelist row rejected the update.'
56962
56572
  });
56963
- case 709:
56964
- _context18.next = 711;
56573
+ case 708:
56574
+ _context18.next = 710;
56965
56575
  return parentHandle.commitStagedChanges();
56966
- case 711:
56576
+ case 710:
56967
56577
  factorOutcome = _context18.sent;
56968
56578
  rejected = factorOutcome === null || factorOutcome === void 0 ? void 0 : factorOutcome.failed.find(function (failure) {
56969
56579
  return failure.rowId === pricelistRowId;
56970
56580
  });
56971
56581
  if (!rejected) {
56972
- _context18.next = 715;
56582
+ _context18.next = 714;
56973
56583
  break;
56974
56584
  }
56975
56585
  return _context18.abrupt("return", {
56976
56586
  error: "The server rejected the factor update: ".concat(rejected.errors.join(' ') || 'no reason given', ". Nothing was changed.")
56977
56587
  });
56978
- case 715:
56588
+ case 714:
56979
56589
  if (!(factorOutcome && !factorOutcome.committed.includes(pricelistRowId))) {
56980
- _context18.next = 717;
56590
+ _context18.next = 716;
56981
56591
  break;
56982
56592
  }
56983
56593
  return _context18.abrupt("return", {
56984
56594
  error: 'The factor update was NOT saved — the commit did not confirm the pricelist row. Re-read the pricelist (readGridRows) before retrying.'
56985
56595
  });
56986
- case 717:
56596
+ case 716:
56987
56597
  return _context18.abrupt("return", {
56988
56598
  applied: true,
56989
56599
  note: "Saved on the pricelist record and confirmed by the server (same path as the factor modal) \u2014 the prices table reflects it immediately.".concat(autoNote)
56990
56600
  });
56991
- case 718:
56601
+ case 717:
56992
56602
  if (!(actionName === 'deleteAllManualPrices')) {
56993
- _context18.next = 736;
56603
+ _context18.next = 735;
56994
56604
  break;
56995
56605
  }
56996
56606
  _app = (_handle$getApplicatio11 = (_handle$getApplicatio12 = _handle.getApplicationData) === null || _handle$getApplicatio12 === void 0 ? void 0 : _handle$getApplicatio12.call(_handle)) !== null && _handle$getApplicatio11 !== void 0 ? _handle$getApplicatio11 : {};
56997
- _context18.next = 722;
56607
+ _context18.next = 721;
56998
56608
  return approve("deleteAllManualPrices (Pricelist ".concat(_app.pricelistId, ", Serie ").concat(_app.serieNo, ")"));
56999
- case 722:
56609
+ case 721:
57000
56610
  if (_context18.sent) {
57001
- _context18.next = 724;
56611
+ _context18.next = 723;
57002
56612
  break;
57003
56613
  }
57004
56614
  return _context18.abrupt("return", declined);
57005
- case 724:
57006
- _context18.prev = 724;
57007
- _context18.next = 727;
56615
+ case 723:
56616
+ _context18.prev = 723;
56617
+ _context18.next = 726;
57008
56618
  return authorizedFetch("".concat(root.configurationStore.apiConfig.enricherService, "/packages/").concat(_app.packageId, "/pricelists/").concat(_app.pricelistId, "/serie/").concat(_app.serieNo, "/prices/manual"), 'DELETE');
57009
- case 727:
57010
- _context18.next = 732;
56619
+ case 726:
56620
+ _context18.next = 731;
57011
56621
  break;
57012
- case 729:
57013
- _context18.prev = 729;
57014
- _context18.t25 = _context18["catch"](724);
56622
+ case 728:
56623
+ _context18.prev = 728;
56624
+ _context18.t25 = _context18["catch"](723);
57015
56625
  return _context18.abrupt("return", {
57016
56626
  error: _context18.t25 instanceof Error ? _context18.t25.message : String(_context18.t25)
57017
56627
  });
57018
- case 732:
57019
- _context18.next = 734;
56628
+ case 731:
56629
+ _context18.next = 733;
57020
56630
  return refreshAndSettle();
57021
- case 734:
56631
+ case 733:
57022
56632
  pricesSettled = _context18.sent;
57023
56633
  return _context18.abrupt("return", {
57024
56634
  applied: true,
57025
56635
  note: "All manual price overrides of this pricelist+serie were deleted (irreversible) \u2014 the table refreshed; origPrices and factors now determine every cell.".concat(autoNote).concat(pricesSettled ? '' : unsettledNote)
57026
56636
  });
57027
- case 736:
56637
+ case 735:
57028
56638
  if (!(actionName === 'removeColumn')) {
57029
- _context18.next = 775;
56639
+ _context18.next = 774;
57030
56640
  break;
57031
56641
  }
57032
56642
  if (actionInput) {
57033
- _context18.next = 739;
56643
+ _context18.next = 738;
57034
56644
  break;
57035
56645
  }
57036
56646
  return _context18.abrupt("return", {
57037
56647
  error: "Provide input: the column to remove — its field id ('optionsSetRefs.2305') or the bare key ('2305'); listGrids shows the columns."
57038
56648
  });
57039
- case 739:
56649
+ case 738:
57040
56650
  removeTargetIn = function removeTargetIn(defs) {
57041
56651
  return defs.find(function (def) {
57042
56652
  return def.field === actionInput || def.colId === actionInput || String(def.field).endsWith(".".concat(actionInput));
@@ -57044,7 +56654,7 @@ function createNavigationToolset(ctx) {
57044
56654
  };
57045
56655
  _target4 = removeTargetIn(removeTargets);
57046
56656
  if (_target4) {
57047
- _context18.next = 743;
56657
+ _context18.next = 742;
57048
56658
  break;
57049
56659
  }
57050
56660
  return _context18.abrupt("return", {
@@ -57052,75 +56662,75 @@ function createNavigationToolset(ctx) {
57052
56662
  return "'".concat(def.field, "'");
57053
56663
  }).join(', ') || 'none', ".")
57054
56664
  });
57055
- case 743:
56665
+ case 742:
57056
56666
  _header = typeof _target4.headerName === 'string' ? root.t(_target4.headerName) : String(_target4.field);
57057
- _context18.next = 746;
56667
+ _context18.next = 745;
57058
56668
  return approve("removeColumn: ".concat(_header));
57059
- case 746:
56669
+ case 745:
57060
56670
  if (_context18.sent) {
57061
- _context18.next = 748;
56671
+ _context18.next = 747;
57062
56672
  break;
57063
56673
  }
57064
56674
  return _context18.abrupt("return", declined);
57065
- case 748:
56675
+ case 747:
57066
56676
  // The defs are rebuilt on every render, each onRemove closing over the feature list of ITS render — the
57067
56677
  // pre-wait closure would drop a feature the user added while the bar was open. Re-resolve after the wait.
57068
56678
  live = removeTargetIn(_handle.getDivaColumnDefs().filter(isRemovableColumn));
57069
56679
  if (live) {
57070
- _context18.next = 751;
56680
+ _context18.next = 750;
57071
56681
  break;
57072
56682
  }
57073
56683
  return _context18.abrupt("return", {
57074
56684
  applied: false,
57075
56685
  note: "'".concat(_target4.field, "' left the table while the approval was pending \u2014 nothing was removed. listGrids shows the current columns.")
57076
56686
  });
57077
- case 751:
57078
- _context18.prev = 751;
57079
- _context18.next = 754;
56687
+ case 750:
56688
+ _context18.prev = 750;
56689
+ _context18.next = 753;
57080
56690
  return live.headerComponentParams.onRemove();
57081
- case 754:
56691
+ case 753:
57082
56692
  saved = _context18.sent;
57083
- _context18.next = 760;
56693
+ _context18.next = 759;
57084
56694
  break;
57085
- case 757:
57086
- _context18.prev = 757;
57087
- _context18.t26 = _context18["catch"](751);
56695
+ case 756:
56696
+ _context18.prev = 756;
56697
+ _context18.t26 = _context18["catch"](750);
57088
56698
  return _context18.abrupt("return", {
57089
56699
  error: _context18.t26 instanceof Error ? _context18.t26.message : String(_context18.t26)
57090
56700
  });
57091
- case 760:
56701
+ case 759:
57092
56702
  if (!(saved === false)) {
57093
- _context18.next = 762;
56703
+ _context18.next = 761;
57094
56704
  break;
57095
56705
  }
57096
56706
  return _context18.abrupt("return", {
57097
56707
  applied: false,
57098
56708
  note: "The parent row did not take the new feature list \u2014 '".concat(_target4.field, "' was NOT removed. locateRow the parent row again so the view reloads, then retry.")
57099
56709
  });
57100
- case 762:
56710
+ case 761:
57101
56711
  // Poll until the column left the view — the parent entity's write and the rebuild are asynchronous.
57102
56712
  gone = false;
57103
56713
  attempt = 0;
57104
- case 764:
56714
+ case 763:
57105
56715
  if (!(attempt < 20 && !gone)) {
57106
- _context18.next = 771;
56716
+ _context18.next = 770;
57107
56717
  break;
57108
56718
  }
57109
- _context18.next = 767;
56719
+ _context18.next = 766;
57110
56720
  return sleep(100);
57111
- case 767:
56721
+ case 766:
57112
56722
  gone = !_handle.getDivaColumnDefs().some(function (def) {
57113
56723
  return def.field === _target4.field;
57114
56724
  });
57115
- case 768:
56725
+ case 767:
57116
56726
  attempt++;
57117
- _context18.next = 764;
56727
+ _context18.next = 763;
57118
56728
  break;
57119
- case 771:
56729
+ case 770:
57120
56730
  // The view declares what becomes of the rows' cells of a removed feature column.
57121
56731
  rowsNote = _target4.headerComponentParams.removeKeepsCells ? ' The rows KEEP their cells for that feature (hidden now, still exported) — re-add the column to see or clear them.' : " The server also strips that feature's cells from every row of this table.";
57122
56732
  if (gone) {
57123
- _context18.next = 774;
56733
+ _context18.next = 773;
57124
56734
  break;
57125
56735
  }
57126
56736
  return _context18.abrupt("return", {
@@ -57132,7 +56742,7 @@ function createNavigationToolset(ctx) {
57132
56742
  viewNotRebuilt: true,
57133
56743
  note: "The parent row took the new feature list, but '".concat(_target4.field, "' is still in the view after the wait \u2014 the rebuild is pending. Re-read the columns (listGrids) before touching this table again; do NOT retry the removal.") + rowsNote + autoNote
57134
56744
  });
57135
- case 774:
56745
+ case 773:
57136
56746
  return _context18.abrupt("return", {
57137
56747
  applied: true,
57138
56748
  removed: {
@@ -57141,24 +56751,24 @@ function createNavigationToolset(ctx) {
57141
56751
  },
57142
56752
  note: 'Column removed.' + rowsNote + autoNote
57143
56753
  });
57144
- case 775:
56754
+ case 774:
57145
56755
  // addColumn: one approval, sequential adds — parallel adds race the view rebuild.
57146
56756
  _target5 = _addTargets[0];
57147
56757
  if (actionInput) {
57148
- _context18.next = 778;
56758
+ _context18.next = 777;
57149
56759
  break;
57150
56760
  }
57151
56761
  return _context18.abrupt("return", {
57152
56762
  error: "Provide input: the key(s) to add, comma-separated \u2014 readColumnOptions('".concat(_target5.field, "') lists the addable entries.")
57153
56763
  });
57154
- case 778:
56764
+ case 777:
57155
56765
  keys = actionInput.split(',').map(function (k) {
57156
56766
  return k.trim();
57157
56767
  }).filter(Boolean); // Resolve ALL keys BEFORE asking approval: the bar shows the real labels, invalid keys fail fast.
57158
56768
  resolved = [];
57159
- _context18.prev = 780;
56769
+ _context18.prev = 779;
57160
56770
  _iterator26 = _createForOfIteratorHelper$r(keys);
57161
- _context18.prev = 782;
56771
+ _context18.prev = 781;
57162
56772
  _loop8 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop8() {
57163
56773
  var key, options, option;
57164
56774
  return _regeneratorRuntime.wrap(function _loop8$(_context16) {
@@ -57193,63 +56803,63 @@ function createNavigationToolset(ctx) {
57193
56803
  }, _loop8);
57194
56804
  });
57195
56805
  _iterator26.s();
57196
- case 785:
56806
+ case 784:
57197
56807
  if ((_step26 = _iterator26.n()).done) {
57198
- _context18.next = 792;
56808
+ _context18.next = 791;
57199
56809
  break;
57200
56810
  }
57201
- return _context18.delegateYield(_loop8(), "t27", 787);
57202
- case 787:
56811
+ return _context18.delegateYield(_loop8(), "t27", 786);
56812
+ case 786:
57203
56813
  _ret6 = _context18.t27;
57204
56814
  if (!_ret6) {
57205
- _context18.next = 790;
56815
+ _context18.next = 789;
57206
56816
  break;
57207
56817
  }
57208
56818
  return _context18.abrupt("return", _ret6.v);
57209
- case 790:
57210
- _context18.next = 785;
56819
+ case 789:
56820
+ _context18.next = 784;
57211
56821
  break;
57212
- case 792:
57213
- _context18.next = 797;
56822
+ case 791:
56823
+ _context18.next = 796;
57214
56824
  break;
57215
- case 794:
57216
- _context18.prev = 794;
57217
- _context18.t28 = _context18["catch"](782);
56825
+ case 793:
56826
+ _context18.prev = 793;
56827
+ _context18.t28 = _context18["catch"](781);
57218
56828
  _iterator26.e(_context18.t28);
57219
- case 797:
57220
- _context18.prev = 797;
56829
+ case 796:
56830
+ _context18.prev = 796;
57221
56831
  _iterator26.f();
57222
- return _context18.finish(797);
57223
- case 800:
57224
- _context18.next = 805;
56832
+ return _context18.finish(796);
56833
+ case 799:
56834
+ _context18.next = 804;
57225
56835
  break;
57226
- case 802:
57227
- _context18.prev = 802;
57228
- _context18.t29 = _context18["catch"](780);
56836
+ case 801:
56837
+ _context18.prev = 801;
56838
+ _context18.t29 = _context18["catch"](779);
57229
56839
  return _context18.abrupt("return", {
57230
56840
  error: _context18.t29 instanceof Error ? _context18.t29.message : String(_context18.t29)
57231
56841
  });
57232
- case 805:
57233
- _context18.next = 807;
56842
+ case 804:
56843
+ _context18.next = 806;
57234
56844
  return approve("addColumn: ".concat(resolved.map(function (r) {
57235
56845
  return r.label;
57236
56846
  }).join(', ')));
57237
- case 807:
56847
+ case 806:
57238
56848
  if (_context18.sent) {
57239
- _context18.next = 809;
56849
+ _context18.next = 808;
57240
56850
  break;
57241
56851
  }
57242
56852
  return _context18.abrupt("return", declined);
57243
- case 809:
56853
+ case 808:
57244
56854
  added = [];
57245
56855
  newColumns = [];
57246
- _context18.prev = 811;
56856
+ _context18.prev = 810;
57247
56857
  _loop9 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop9() {
57248
56858
  var key, beforeFields, _attempt, newColumn;
57249
56859
  return _regeneratorRuntime.wrap(function _loop9$(_context17) {
57250
56860
  while (1) switch (_context17.prev = _context17.next) {
57251
56861
  case 0:
57252
- key = _resolved[_i15].key;
56862
+ key = _resolved[_i14].key;
57253
56863
  beforeFields = new Set(_handle.getDivaColumnDefs().map(function (d) {
57254
56864
  return d.field;
57255
56865
  }).filter(Boolean));
@@ -57289,18 +56899,18 @@ function createNavigationToolset(ctx) {
57289
56899
  }
57290
56900
  }, _loop9);
57291
56901
  });
57292
- _i15 = 0, _resolved = resolved;
57293
- case 814:
57294
- if (!(_i15 < _resolved.length)) {
57295
- _context18.next = 819;
56902
+ _i14 = 0, _resolved = resolved;
56903
+ case 813:
56904
+ if (!(_i14 < _resolved.length)) {
56905
+ _context18.next = 818;
57296
56906
  break;
57297
56907
  }
57298
- return _context18.delegateYield(_loop9(), "t30", 816);
57299
- case 816:
57300
- _i15++;
57301
- _context18.next = 814;
56908
+ return _context18.delegateYield(_loop9(), "t30", 815);
56909
+ case 815:
56910
+ _i14++;
56911
+ _context18.next = 813;
57302
56912
  break;
57303
- case 819:
56913
+ case 818:
57304
56914
  // On a decision's option-combinations subtable the add also writes the decision's featureRefs.
57305
56915
  decisionSubtableNote = /optioncombination/i.test(_entry3.label) ? " NOTE: on a decision's option-combinations subtable this ALSO wrote the feature(s) into the decision's featureRefs — existing rows carry NO condition for it, which in a type-0/1 re-opens that feature entirely. Re-read the decision row; fill the rows or revert featureRefs if you only wanted to look." : '';
57306
56916
  partialNote = newColumns.length < resolved.length ? " ".concat(resolved.length - newColumns.length, " added column(s) did not surface a field id within the poll \u2014 listGrids shows the final columns.") : '';
@@ -57316,31 +56926,31 @@ function createNavigationToolset(ctx) {
57316
56926
  return "'".concat(c, "'");
57317
56927
  }).join(', '), ".") : 'Column(s) added — the table re-renders; listGrids shows the new columns and their field ids.') + partialNote + decisionSubtableNote + autoNote
57318
56928
  }));
57319
- case 824:
57320
- _context18.prev = 824;
57321
- _context18.t31 = _context18["catch"](811);
56929
+ case 823:
56930
+ _context18.prev = 823;
56931
+ _context18.t31 = _context18["catch"](810);
57322
56932
  return _context18.abrupt("return", {
57323
56933
  error: "".concat(_context18.t31 instanceof Error ? _context18.t31.message : String(_context18.t31)).concat(newColumns.length ? " \u2014 ".concat(newColumns.length, " column(s) were already added before the failure: ").concat(newColumns.join(', ')) : '')
57324
56934
  });
57325
- case 827:
56935
+ case 826:
57326
56936
  _resolveGrid5 = resolveGrid(args.grid), _entry4 = _resolveGrid5.entry, _api3 = _resolveGrid5.api, _error4 = _resolveGrid5.error;
57327
56937
  if (!(_error4 || !_api3 || !_entry4)) {
57328
- _context18.next = 830;
56938
+ _context18.next = 829;
57329
56939
  break;
57330
56940
  }
57331
56941
  return _context18.abrupt("return", {
57332
56942
  error: _error4
57333
56943
  });
57334
- case 830:
56944
+ case 829:
57335
56945
  _handle2 = _entry4.getHandle();
57336
56946
  if (_handle2) {
57337
- _context18.next = 833;
56947
+ _context18.next = 832;
57338
56948
  break;
57339
56949
  }
57340
56950
  return _context18.abrupt("return", {
57341
56951
  error: "Table '".concat(_entry4.label, "' is not ready.")
57342
56952
  });
57343
- case 833:
56953
+ case 832:
57344
56954
  _column7 = String((_column8 = input === null || input === void 0 ? void 0 : input.column) !== null && _column8 !== void 0 ? _column8 : '');
57345
56955
  search = String((_search = input === null || input === void 0 ? void 0 : input.search) !== null && _search !== void 0 ? _search : '');
57346
56956
  _limit = Math.min(Number(input === null || input === void 0 ? void 0 : input.limit) > 0 ? Number(input.limit) : 50, 200); // `exact` is one contract for every source below: action values and enum values as well as lookups.
@@ -57355,11 +56965,11 @@ function createNavigationToolset(ctx) {
57355
56965
  return action.name === _column7;
57356
56966
  });
57357
56967
  if (!optionAction) {
57358
- _context18.next = 855;
56968
+ _context18.next = 854;
57359
56969
  break;
57360
56970
  }
57361
56971
  if (optionAction.options) {
57362
- _context18.next = 843;
56972
+ _context18.next = 842;
57363
56973
  break;
57364
56974
  }
57365
56975
  return _context18.abrupt("return", {
@@ -57368,11 +56978,11 @@ function createNavigationToolset(ctx) {
57368
56978
  hasMore: false,
57369
56979
  note: "'".concat(_column7, "' is a table ACTION with no value list \u2014 its input is described in listGrids: ").concat(optionAction.description)
57370
56980
  });
57371
- case 843:
57372
- _context18.prev = 843;
57373
- _context18.next = 846;
56981
+ case 842:
56982
+ _context18.prev = 842;
56983
+ _context18.next = 845;
57374
56984
  return optionAction.options(search, _limit);
57375
- case 846:
56985
+ case 845:
57376
56986
  _yield$optionAction$o = _context18.sent;
57377
56987
  options = _yield$optionAction$o.options;
57378
56988
  note = _yield$optionAction$o.note;
@@ -57385,20 +56995,20 @@ function createNavigationToolset(ctx) {
57385
56995
  } : {}), {}, {
57386
56996
  note: "Values for runTableAction('".concat(_column7, "', <input>) \u2014 pass the VALUE(s), not the label.").concat(note ? " ".concat(note) : '').concat(wantsExact ? ' exact:true — only options whose value or label equals the search.' : '')
57387
56997
  }));
57388
- case 852:
57389
- _context18.prev = 852;
57390
- _context18.t32 = _context18["catch"](843);
56998
+ case 851:
56999
+ _context18.prev = 851;
57000
+ _context18.t32 = _context18["catch"](842);
57391
57001
  return _context18.abrupt("return", {
57392
57002
  error: _context18.t32 instanceof Error ? _context18.t32.message : String(_context18.t32)
57393
57003
  });
57394
- case 855:
57004
+ case 854:
57395
57005
  // Enum columns are answered here too: 'which values does this column take' is ONE question.
57396
57006
  enumDef = _handle2.getDivaColumnDefs().find(function (d) {
57397
57007
  return d.field === _column7;
57398
57008
  });
57399
57009
  enumData = enumDef === null || enumDef === void 0 || (_enumDef$customParams = enumDef.customParams) === null || _enumDef$customParams === void 0 ? void 0 : _enumDef$customParams.enumData;
57400
57010
  if (!(Array.isArray(enumData) && enumData.length)) {
57401
- _context18.next = 859;
57011
+ _context18.next = 858;
57402
57012
  break;
57403
57013
  }
57404
57014
  return _context18.abrupt("return", _objectSpread$X(_objectSpread$X({
@@ -57418,14 +57028,14 @@ function createNavigationToolset(ctx) {
57418
57028
  } : {}), {}, {
57419
57029
  note: "Enum column \u2014 this is the COMPLETE allowed set (also in listGrids). Stage the VALUE, not the label".concat(enumDef !== null && enumDef !== void 0 && (_enumDef$customParams2 = enumDef.customParams) !== null && _enumDef$customParams2 !== void 0 && _enumDef$customParams2.multiple ? ', comma-separated for multiple' : '', ".").concat(wantsExact ? ' exact:true — only options whose value or label equals the search.' : '')
57420
57030
  }));
57421
- case 859:
57031
+ case 858:
57422
57032
  if (enumDef) {
57423
- _context18.next = 866;
57033
+ _context18.next = 865;
57424
57034
  break;
57425
57035
  }
57426
57036
  computedDef = divaDefOf(_handle2.getDivaColumnDefs(), _column7);
57427
57037
  if (!isComputedColumn(computedDef)) {
57428
- _context18.next = 864;
57038
+ _context18.next = 863;
57429
57039
  break;
57430
57040
  }
57431
57041
  // Same source as listGrids, so the two cannot disagree about whether a new row may carry this column.
@@ -57436,16 +57046,16 @@ function createNavigationToolset(ctx) {
57436
57046
  hasMore: false,
57437
57047
  note: savedRowsOnly ? "'".concat(_column7, "' is a computed matrix cell \u2014 it has no option list, and addRows cannot set it. Create the row, then set it with stageTableEdits 'edits'.") : "'".concat(_column7, "' is a computed matrix cell \u2014 it has no option list; stage its value directly with stageTableEdits.")
57438
57048
  });
57439
- case 864:
57049
+ case 863:
57440
57050
  fields = _handle2.getDivaColumnDefs().map(function (d) {
57441
57051
  return d.field;
57442
57052
  }).filter(Boolean);
57443
57053
  return _context18.abrupt("return", {
57444
57054
  error: "Column '".concat(_column7, "' not found. Fields of '").concat(_entry4.label, "': ").concat(fields.join(', '), ".")
57445
57055
  });
57446
- case 866:
57056
+ case 865:
57447
57057
  if (!(enumDef.cellDataType === 'asset')) {
57448
- _context18.next = 868;
57058
+ _context18.next = 867;
57449
57059
  break;
57450
57060
  }
57451
57061
  return _context18.abrupt("return", {
@@ -57454,9 +57064,9 @@ function createNavigationToolset(ctx) {
57454
57064
  hasMore: false,
57455
57065
  note: "'".concat(_column7, "' is an ASSET cell \u2014 no option list; write it via uploadAsset + setAssetCell.")
57456
57066
  });
57457
- case 868:
57067
+ case 867:
57458
57068
  if (!(enumDef.cellDataType !== 'lookup' && !isHeaderAddColumn(enumDef))) {
57459
- _context18.next = 870;
57069
+ _context18.next = 869;
57460
57070
  break;
57461
57071
  }
57462
57072
  return _context18.abrupt("return", {
@@ -57465,7 +57075,7 @@ function createNavigationToolset(ctx) {
57465
57075
  hasMore: false,
57466
57076
  note: "'".concat(_column7, "' is a free-form ").concat((_enumDef$cellDataType = enumDef.cellDataType) !== null && _enumDef$cellDataType !== void 0 ? _enumDef$cellDataType : 'text', " column \u2014 it has no option list; stage a ").concat(enumDef.cellDataType === 'number' ? 'number' : 'value', " directly with stageTableEdits.")
57467
57077
  });
57468
- case 870:
57078
+ case 869:
57469
57079
  // Row-dependent url/filter templates resolve against a loaded row.
57470
57080
  firstRow = _api3.getDisplayedRowAtIndex(0);
57471
57081
  rowData = isRealRow(firstRow) ? (_data = firstRow.data) !== null && _data !== void 0 ? _data : {} : {}; // The server's contains-filter reads the search as a pattern: a bracket or a pipe in it returns nothing at all
@@ -57478,10 +57088,10 @@ function createNavigationToolset(ctx) {
57478
57088
  })[0]) !== null && _plainWords$sort$ !== void 0 ? _plainWords$sort$ : '' : search;
57479
57089
  matchLocally = remoteSearch !== search || wantsExact; // The local match only sees ONE capped fetch — a plain word with more hits than that can still hide the value.
57480
57090
  fetchLimit = matchLocally ? Math.max(_limit, 200) : _limit;
57481
- _context18.prev = 877;
57482
- _context18.next = 880;
57091
+ _context18.prev = 876;
57092
+ _context18.next = 879;
57483
57093
  return _handle2.fetchLookupOptions(_column7, remoteSearch, rowData, 0, fetchLimit);
57484
- case 880:
57094
+ case 879:
57485
57095
  fetched = _context18.sent;
57486
57096
  text = function text(o) {
57487
57097
  var _o$label2;
@@ -57509,9 +57119,9 @@ function createNavigationToolset(ctx) {
57509
57119
  } : {}), {}, {
57510
57120
  note: (isHeaderAddColumn(enumDef) ? "These entries are ADDABLE via runTableAction 'addColumn' (each becomes a table column) — they are not cell values to stage." : 'Stage this column with the VALUE(s) — comma-separated when the column is multi-select (see columnMeta.multiSelect).') + (remoteSearch !== search ? " The search contains characters the server filter reads as a pattern \u2014 the server was asked for '".concat(remoteSearch, "' and the full text '").concat(search, "' was matched here.") : '') + (wantsExact ? ' exact:true — only options whose value or label equals the search.' : '') + (fetchCapped ? " The ".concat(wantsExact ? 'exact' : 'full-text', " check ran on the first ").concat(fetchLimit, " rows").concat(remoteSearch ? " matching '".concat(remoteSearch, "'") : '', " only \u2014 narrow the search if the value is not among them.") : '')
57511
57121
  }));
57512
- case 887:
57513
- _context18.prev = 887;
57514
- _context18.t33 = _context18["catch"](877);
57122
+ case 886:
57123
+ _context18.prev = 886;
57124
+ _context18.t33 = _context18["catch"](876);
57515
57125
  // On an empty table a row-dependent lookup request goes out broken — teach the recovery instead of the opaque error.
57516
57126
  defs = _handle2.getDivaColumnDefs();
57517
57127
  url = String((_defs$find$customPara = (_defs$find = defs.find(function (d) {
@@ -57531,92 +57141,92 @@ function createNavigationToolset(ctx) {
57531
57141
  return _context18.abrupt("return", {
57532
57142
  error: (_context18.t33 instanceof Error ? _context18.t33.message : String(_context18.t33)) + hint
57533
57143
  });
57534
- case 896:
57144
+ case 895:
57535
57145
  _resolveGrid6 = resolveGrid(args.grid), _api4 = _resolveGrid6.api, _error5 = _resolveGrid6.error;
57536
57146
  if (!(_error5 || !_api4)) {
57537
- _context18.next = 899;
57147
+ _context18.next = 898;
57538
57148
  break;
57539
57149
  }
57540
57150
  return _context18.abrupt("return", {
57541
57151
  error: _error5
57542
57152
  });
57543
- case 899:
57153
+ case 898:
57544
57154
  _api4.setFilterModel(null);
57545
57155
  return _context18.abrupt("return", {
57546
57156
  ok: true
57547
57157
  });
57548
- case 901:
57158
+ case 900:
57549
57159
  _resolveGrid7 = resolveGrid(args.grid), _entry5 = _resolveGrid7.entry, _error6 = _resolveGrid7.error;
57550
57160
  if (!(_error6 || !_entry5)) {
57551
- _context18.next = 904;
57161
+ _context18.next = 903;
57552
57162
  break;
57553
57163
  }
57554
57164
  return _context18.abrupt("return", {
57555
57165
  error: _error6
57556
57166
  });
57557
- case 904:
57167
+ case 903:
57558
57168
  _handle3 = _entry5.getHandle();
57559
57169
  if (_handle3) {
57560
- _context18.next = 907;
57170
+ _context18.next = 906;
57561
57171
  break;
57562
57172
  }
57563
57173
  return _context18.abrupt("return", {
57564
57174
  error: "Table '".concat(_entry5.label, "' is not ready.")
57565
57175
  });
57566
- case 907:
57176
+ case 906:
57567
57177
  if (_handle3.hasPendingChanges()) {
57568
- _context18.next = 909;
57178
+ _context18.next = 908;
57569
57179
  break;
57570
57180
  }
57571
57181
  return _context18.abrupt("return", {
57572
57182
  discarded: false,
57573
57183
  note: "Nothing is staged on '".concat(_entry5.label, "' \u2014 no staging blocks writes to it.")
57574
57184
  });
57575
- case 909:
57185
+ case 908:
57576
57186
  if (ctx.autoApprove) {
57577
- _context18.next = 916;
57187
+ _context18.next = 915;
57578
57188
  break;
57579
57189
  }
57580
57190
  awaitingApproval();
57581
57191
  // The bar's own buttons read Apply/Discard — the label says what Apply does, or Discard reads as the action.
57582
57192
  _label = "discardStagedChanges: every staged change on '".concat(_entry5.label, "' is dropped, the table returns to its last committed state");
57583
- _context18.next = 914;
57193
+ _context18.next = 913;
57584
57194
  return _entry5.requestAgentApproval(1, _label, signal);
57585
- case 914:
57195
+ case 913:
57586
57196
  if (_context18.sent) {
57587
- _context18.next = 916;
57197
+ _context18.next = 915;
57588
57198
  break;
57589
57199
  }
57590
57200
  return _context18.abrupt("return", {
57591
57201
  discarded: false,
57592
57202
  note: 'The user KEPT the staged changes — nothing was discarded. Ask what to do with them instead.'
57593
57203
  });
57594
- case 916:
57204
+ case 915:
57595
57205
  if (_handle3.hasPendingChanges()) {
57596
- _context18.next = 918;
57206
+ _context18.next = 917;
57597
57207
  break;
57598
57208
  }
57599
57209
  return _context18.abrupt("return", {
57600
57210
  discarded: false,
57601
57211
  note: "The table SAVED the staged changes on '".concat(_entry5.label, "' before the decision arrived (it saves pending edits by itself when the user clicks outside the grid) \u2014 nothing was discarded, those changes are live on the server. Read the rows back (readGridRows) and ask the user whether to undo them.")
57602
57212
  });
57603
- case 918:
57604
- _context18.next = 920;
57213
+ case 917:
57214
+ _context18.next = 919;
57605
57215
  return _handle3.rollback();
57606
- case 920:
57216
+ case 919:
57607
57217
  // Same transparency rule as runTableAction: a discard executed without the bar must be reported as such.
57608
57218
  _autoNote = ctx.autoApprove ? ' AUTO-APPROVE is on — executed WITHOUT the approval bar, so the user could not keep their own pending edits; mention that ONCE per reply, not per call.' : '';
57609
57219
  return _context18.abrupt("return", {
57610
57220
  discarded: true,
57611
57221
  note: "The staged changes on '".concat(_entry5.label, "' were discarded \u2014 the table is back at its last committed state, nothing was sent to the server, and writes to it are possible again.").concat(_autoNote)
57612
57222
  });
57613
- case 922:
57223
+ case 921:
57614
57224
  throw new Error("Unknown navigation tool: ".concat(name));
57615
- case 923:
57225
+ case 922:
57616
57226
  case "end":
57617
57227
  return _context18.stop();
57618
57228
  }
57619
- }, _callee11, null, [[38, 44], [58, 64], [284, 296, 299, 302], [308, 326, 329, 332], [333, 357, 360, 363], [391, 403, 406, 409], [481,, 538, 541], [483, 494, 497, 500], [501, 513, 516, 519], [520, 532, 535, 538], [606, 615], [625, 630], [645, 650], [660, 664], [680, 697], [724, 729], [751, 757], [780, 802], [782, 794, 797, 800], [811, 824], [843, 852], [877, 887]]);
57229
+ }, _callee11, null, [[37, 43], [57, 63], [283, 295, 298, 301], [307, 325, 328, 331], [332, 356, 359, 362], [390, 402, 405, 408], [480,, 537, 540], [482, 493, 496, 499], [500, 512, 515, 518], [519, 531, 534, 537], [605, 614], [624, 629], [644, 649], [659, 663], [679, 696], [723, 728], [750, 756], [779, 801], [781, 793, 796, 799], [810, 823], [842, 851], [876, 886]]);
57620
57230
  }));
57621
57231
  function dispatch(_x12, _x13, _x14, _x15) {
57622
57232
  return _dispatch.apply(this, arguments);
@@ -57803,7 +57413,7 @@ function showEntityFromLink(_x46, _x47) {
57803
57413
  function _showEntityFromLink() {
57804
57414
  _showEntityFromLink = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee19(root, href) {
57805
57415
  var _params$get, _params$get2, _params$get3, _params$get4, _params$get5, _params$get6, _params$get7, _params$get8;
57806
- var params, targetPath, grid, column, value, targetMissing, api, _yield$locateRowCore$, parentNode, toolId, toolDeadline, opened, _i17, _arr5, bar, tool, subGrid, subColumn, subValue, subApi;
57416
+ var params, targetPath, grid, column, value, targetMissing, api, _yield$locateRowCore$, parentNode, toolId, toolDeadline, opened, _i16, _arr5, bar, tool, subGrid, subColumn, subValue, subApi;
57807
57417
  return _regeneratorRuntime.wrap(function _callee19$(_context27) {
57808
57418
  while (1) switch (_context27.prev = _context27.next) {
57809
57419
  case 0:
@@ -57879,13 +57489,13 @@ function _showEntityFromLink() {
57879
57489
  _context27.next = 47;
57880
57490
  break;
57881
57491
  }
57882
- _i17 = 0, _arr5 = [root.contentStore.rightToolBar, root.contentStore.bottomToolBar];
57492
+ _i16 = 0, _arr5 = [root.contentStore.rightToolBar, root.contentStore.bottomToolBar];
57883
57493
  case 31:
57884
- if (!(_i17 < _arr5.length)) {
57494
+ if (!(_i16 < _arr5.length)) {
57885
57495
  _context27.next = 42;
57886
57496
  break;
57887
57497
  }
57888
- bar = _arr5[_i17];
57498
+ bar = _arr5[_i16];
57889
57499
  tool = bar.tools.find(function (candidate) {
57890
57500
  return candidate.id.toLowerCase() === toolId.toLowerCase();
57891
57501
  });
@@ -57898,7 +57508,7 @@ function _showEntityFromLink() {
57898
57508
  opened = true;
57899
57509
  return _context27.abrupt("break", 42);
57900
57510
  case 39:
57901
- _i17++;
57511
+ _i16++;
57902
57512
  _context27.next = 31;
57903
57513
  break;
57904
57514
  case 42:
@@ -57946,566 +57556,8 @@ function _createForOfIteratorHelper$q(r, e) { var t = "undefined" != typeof Symb
57946
57556
  function _unsupportedIterableToArray$q(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$q(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$q(r, a) : void 0; } }
57947
57557
  function _arrayLikeToArray$q(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
57948
57558
 
57949
- /** Definitions of the media/asset tools this toolset executes — sent to the backend per turn. */
57950
- var MEDIA_TOOL_DEFS = [{
57951
- name: 'uploadAsset',
57952
- description: "Upload one or MANY media assets and get their mediaItemIds. Three sources per asset: 'url' (a source the BROWSER downloads), 'svg' (inline markup), 'base64' (inline bytes of a SMALL local file — a data: URI in 'url' counts as the same thing). WHICH SOURCE: inline bytes travel through the conversation, so 'base64' is for small assets only (swatches, icons, thumbnails; hard cap 128 KB decoded). Photo-sized or BULK local files go over HTTP as 'url' — a CORS-enabled static server on localhost is enough, the browser fetches it directly, so the bytes never enter the conversation and a folder of 50 photos costs 50 short URLs. BULK: pass 'files' (an array of {fileName, url|svg|base64}) to upload a whole set in ONE call; it uploads sequentially and reports uploaded/failed per entry, so a partial failure names exactly what to retry. Assets are unused until referenced: write each mediaItemId into an asset column with setAssetCell. Extension decides the media type (svg/png/jpg/webp/gif/pdf/glb).",
57953
- input_schema: {
57954
- type: 'object',
57955
- properties: {
57956
- fileName: {
57957
- type: 'string',
57958
- description: "target file name WITH extension (e.g. 'front.png', 'top-4711.svg') — REQUIRED for a single upload (ignored when 'files' is passed)"
57959
- },
57960
- url: {
57961
- type: 'string',
57962
- description: 'source URL the browser downloads (mutually exclusive with svg/base64); a data: URI is treated as inline bytes'
57963
- },
57964
- svg: {
57965
- type: 'string',
57966
- description: 'inline SVG markup to upload as an .svg asset (mutually exclusive with url/base64) — inline like base64, so the same 128 KB cap applies'
57967
- },
57968
- base64: {
57969
- type: 'string',
57970
- description: 'inline file bytes, base64-encoded (raw or a full data: URI) — for SMALL local files only, max 128 KB decoded'
57971
- },
57972
- files: {
57973
- type: 'array',
57974
- description: 'BULK: upload many assets in one call. Each entry is SELF-CONTAINED ({fileName, url|svg|base64}) — the top-level fields are IGNORED once files is passed, so every entry carries its own source.',
57975
- items: {
57976
- type: 'object',
57977
- properties: {
57978
- fileName: {
57979
- type: 'string'
57980
- },
57981
- url: {
57982
- type: 'string'
57983
- },
57984
- svg: {
57985
- type: 'string'
57986
- },
57987
- base64: {
57988
- type: 'string'
57989
- }
57990
- },
57991
- required: ['fileName']
57992
- }
57993
- }
57994
- }
57995
- },
57996
- requiresEditPermission: true
57997
- }, {
57998
- name: 'generateImageAsset',
57999
- description: "Generate an image with the DIVA AI service and upload the result to the media service — returns the mediaItemId, NEVER the bytes (they stay in the browser). REFERENCE-DRIVEN: 'referenceUrls'/'referenceMediaItemIds' are what keep an existing product recognizable, and the AI SERVICE downloads them, not the browser, so they must be reachable FROM THE SERVICE — a media-service CDN url always is; a localhost url only when the service itself runs locally (against a remote service it is refused). MODES carry the rules the caller should not have to remember: 'product' forbids every change to geometry (identical silhouette, proportions, angles, part count — only render quality, background and stray text/dimension lines may change) and REQUIRES a reference, so it is the mode for lifting an existing drawing or photo into a clean tile; 'texture' produces a flat edge-to-edge material swatch (color/gloss/grain taken from the reference, no object, no perspective, no shadow) for finish/color options; 'free' sends the prompt verbatim. Put WHAT you want in 'prompt' — the mode supplies the HOW. Text-only generation of an EXISTING product is never faithful: without a reference the model invents a similar-looking product. Costs money per image and counts against the organization's AI budget, so the call asks the user to approve the SPEND on the view's approval bar first (unless the conversation enabled auto-approve) and names the number of images; 'dryRun' returns the final prompt without generating. BULK: pass 'batch' (an array of {prompt, fileName, referenceMediaItemIds?|referenceUrls?}) to generate a whole set in ONE call — entries inherit the top-level mode/model/resolution, results come back per entry with ONE usage block, and a time budget hands untouched entries back as 'remaining' instead of losing the receipt. Check usage.daily.user.remaining BEFORE a series run — a run that hits the limit halfway leaves mixed image sources. This tool does NOT touch the catalog — look at the results (fetch them into ONE contact sheet, not one review per file), then write them with setAssetCell 'cells'.",
58000
- input_schema: {
58001
- type: 'object',
58002
- properties: {
58003
- fileName: {
58004
- type: 'string',
58005
- description: "target file name WITH extension (e.g. 'foot-191.png') — REQUIRED unless 'batch' is passed"
58006
- },
58007
- prompt: {
58008
- type: 'string',
58009
- description: "what to produce: the subject and the wanted result. NOT the preservation rules — the mode adds those. REQUIRED unless 'batch' is passed"
58010
- },
58011
- mode: {
58012
- type: 'string',
58013
- "enum": ['product', 'texture', 'free'],
58014
- description: "'product' = geometry untouchable, reference REQUIRED · 'texture' = flat material swatch · 'free' = prompt verbatim"
58015
- },
58016
- referenceUrls: {
58017
- type: 'array',
58018
- items: {
58019
- type: 'string'
58020
- },
58021
- description: 'http(s) image urls the AI SERVICE downloads (CDN urls always work; a localhost url only if the service runs locally too)'
58022
- },
58023
- referenceMediaItemIds: {
58024
- type: 'array',
58025
- items: {
58026
- type: 'string'
58027
- },
58028
- description: 'media items to use as references — resolved to their CDN url here (read one out of an asset cell with locateRow)'
58029
- },
58030
- model: {
58031
- type: 'string',
58032
- description: "image model, default 'gemini-3.1-flash-image-preview' (newest). gemini: gemini-2.5-flash-image | gemini-3-pro-image-preview | gemini-3.1-flash-image-preview · openai: gpt-image-1 | gpt-image-1-mini | dall-e-3"
58033
- },
58034
- engine: {
58035
- type: 'string',
58036
- "enum": ['gemini', 'openai'],
58037
- description: 'AI provider — inferred from the model when omitted'
58038
- },
58039
- resolution: {
58040
- type: 'string',
58041
- description: "'WIDTHxHEIGHT', default '1024x1024' (1K square, what option/article tiles show); the ratio of the two decides the aspect ratio"
58042
- },
58043
- temperature: {
58044
- type: 'number',
58045
- description: 'sampling temperature — lower stays closer to the reference'
58046
- },
58047
- promptId: {
58048
- type: 'string',
58049
- description: "a managed prompt's _id (admin/prompts) — its own engine/model/enhancements win over 'mode'"
58050
- },
58051
- dryRun: {
58052
- type: 'boolean',
58053
- description: 'return the final prompt and the resolved references WITHOUT generating — costs nothing'
58054
- },
58055
- batch: {
58056
- type: 'array',
58057
- maxItems: 50,
58058
- items: {
58059
- type: 'object',
58060
- properties: {
58061
- prompt: {
58062
- type: 'string',
58063
- description: 'what THIS image should show'
58064
- },
58065
- fileName: {
58066
- type: 'string',
58067
- description: "target file name WITH extension (e.g. 'foot-191.png')"
58068
- },
58069
- referenceUrls: {
58070
- type: 'array',
58071
- items: {
58072
- type: 'string'
58073
- },
58074
- description: 'http(s) reference urls for THIS entry'
58075
- },
58076
- referenceMediaItemIds: {
58077
- type: 'array',
58078
- items: {
58079
- type: 'string'
58080
- },
58081
- description: 'reference media items for THIS entry'
58082
- },
58083
- mode: {
58084
- type: 'string',
58085
- "enum": ['product', 'texture', 'free'],
58086
- description: 'overrides the top-level mode for THIS entry'
58087
- },
58088
- model: {
58089
- type: 'string',
58090
- description: 'overrides the top-level model for THIS entry'
58091
- },
58092
- resolution: {
58093
- type: 'string',
58094
- description: 'overrides the top-level resolution for THIS entry'
58095
- }
58096
- },
58097
- required: ['prompt', 'fileName']
58098
- },
58099
- description: 'BULK: many generations in ONE call — each entry inherits the top-level mode/model/resolution and may override them. Sequential; a time budget returns not-started entries as remaining.'
58100
- }
58101
- },
58102
- required: ['mode']
58103
- },
58104
- requiresEditPermission: true
58105
- }, {
58106
- name: 'setAssetCell',
58107
- description: "Write an ASSET column ('asset' type in listGrids: images, svgs, textures, documents, logo, …) — the asset counterpart of stageTableEdits (which rejects asset cells). The row is addressed by keyColumn=keyValue on the target table; the value is a mediaItemId from uploadAsset (or read from another asset cell). A row that is not yet loaded on screen is located server-side automatically (same mechanism as stageTableEdits) — nothing needs to be scrolled/filtered into view first. Multi-asset columns (multiSelect) default to APPEND; mode 'replace' overwrites the whole list, 'remove' deletes the entry with this mediaItemId. BULK: pass 'cells' (an array of {keyValue, mediaItemId}) to write a whole set in ONE call — entries inherit the top-level grid/keyColumn/column/mode, so a serie of article images is one call instead of 35; rows already on screen are staged together and saved in ONE commit, rows that first need locating are each saved on their own right after being found (so one row's lookup can never cost another row its write) — either way ONE approval covers the whole batch. An entry may carry a decisionNo — the MEDIA GATE for the planner's SVG-Tausch (entry order = evaluation order, first matching gate wins; see getGuide('decisionWiring') MEDIA GATES). Shows the user an approval bar on the table (ONE bar for a batch) — announce the change BEFORE calling; the tool blocks until the user decides. After the server CONFIRMS a write, the grid refreshes itself (gridRefreshed:true) — no manual reload; if any entry stays persisted:false the refresh is skipped so the pending write is not discarded. Item svgs note: svgs[0] is the planner's top view.",
58108
- input_schema: {
58109
- type: 'object',
58110
- properties: {
58111
- grid: {
58112
- type: 'string',
58113
- description: 'table label/gridId from listGrids (default: first table)'
58114
- },
58115
- keyColumn: {
58116
- type: 'string',
58117
- description: 'column FIELD id whose value uniquely identifies the row — REQUIRED (single cell and batch)'
58118
- },
58119
- keyValue: {
58120
- type: 'string',
58121
- description: "the unique value (rows not on screen are located server-side) — REQUIRED unless 'cells' is passed"
58122
- },
58123
- column: {
58124
- type: 'string',
58125
- description: "the asset column's field id"
58126
- },
58127
- mediaItemId: {
58128
- type: 'string',
58129
- description: "the media item _id — uploadAsset returns it. REQUIRED unless 'cells' is passed"
58130
- },
58131
- url: {
58132
- type: 'string',
58133
- description: "the asset's URL (from uploadAsset) — used for the cell preview"
58134
- },
58135
- name: {
58136
- type: 'string',
58137
- description: 'display file name for the cell'
58138
- },
58139
- decisionNo: {
58140
- type: 'number',
58141
- description: 'media-gate decision for THIS entry (SVG-Tausch): the entry only wins when that decision matches the configuration'
58142
- },
58143
- mode: {
58144
- type: 'string',
58145
- "enum": ['append', 'replace', 'remove'],
58146
- description: "default 'append' (multi-asset columns)"
58147
- },
58148
- cells: {
58149
- type: 'array',
58150
- maxItems: 200,
58151
- description: 'BULK: write many cells in ONE call — the normal case when a supplier delivery is attached (a whole serie, not one row). Each entry needs keyValue + mediaItemId; grid/keyColumn/column come from the top level (the whole batch writes one column of one table), and an entry may carry its own decisionNo and mode. All rows must be loaded. One approval bar for the whole batch.',
58152
- items: {
58153
- type: 'object',
58154
- properties: {
58155
- keyValue: {
58156
- type: 'string'
58157
- },
58158
- mediaItemId: {
58159
- type: 'string'
58160
- },
58161
- url: {
58162
- type: 'string'
58163
- },
58164
- name: {
58165
- type: 'string'
58166
- },
58167
- decisionNo: {
58168
- type: 'number',
58169
- description: 'media-gate decision for THIS entry (SVG-Tausch)'
58170
- },
58171
- mode: {
58172
- type: 'string',
58173
- "enum": ['append', 'replace', 'remove']
58174
- }
58175
- },
58176
- required: ['keyValue', 'mediaItemId']
58177
- }
58178
- }
58179
- },
58180
- required: ['column']
58181
- },
58182
- argAliases: GRID_ARG_ALIASES,
58183
- requiresEditPermission: true
58184
- }, {
58185
- name: 'generateArticleSvg',
58186
- description: "Generate a planner-conform top-view SVG for an article from a TEMPLATE, upload it, and (when typeNo is given) attach it to that item's svgs column — svgs[0] becomes the planner's 2D top view (clears WC_0011). Units are CENTIMETERS (item measures in mm ÷ 10; planner articleSize is cm). The SVG carries the planner semantics automatically: OLT outline (size/collision), OLF functional footprint when functionalOverhangCm is set (e.g. pull-out bed space), SAH/SAV stretch strips (thin insertion zones inside the seat/body — width/depth growth distributes there; armrests and backrests keep their size), and AV docking LINES (AVL↔AVR side docking, AVN↔AVS front/back, AVO↔AVU stacking, AVC center; equal numbers pair). Templates: box (Schrank/Tisch/Hocker/Kissen), roundTable, sofaModule (seats/armrests/backrest/cushions; armLeftCm/armRightCm = 0 auto-adds the AVL/AVR connector on that open side), longchair (ONE seat cushion folded around the armrest fronts; arms reach depthCm/2 by default — do NOT pass armDepthCm unless the PDF differs), cornerElement (SQUARE body with ALWAYS-straight outline edges — only the cushion seams curve, so the shape stays symmetric under planner rotation; backrest bands on the back and one side via backSide), bed (widthCm/depthCm ARE the footprint; headboardWidthCm/headboardDepthCm are OPT-IN and ADD to it, so the item's depth then has to be the total). ALWAYS PASS BOTH armLeftCm AND armRightCm on sofaModule/longchair: the defaults are NOT zero (sofaModule 15/15, longchair 0/15), so an omitted side silently grows an armrest and that side's auto AVL/AVR connector — which only appears on an ARMLESS side — is never emitted, leaving an article that looks right and does not dock. An ACCESSORY (headrest/footrest) needs an UNNUMBERED anchor: connectors [{type:'AVU', unnumbered:true}] with autoConnectors:false, because per:'back' numbers the base anchors AVO1..AVOn and a numbered AVU1 pairs with AVO1 only — one accessory article then serves every cushion of the serie. LOOK: every manufacturer draws differently — the 'style' config controls ALL visible artwork (per-part colors/strokes/radii, seam-vs-cushion rendering, scalloped front edge, dashed function zones, symbols, gradients) while the planner semantics stay identical. Match a supplier's catalog drawings by designing the style ONCE with the user (iterate with attach:false and check the preview), uploadAsset the JSON, then pass styleUrl on every later call. RECIPES do the same for recurring BUILD SHAPES: 'recipe' takes a built-in name ('daybed') or an inline {spec, style?} whose fields merge UNDER the call's own — capture a new shape once, uploadAsset the recipe JSON, reuse it via recipeUrl in any later session. Attached writes REFRESH the grid automatically once the server confirms them. The OLT outline IS the collision shape — keep the generated footprint equal to the article's real measures unless you deliberately model an overhang. Docking-line orientation is EXPERIMENTAL — verify with getDockingInfo after reloadPlanner. Attaching shows the approval bar on the items table (items view on screen, row loaded).",
58187
- input_schema: {
58188
- type: 'object',
58189
- properties: {
58190
- template: {
58191
- type: 'string',
58192
- "enum": ['box', 'roundTable', 'sofaModule', 'longchair', 'cornerElement', 'recamiere', 'lShape', 'bed'],
58193
- description: 'base shape template (recamiere = open lying element with the backrest along ONE side, the other side docks; lShape = one-piece corner landscape — landscapes are normally DOCKED module combinations, use lShape only when the catalog sells it as one article)'
58194
- },
58195
- widthCm: {
58196
- type: 'number',
58197
- description: "article width in cm. bed: the BED only (headboard adds to it); longchair armStyle 'extension': the seat body only (arms add to it)"
58198
- },
58199
- depthCm: {
58200
- type: 'number',
58201
- description: 'article depth in cm (top view, toward the viewer). bed: the BED only'
58202
- },
58203
- cornerRadiusCm: {
58204
- type: 'number',
58205
- description: 'corner rounding in cm: box body; sofa/longchair PARTS (Armlehnen, Rückenlehne, Polster — the outer silhouette stays square); bed headboard+mattress'
58206
- },
58207
- seats: {
58208
- type: 'number',
58209
- description: 'sofaModule: seat cushion count (default 2). longchair: BACK cushion count (default 1)'
58210
- },
58211
- armLeftCm: {
58212
- type: 'number',
58213
- description: 'sofa/longchair: left armrest width in cm; 0 = open dockable side (auto AVL). Defaults 15 / 0'
58214
- },
58215
- armRightCm: {
58216
- type: 'number',
58217
- description: 'sofa/longchair: right armrest width in cm; 0 = open dockable side (auto AVR). Defaults 15 / 15'
58218
- },
58219
- armDepthCm: {
58220
- type: 'number',
58221
- description: 'longchair: how far the armrests reach from the back edge toward the front, in cm. OMIT IT — the default depthCm/2 is the real-world shape (arms stop about halfway, the seat folds around their fronts). Passing the full depth turns the longchair into a plain sofa silhouette (measured mistake), and any value within 8cm of the full depth snaps to full. Only set it when the PDF clearly shows a different arm length'
58222
- },
58223
- armStyle: {
58224
- type: 'string',
58225
- "enum": ['inset', 'extension'],
58226
- description: "longchair: 'inset' (default) = armrests take space away from the seat cushion (folded cushion); 'extension' = armrests EXTEND the article beyond widthCm (total = widthCm + arms) and the seat cushion stays rectangular"
58227
- },
58228
- armOutsideRatio: {
58229
- type: 'number',
58230
- description: 'longchair: fraction of each armrest OUTSIDE the seat body — 0 = inset, 1 = extension, 0.5 = 50/50, 0.7 = 30/70 inside/outside. Wins over armStyle; outside portions ADD to the total width'
58231
- },
58232
- backDepthCm: {
58233
- type: 'number',
58234
- description: 'sofa/longchair/corner: backrest depth in cm (default 20). longchair also accepts 0 = BACKLESS liege (no band, no fold seam) — the Daybed idiom, usually with looseBackCushions'
58235
- },
58236
- looseBackCushions: {
58237
- type: 'boolean',
58238
- description: "longchair: draw loose back cushions as overlapping LEAF shapes along the back edge (supplier 'Daybed' drawings) instead of a band — combine with backDepthCm 0 and partial-depth arms on BOTH sides"
58239
- },
58240
- recipe: {
58241
- description: "reusable spec defaults for a recurring build shape: a BUILT-IN name (e.g. 'daybed') or an inline {description?, spec: {…}, style?} object. Merged UNDER the call/batch-entry fields (the call always wins), so one recipe + per-article width/depth covers a whole serie. AUTHOR NEW ONES mid-session: design the shape once with attach:false, then uploadAsset the recipe JSON and pass recipeUrl on later calls — same flow as styleUrl"
58242
- },
58243
- recipeUrl: {
58244
- type: 'string',
58245
- description: 'URL of a stored recipe JSON (media item) — the durable form of `recipe`; fetched once per call, entries merge the same way'
58246
- },
58247
- backFromCm: {
58248
- type: 'number',
58249
- description: "sofaModule: back band covers only [backFromCm..backToCm] of the back edge — the open rest is a lying surface ('1-Sitzer + ABSCHLUSSTEIL links/rechts' price-list idiom). Cells/cushions/seams live in the band segment"
58250
- },
58251
- backToCm: {
58252
- type: 'number',
58253
- description: 'sofaModule: end of the back-band segment in cm (default: up to the arm/edge)'
58254
- },
58255
- sideBackSide: {
58256
- type: 'string',
58257
- "enum": ['left', 'right'],
58258
- description: "sofaModule: additional side band mitre-joined to the back band = one-piece Abschlusselement ('UMBAUECKE'/'OPEN END links/rechts'). TWO conventions, auto-picked by orientation: LANDSCAPE (widthCm > depthCm, partial back band via backFromCm) keeps the band + ONE unnumbered front-corner dock at the band side; PORTRAIT (depthCm > widthCm — the Vilmers Umbauecke/Open-end shape) draws a SEAT area at the top (division line at seatDepthCm) + open LYING surface below and gets ONE numbered back-aligned dock on the open side. NEVER model these as cornerElement and never as a plain stretched sofa. Catalog side: an Abschlusselement is typeKey 14 (Polster-Abschlussteil), NOT 7 (Polsterecke) — the planner groups articles by typeKey"
58259
- },
58260
- seatDepthCm: {
58261
- type: 'number',
58262
- description: 'sofaModule portrait Abschluss (sideBackSide set + depthCm > widthCm): depth of the seat area from the back edge — the seat/lying division line. Take it from the PDF (often = the serie seat depth or the element width); default depthCm/2'
58263
- },
58264
- autoConnectors: {
58265
- type: 'boolean',
58266
- description: 'false = suppress ALL auto-added docking points — the explicit connectors list is then complete (for Abschluss elements with house-specific docking)'
58267
- },
58268
- cornerShapeSide: {
58269
- type: 'string',
58270
- "enum": ['left', 'right'],
58271
- description: "sofaModule: which FRONT corner carries the cornerShape cut (default 'right')"
58272
- },
58273
- cushions: {
58274
- type: 'boolean',
58275
- description: 'sofa/longchair: draw seat/back cushions (default true)'
58276
- },
58277
- backSide: {
58278
- type: 'string',
58279
- "enum": ['left', 'right'],
58280
- description: "cornerElement/recamiere: which side carries the (second) backrest band (default 'left')"
58281
- },
58282
- cornerShape: {
58283
- type: 'string',
58284
- "enum": ['square', 'diagonal', 'round'],
58285
- description: "cornerElement/sofaModule: FRONT-corner treatment — 'diagonal' cuts it straight (Trapezecke/Fase), 'round' draws a convex quarter arc (Rundecke). Collision/OLT stays the full rectangle"
58286
- },
58287
- cornerShapeCm: {
58288
- type: 'number',
58289
- description: 'cornerElement: cut/arc extent from the front corner in cm (default 40% of the smaller side)'
58290
- },
58291
- legSide: {
58292
- type: 'string',
58293
- "enum": ['left', 'right'],
58294
- description: "lShape: which side carries the deep LEG (default 'left')"
58295
- },
58296
- legWidthCm: {
58297
- type: 'number',
58298
- description: 'lShape: leg width along x in cm (default 40% of widthCm)'
58299
- },
58300
- barDepthCm: {
58301
- type: 'number',
58302
- description: 'lShape: back-bar depth along y in cm (default 45% of depthCm); seats splits the bar into seam cells'
58303
- },
58304
- headboardWidthCm: {
58305
- type: 'number',
58306
- description: 'bed: headboard width in cm (default bed width) — ADDS to the bed, may differ from it'
58307
- },
58308
- headboardDepthCm: {
58309
- type: 'number',
58310
- description: 'bed: headboard depth in cm (default 8) — ADDS to depthCm (total = depthCm + headboard)'
58311
- },
58312
- connectors: {
58313
- type: 'array',
58314
- description: 'docking connectors as planner AV lines (auto-added for open sofa sides). On sofa/longchair/cornerElement, AVC/AVO/AVU without explicit position expand to ONE PER CUSHION at the cushion centers (numbered 1..n); `per` picks seat cushions (default) or back cushions/bands — the counts differ on the cornerElement.',
58315
- items: {
58316
- type: 'object',
58317
- properties: {
58318
- type: {
58319
- type: 'string',
58320
- "enum": ['AVL', 'AVR', 'AVC', 'AVN', 'AVO', 'AVS', 'AVU'],
58321
- description: 'connector family (L↔R, N↔S, O↔U, C↔C)'
58322
- },
58323
- number: {
58324
- type: 'number',
58325
- description: 'pairing number (AVU1 docks AVO1)'
58326
- },
58327
- position: {
58328
- type: 'number',
58329
- description: '0..1 along the owning edge. Default: AVL/AVR at the BACK edge (0 — different-depth modules align at the back); others 0.5'
58330
- },
58331
- positionY: {
58332
- type: 'number',
58333
- description: 'AVC/AVO/AVU: 0..1 along the depth axis (default 0.5)'
58334
- },
58335
- per: {
58336
- type: 'string',
58337
- "enum": ['seat', 'back', 'front'],
58338
- description: "expansion target on sofa/longchair/corner templates (default 'seat' = seat-cushion centers). ZUBEHÖR-ANKER: 'back' = one AVO per BACK cushion (headrest anchors; a corner gets 2 — one per band, the side one rotated), 'front' = one AVO per seat cushion at its free FRONT edge (footrest anchors; a corner gets 0). The accessory article carries the matching AVU (headrest: centered default; footrest: positionY 0 so it lands IN FRONT). Catalog wiring required: the base item's accessoires list + a different layer"
58339
- },
58340
- ignoreLayer: {
58341
- type: 'boolean',
58342
- description: 'docks regardless of layer (_IL marker)'
58343
- },
58344
- direction: {
58345
- type: 'string',
58346
- "enum": ['down', 'up', 'left', 'right'],
58347
- description: "line direction p1→p2 = docking ROTATION (down = 0°, clockwise: left 90°, up 180°, right 270°; default down). Production SVGs use e.g. a horizontal 'left' AVR at the FRONT corner (position 1) for front-aligned docking"
58348
- },
58349
- lengthCm: {
58350
- type: 'number',
58351
- description: 'line length in cm (cosmetic — the planner reads p1 + direction; default 3.5)'
58352
- },
58353
- unnumbered: {
58354
- type: 'boolean',
58355
- description: "emit the id WITHOUT numeric suffix (plain 'AVR' — common in hand-drawn production SVGs)"
58356
- }
58357
- },
58358
- required: ['type']
58359
- }
58360
- },
58361
- functionalOverhangCm: {
58362
- type: 'object',
58363
- description: 'extends the FUNCTIONAL footprint (OLF) beyond the visible body, in cm — the planner reserves this space',
58364
- properties: {
58365
- left: {
58366
- type: 'number'
58367
- },
58368
- right: {
58369
- type: 'number'
58370
- },
58371
- front: {
58372
- type: 'number',
58373
- description: 'e.g. pull-out bed space in front of a couch'
58374
- },
58375
- back: {
58376
- type: 'number'
58377
- }
58378
- }
58379
- },
58380
- stretchable: {
58381
- type: 'boolean',
58382
- description: 'emit SAH/SAV stretch areas so the article resizes (default true)'
58383
- },
58384
- style: {
58385
- type: 'object',
58386
- description: "manufacturer drawing style (JSON, all fields optional). preset: 'classic' (filled gray parts + cushion rects, default) | 'outline' (technical supplier line drawing: white body, thin strokes, seat SEAMS, scalloped front, dashed bed zone WITHOUT icon — icons are OPT-IN via functionFootprint.icon, draw one ONLY if the supplier PDF shows it) | 'flat' (color blocks, no strokes). Overrides on top: base {fill,stroke,strokeWidthCm,cornerRadiusCm,dashCm:[..],draw} for all parts; parts.{body|arm|back|seatCushion|backCushion|seam|headboard|bedDetail|functionFootprint|label} same fields per part; cushionMode 'outline'|'seams'|'none'; backBand {mode:'rect'|'line',sagCm,topOffsetCm,mitre} — 'line' draws the backrest as a sagging cushion-front LINE instead of a band; mitre = 45° joint where a corner's back+side bands meet (default true for 'line', false for 'rect'); frontEdge {mode:'straight'|'scallop',amplitudeCm}; functionFootprint {mode:'none'|'dashed',icon:'bedBox'|'arrowFront'|'arrowBack'|'curvedArrow'|'none'} — draws the functionalOverhangCm zone visibly the way supplier catalogs mark pull-out beds; symbols [{symbol:'bedBox'|'arrowFront'|'arrowBack'|'curvedArrow'|'triangle',x,y,sizeCm,rotateDeg,stroke}] with x/y 0..1 relative to the article; gradients [{id,angleDeg,stops:[{offset,color}]}] referenced from any fill as 'url(#id)'."
58387
- },
58388
- styleUrl: {
58389
- type: 'string',
58390
- description: "URL of a stored style-config JSON (e.g. a media item uploaded via uploadAsset) — the 'design once per manufacturer, reference everywhere' flow. Fetched as the base config; inline 'style' fields override it."
58391
- },
58392
- canvasCm: {
58393
- type: 'number',
58394
- description: "SQUARE canvas edge in cm for ARTICLE-LIST images: the drawing is centered in a canvasCm×canvasCm frame, so every article rendered with the SAME canvasCm shares ONE scale and the article list shows true size differences. SERIE WORKFLOW: first read all articles' measures, take the LARGEST extent (width or depth, incl. functional overhang — e.g. a 250cm 4-seater → 260), then pass that SAME canvasCm to every generateArticleSvg call of the serie/session. NOT for the planner top view: canvas images belong in 'images' (format 'jpg' targets that by default)"
58395
- },
58396
- format: {
58397
- type: 'string',
58398
- "enum": ['svg', 'jpg'],
58399
- description: "'svg' (default) = planner top view (attaches to svgs). 'jpg' = rasterized article-list picture on white background — attaches to 'images' by default; combine with canvasCm for a serie-uniform scale"
58400
- },
58401
- jpgSizePx: {
58402
- type: 'number',
58403
- description: 'jpg raster width in px (default 1024; height follows the aspect ratio)'
58404
- },
58405
- column: {
58406
- type: 'string',
58407
- description: "attach column override (defaults: svg → 'svgs', jpg → 'images')"
58408
- },
58409
- fill: {
58410
- type: 'string',
58411
- description: 'LEGACY body fill shortcut — prefer style.parts.body.fill'
58412
- },
58413
- stroke: {
58414
- type: 'string',
58415
- description: 'LEGACY outline color shortcut — prefer style.base.stroke'
58416
- },
58417
- label: {
58418
- type: 'string',
58419
- description: 'short text rendered in the center (e.g. the typeNo)'
58420
- },
58421
- typeNo: {
58422
- type: 'string',
58423
- description: "attach to this item's svgs (items view must be on screen)"
58424
- },
58425
- grid: {
58426
- type: 'string',
58427
- description: "items table label when it isn't 'items' (subtable label from listGrids)"
58428
- },
58429
- attach: {
58430
- type: 'boolean',
58431
- description: 'false = only generate + upload, do not attach'
58432
- },
58433
- mode: {
58434
- type: 'string',
58435
- "enum": ['append', 'replace'],
58436
- description: "how the attach writes the asset column: 'append' (default) keeps what is there, 'replace' makes this the ONLY entry — use replace when regenerating a serie, otherwise the superseded supplier image stays first and the list keeps showing it"
58437
- },
58438
- fileName: {
58439
- type: 'string',
58440
- description: "file name (default 'top-<typeNo>.svg')"
58441
- },
58442
- returnSvg: {
58443
- type: 'boolean',
58444
- description: 'false = leave the SVG markup out of the answer (ids only) — use it for rollouts, the markup is large'
58445
- },
58446
- batch: {
58447
- type: 'array',
58448
- description: 'WHOLE SERIE IN ONE CALL: one entry per article, each with its own template/widthCm/depthCm/seats/arms/connectors/typeNo/fileName. style, styleUrl, format, canvasCm, jpgSizePx, grid and column are taken from the TOP LEVEL and inherited by every entry (a styleUrl is fetched once). Nothing is attached and no markup is returned — the answer carries one {typeNo, mediaItemId, url, connectors, warnings} per article, which you then write with ONE setAssetCell cells:[…] (a single approval bar for the serie). A failing entry lands in `failed` and does not stop the rest. Max 60 per call.',
58449
- items: {
58450
- type: 'object'
58451
- }
58452
- }
58453
- },
58454
- required: []
58455
- },
58456
- argAliases: GRID_ARG_ALIASES,
58457
- requiresEditPermission: true
58458
- }, {
58459
- name: 'getAssetUrls',
58460
- description: 'Resolve media item ids to their downloadable URL, file name and mime type in ONE call. Asset cells carry only the id and cut their preview at 110 characters, so the URL of an image is never readable off the grid — read the ids from the asset cell (locateRow.firstRow / readGridRows) and pass them here. Ids the media service does not know are listed under `missing`. Read-only: nothing is uploaded or written. At most 50 ids per call.',
58461
- input_schema: {
58462
- type: 'object',
58463
- properties: {
58464
- mediaItemIds: {
58465
- type: 'array',
58466
- items: {
58467
- type: 'string'
58468
- },
58469
- description: 'media item _ids as stored in an asset cell (mediaitemId)'
58470
- }
58471
- },
58472
- required: ['mediaItemIds']
58473
- }
58474
- }, {
58475
- name: 'publishCatalogTestManifest',
58476
- description: "ARCHIVE a catalog test manifest and get the durable URL runCatalogTests should be run from. This is the counterpart of running the tests: a manifest that exists only as a local file dies with the machine that built it, and with it the supplier expectations, the generator and the run log — so publishing is part of every run, not an afterthought. The manifest itself NEVER passes through the conversation: give `sourceUrl` (a local dev-server URL, or the manifest's own media URL when updating it) and the browser fetches it. Three things happen in one call, so the archive cannot end up half-updated: PROVENANCE is enforced (meta.catalogCodex, meta.source and meta.generator.script must be present — an anonymous spec cannot be rebuilt from the next supplier delivery and is refused), the run log is extended (pass runCatalogTests' returned `historyEntry` as `appendHistory`), and the file is uploaded. Returns the new URL plus a small summary — record the URL, it is what the next session, a colleague or a CI run fetches. Publishing creates a NEW immutable file each time; the previous version stays reachable.",
58477
- input_schema: {
58478
- type: 'object',
58479
- properties: {
58480
- sourceUrl: {
58481
- type: 'string',
58482
- description: 'URL the browser fetches the manifest JSON from (local dev server, or the current media URL when updating).'
58483
- },
58484
- manifest: {
58485
- type: 'object',
58486
- description: 'The manifest inline — only for a small hand-written one. Prefer sourceUrl; a real manifest must not enter the conversation.'
58487
- },
58488
- fileName: {
58489
- type: 'string',
58490
- description: "Target file name, ending in .json (e.g. 'helming-serie1.tests.json')."
58491
- },
58492
- appendHistory: {
58493
- type: 'object',
58494
- description: "The `historyEntry` object returned by runCatalogTests — appended to the manifest's `history`."
58495
- },
58496
- meta: {
58497
- type: 'object',
58498
- description: 'Provenance to set or merge: { catalogCodex, catalogName?, source, created?, generator: { name?, language?, inputs?[], script }, notes? }. `source` names the supplier delivery, `generator.script` is the generator VERBATIM. Values already in the manifest are kept unless overwritten here.'
58499
- },
58500
- mediaType: {
58501
- type: 'string',
58502
- description: "Media-service type code for the JSON (default 'DOC'). Needed only if the service's mimeToMediaType config maps application/json to a code other than DOC; it cannot help when the mime type is unmapped altogether."
58503
- }
58504
- },
58505
- required: ['fileName']
58506
- },
58507
- requiresEditPermission: true
58508
- }];
57559
+ /** The media/asset tools this toolset executes — defined by the diva AI service (tools/browser/media.ts). */
57560
+ var MEDIA_TOOL_NAMES = ['uploadAsset', 'generateImageAsset', 'setAssetCell', 'generateArticleSvg', 'getAssetUrls', 'publishCatalogTestManifest'];
58509
57561
  /** Media types the media service pipeline understands, keyed by file extension (subset of DivaFile's map). */
58510
57562
  var MEDIA_TYPE_BY_EXTENSION = {
58511
57563
  svg: 'SVG',
@@ -60665,7 +59717,7 @@ function createMediaToolset(ctx) {
60665
59717
  };
60666
59718
  return {
60667
59719
  useCase: 'backoffice',
60668
- tools: MEDIA_TOOL_DEFS,
59720
+ toolNames: MEDIA_TOOL_NAMES,
60669
59721
  dispatch: function () {
60670
59722
  var _dispatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(name, input, signal) {
60671
59723
  var args, notStartedNote, uploadOne, startedAt, results, remaining, _iterator, _step, _request$fileName, entry, request, fileName, failed, result, imageCount, host, approved, _startedAt, _results, _remaining, usage, _iterator2, _step2, _entry$fileName, _entry$prompt, raw, _entry, label, one, _failed, _args$mediaItemId, MODE_SYNONYMS, parseAssetMode, _args$keyColumn, _args$column, _topMode$mode, topMode, badEntryModes, batchEntries, invalidIds, mediaItemId, parsedMode, mode, _args$format, _args$fileName, _args$grid, _generated$canvasCm, storedStyle, response, fetched, recipe, _response, _fetched, active, _i, _Object$entries, _Object$entries$_i, key, value, generated, spec, inline, typeNo, format, extension, rawName, _fileName, uploaded, file, attachColumn, attachResult;
@@ -96102,50 +95154,8 @@ function _objectSpread$5(e) { for (var r = 1; r < arguments.length; r++) { var t
96102
95154
 
96103
95155
  /** What the toolset acts on: the catalog or package a view is bound to, and that view's serie/item selection and setters. */
96104
95156
 
96105
- /** A serie/item change reloads the planner, which takes seconds — a result sent after 3 s let selectItem hit the previous serie. */
96106
- var SELECTION_SETTLE = {
96107
- timeoutMs: 15000
96108
- };
96109
-
96110
- /** Definitions of the serie/item selection tools this toolset executes — sent to the backend per turn. */
96111
- var BACKOFFICE_TOOL_DEFS = [{
96112
- name: 'listSeries',
96113
- description: 'List the series (models) of the current backoffice catalog/package with serieNo and name, plus the currently selected serie/item. Configurator-entry tool: only meaningful INSIDE a catalog/package editor, as the first step of deliberate engine work (selectSerie next) — for data/inventory questions use the table views instead.',
96114
- input_schema: {
96115
- type: 'object',
96116
- properties: {}
96117
- }
96118
- }, {
96119
- name: 'selectSerie',
96120
- description: 'Select a serie (model) in the backoffice — the planner instance reloads with it and the turn ends automatically. It does NOT navigate: the current view stays; serie-scoped views (items, prices) pick the selection up, but switching views needs a separate navigateTo. Announce the selection to the user BEFORE calling.',
96121
- input_schema: {
96122
- type: 'object',
96123
- properties: {
96124
- serieNo: {
96125
- type: 'number',
96126
- description: 'serieNo from listSeries'
96127
- }
96128
- },
96129
- required: ['serieNo']
96130
- },
96131
- endsTurn: true,
96132
- settle: SELECTION_SETTLE
96133
- }, {
96134
- name: 'selectItem',
96135
- description: 'Select an item (article) of the current serie in the backoffice — the planner instance reloads with it and the turn ends automatically. typeNo = typeNr from findPlannableArticle. Announce the selection to the user BEFORE calling.',
96136
- input_schema: {
96137
- type: 'object',
96138
- properties: {
96139
- typeNo: {
96140
- type: 'string',
96141
- description: 'the item/article type number'
96142
- }
96143
- },
96144
- required: ['typeNo']
96145
- },
96146
- endsTurn: true,
96147
- settle: SELECTION_SETTLE
96148
- }];
95157
+ /** The selection tools this toolset executes — defined by the diva AI service (tools/browser/backoffice.ts). */
95158
+ var BACKOFFICE_TOOL_NAMES = ['listSeries', 'selectSerie', 'selectItem'];
96149
95159
 
96150
95160
  /** Toolset that drives the backoffice serie/item selection through the same context setters the WYSIWYG dropdowns use. */
96151
95161
  function createBackofficeToolset(ctx) {
@@ -96206,7 +95216,7 @@ function createBackofficeToolset(ctx) {
96206
95216
  };
96207
95217
  return {
96208
95218
  useCase: 'backoffice',
96209
- tools: BACKOFFICE_TOOL_DEFS,
95219
+ toolNames: BACKOFFICE_TOOL_NAMES,
96210
95220
  dispatch: function () {
96211
95221
  var _dispatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(name, input) {
96212
95222
  var args, _bound$elementProps$s, _bound$elementProps$s2, _bound$elementProps$i, _bound$elementProps$i2, bound, series, unbound, _bound, onSerieChange, _series, target, _binding, _args$typeNo, onItemChange, typeNo;
@@ -96395,103 +95405,9 @@ var BLOCK_TYPES = ['Title', 'RichText', 'URL', 'Image', 'Video', 'Gallery', 'Wra
96395
95405
 
96396
95406
  /** Media item _ids are nanoids; legacy 24-hex ObjectIds also occur (same rule as setAssetCell). */
96397
95407
  var MEDIA_ID = /^[A-Za-z0-9_-]{10,64}$/;
96398
- var CONTENT_BLOCK_SCHEMA = {
96399
- type: 'object',
96400
- description: "ONE content block. type: 'Title' | 'RichText' | 'URL' | 'Image' | 'Video' | 'Gallery' | 'Wrapper' | 'QuickConfig'. Fields by type — Title/RichText: text (language map {\"DE\": \"…\"}; RichText takes simple HTML). URL: url (+ optional text). Image: image = the asset's URL as ONE PLAIN STRING (uploadAsset returns it as 'url'; media sources are never language-resolved) + optional mediaItemImage = its mediaItemId (+ optional altText, cover). Video: video = URL string + optional mediaItemVideo = its mediaItemId (+ optional loop). Gallery: content = array of Image/Video blocks. Wrapper: content = array of nested blocks. QuickConfig: config = the QuickConfig JSON — read getKnowhow('quickconfig-json-schema') BEFORE authoring one; the config is stored unvalidated."
96401
- };
96402
- var CONTENT_TOOL_DEFS = [{
96403
- name: 'listContentItems',
96404
- description: "List the organization's content items (CMS records referenced by CONTENT_ITEM / GROUP_CONTENT_ITEM / CONTENT_ITEM_TEASER properties and additionalGroupFilter entries): _id, codex, description and block types. Use it to find an existing item to reference or edit, and to check a codex is free before createContentItem. query filters by codex/description substring.",
96405
- input_schema: {
96406
- type: 'object',
96407
- properties: {
96408
- query: {
96409
- type: 'string',
96410
- description: 'optional codex/description substring filter'
96411
- }
96412
- },
96413
- additionalProperties: false
96414
- }
96415
- }, {
96416
- name: 'getContentItem',
96417
- description: 'Read ONE content item with its full content blocks (raw language maps — what you would edit). Accepts the _id or the codex. Read it before updateContentItem: updates REPLACE the whole content array.',
96418
- input_schema: {
96419
- type: 'object',
96420
- properties: {
96421
- idOrCodex: {
96422
- type: 'string',
96423
- description: 'content item _id or codex'
96424
- }
96425
- },
96426
- required: ['idOrCodex'],
96427
- additionalProperties: false
96428
- }
96429
- }, {
96430
- name: 'createContentItem',
96431
- description: "Create a content item from content BLOCKS (rich text/media/QuickConfig records shown in configurator info panels, teasers and notifications). On success the WYSIWYG preview opens AUTOMATICALLY for the user (the result note says where) — do not ask whether to show it. The item is created in the CURRENT organization and is UNUSED until referenced: wire it via the property mechanism — a CONTENT_ITEM / GROUP_CONTENT_ITEM property whose value is the codex (or _id), or a CONTENT_ITEM_TEASER JSON whose id equals the contentItemId (value shapes: getKnowhow catalog/option properties docs). Give it a CODEX — properties reference by codex most readably. Image/Video blocks take the asset URL from uploadAsset (plain string). For QuickConfig blocks read getKnowhow('quickconfig-json-schema') first.",
96432
- input_schema: {
96433
- type: 'object',
96434
- properties: {
96435
- codex: {
96436
- type: 'string',
96437
- description: "unique key other records reference (e.g. 'ci_bezug_intro'); checked against the organization's existing items"
96438
- },
96439
- description: {
96440
- type: 'string',
96441
- description: 'internal description shown in the content-item list'
96442
- },
96443
- content: {
96444
- type: 'array',
96445
- description: 'the content blocks in display order',
96446
- items: CONTENT_BLOCK_SCHEMA
96447
- }
96448
- },
96449
- required: ['content'],
96450
- additionalProperties: false
96451
- },
96452
- requiresEditPermission: true
96453
- }, {
96454
- name: 'showContentItem',
96455
- description: 'Show an EXISTING content item VISUALLY to the user in the WYSIWYG preview tool (createContentItem/updateContentItem already open the preview themselves — this tool is for presenting an item during a discussion or after listContentItems). Accepts the _id or codex. The preview opens WITHOUT hiding this chat: as a separate browser window when another tool is active (a popup blocker may keep it docked in the right rail instead — the result tells you what happened, relay it). Also selects the item in the ContentItem library, so an open library table follows along.',
96456
- input_schema: {
96457
- type: 'object',
96458
- properties: {
96459
- idOrCodex: {
96460
- type: 'string',
96461
- description: 'content item _id or codex'
96462
- }
96463
- },
96464
- required: ['idOrCodex'],
96465
- additionalProperties: false
96466
- }
96467
- }, {
96468
- name: 'updateContentItem',
96469
- description: 'Update a content item (codex, description and/or the FULL content block array — content is REPLACED, not merged: getContentItem first and resend every block you keep). This edits LIVE content that referencing properties already render — ANNOUNCE the intended change to the user BEFORE calling. The user approves the write on the ContentItem library table (one approval bar; the tool blocks until they decide) — if that table is not on screen the tool says so instead of writing. Deleting content items is not offered — that is a user action.',
96470
- input_schema: {
96471
- type: 'object',
96472
- properties: {
96473
- idOrCodex: {
96474
- type: 'string',
96475
- description: 'content item _id or codex'
96476
- },
96477
- codex: {
96478
- type: 'string',
96479
- description: 'new codex (careful: referencing properties that use the OLD codex break)'
96480
- },
96481
- description: {
96482
- type: 'string'
96483
- },
96484
- content: {
96485
- type: 'array',
96486
- description: 'the COMPLETE new block array (replaces the stored one)',
96487
- items: CONTENT_BLOCK_SCHEMA
96488
- }
96489
- },
96490
- required: ['idOrCodex'],
96491
- additionalProperties: false
96492
- },
96493
- requiresEditPermission: true
96494
- }];
95408
+
95409
+ /** The content-item tools this toolset executes — defined by the diva AI service (tools/browser/content.ts). */
95410
+ var CONTENT_TOOL_NAMES = ['listContentItems', 'getContentItem', 'createContentItem', 'showContentItem', 'updateContentItem'];
96495
95411
  /** Uppercase the language keys of a {lang: text} map — lowercase keys validate fine but render EMPTY. */
96496
95412
  function normalizeLangKeys(value) {
96497
95413
  if (!value || _typeof(value) !== 'object' || Array.isArray(value)) return value;
@@ -96820,7 +95736,7 @@ function createContentToolset(ctx) {
96820
95736
  };
96821
95737
  return {
96822
95738
  useCase: 'backoffice',
96823
- tools: CONTENT_TOOL_DEFS,
95739
+ toolNames: CONTENT_TOOL_NAMES,
96824
95740
  dispatch: function () {
96825
95741
  var _dispatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5(name, input, signal) {
96826
95742
  var args, _args$query, items, q, matched, _args$idOrCodex, _item$content, idOrCodex, item, errors, organizationId, codex, existing, created, previewNote, _args$idOrCodex2, _item$codex4, _idOrCodex, _item, _previewNote, _args$idOrCodex3, _idOrCodex2, _existing, patch, _errors, collision, _existing$codex, library, approved, updated, _previewNote2;