@crystaldesign/diva-backoffice 26.13.0-beta.28 → 26.13.0-beta.29

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.
@@ -31374,9 +31374,11 @@ function agentAccess(hasPermission, license) {
31374
31374
  var holds = function holds(object, flag) {
31375
31375
  return hasPermission("".concat(object, "_internal")) || hasPermission(object) && (license === null || license === void 0 ? void 0 : license[flag]) === true;
31376
31376
  };
31377
- var chat = holds('diva_advisor', 'enableDivaAdvisor') || holds('diva_agent', 'enableDivaAgent');
31377
+ var edit = holds('diva_agent', 'enableDivaAgent');
31378
+ var chat = holds('diva_advisor', 'enableDivaAdvisor') || edit;
31378
31379
  return {
31379
31380
  chat: chat,
31381
+ edit: edit,
31380
31382
  mcp: chat && hasPermission('diva_agent_mcp_internal')
31381
31383
  };
31382
31384
  }
@@ -36344,7 +36346,7 @@ var ZoomWrapper = function ZoomWrapper(_ref) {
36344
36346
  size: 'small'
36345
36347
  }), /*#__PURE__*/jsx(Button, {
36346
36348
  onClick: function onClick() {
36347
- return zoomOut(1);
36349
+ return zoomOut();
36348
36350
  },
36349
36351
  type: "default",
36350
36352
  icon: /*#__PURE__*/jsx(MinusCircleOutlined, {
@@ -76296,8 +76298,8 @@ var useLoadingModal = function useLoadingModal() {
76296
76298
 
76297
76299
  /**
76298
76300
  * Fetches organizations related to the given organization and filters them down to the ones eligible
76299
- * for automatic publishing of the package (either explicitly enabled for this package, or having both
76300
- * access to the package and automaticPublishing enabled on their own organization settings).
76301
+ * for automatic publishing of the package: organizations with access to the package that have automatic publishing
76302
+ * enabled either for this package or on their own organization settings.
76301
76303
  */
76302
76304
  function fetchAutomaticPublishingOrganizations(_x) {
76303
76305
  return _fetchAutomaticPublishingOrganizations.apply(this, arguments);
@@ -76334,11 +76336,9 @@ function _fetchAutomaticPublishingOrganizations() {
76334
76336
  return o._id === organizationId;
76335
76337
  });
76336
76338
  currentOrgParentIds = (currentOrg === null || currentOrg === void 0 ? void 0 : currentOrg.parentOrganizations) || [];
76337
- isOwner = packageData.organizationId === organizationId; // Show organizations that are:
76338
- // 1. In package settings with AutomaticPublishing === true, OR
76339
- // 2. Has access to the package AND have automaticPublishing === true in their own organization settings
76339
+ isOwner = packageData.organizationId === organizationId;
76340
76340
  return _context.abrupt("return", (result.data || []).filter(function (org) {
76341
- var _packageData$publishe2, _packageData$dependin, _packageData$dependin2, _packageData$settings;
76341
+ var _packageData$publishe2, _packageData$dependin, _packageData$dependin2, _packageData$publishe3, _packageData$settings;
76342
76342
  // EXCLUDE the current organization
76343
76343
  if (org._id === organizationId) {
76344
76344
  return false;
@@ -76363,7 +76363,8 @@ function _fetchAutomaticPublishingOrganizations() {
76363
76363
 
76364
76364
  //an organization inherits any publication in its parent chain automatically (same rule as the
76365
76365
  //server-side auto-publish skip), so automatic publishing only makes sense for it when one of its
76366
- //own packages is based on this package
76366
+ //own packages is based on this package - or when it has an own published entry, which shadows the inherited
76367
+ //publication and goes stale unless it is refreshed (the server keeps refreshing such an entry as well)
76367
76368
  var publishingOrgIds = [organizationId].concat(_toConsumableArray(Object.keys((_packageData$publishe2 = packageData.published) !== null && _packageData$publishe2 !== void 0 ? _packageData$publishe2 : {})));
76368
76369
  var inheritsAPublication = orgParentIds.some(function (parentId) {
76369
76370
  return parentId !== org._id && publishingOrgIds.includes(parentId);
@@ -76371,16 +76372,22 @@ function _fetchAutomaticPublishingOrganizations() {
76371
76372
  var hasDependingPackage = (_packageData$dependin = (_packageData$dependin2 = packageData.dependingPackages) === null || _packageData$dependin2 === void 0 ? void 0 : _packageData$dependin2.some(function (dependingPackage) {
76372
76373
  return dependingPackage.organizationId === org._id;
76373
76374
  })) !== null && _packageData$dependin !== void 0 ? _packageData$dependin : false;
76374
- if (inheritsAPublication && !hasDependingPackage) {
76375
+ var hasOwnPublishedEntry = !!((_packageData$publishe3 = packageData.published) !== null && _packageData$publishe3 !== void 0 && _packageData$publishe3[org._id]);
76376
+ if (inheritsAPublication && !hasDependingPackage && !hasOwnPublishedEntry) {
76375
76377
  return false;
76376
76378
  }
76377
- var hasAutomaticPublishingForPackage = ((_packageData$settings = packageData.settings) === null || _packageData$settings === void 0 || (_packageData$settings = _packageData$settings[org._id]) === null || _packageData$settings === void 0 ? void 0 : _packageData$settings.automaticPublishing) === true;
76378
- var hasAccessToPackage = orgParentIds.includes(packageData.organizationId) || allowedOrgIds.includes(org._id) || allowedOrgIds.some(function (id) {
76379
+
76380
+ //only organizations the server would auto-publish for (owner's or allowed organization's subtree, see
76381
+ //HandleAutoPublishingForOrganizations) - the complete package lists the entries and settings of every organization.
76382
+ //The publishing organization has access itself, so its own subtree counts too (a package row only keeps its own
76383
+ //allowed entry)
76384
+ var hasAccessToPackage = orgParentIds.includes(packageData.organizationId) || orgParentIds.includes(organizationId) || allowedOrgIds.includes(org._id) || allowedOrgIds.some(function (id) {
76379
76385
  return orgParentIds.includes(id);
76380
76386
  });
76381
- var hasAutomaticPublishing = org.automaticPublishing === true;
76382
- var hasAccessToPackageAndAutomaticPublishing = hasAccessToPackage && hasAutomaticPublishing;
76383
- return hasAutomaticPublishingForPackage || hasAccessToPackageAndAutomaticPublishing;
76387
+ if (!hasAccessToPackage) {
76388
+ return false;
76389
+ }
76390
+ return ((_packageData$settings = packageData.settings) === null || _packageData$settings === void 0 || (_packageData$settings = _packageData$settings[org._id]) === null || _packageData$settings === void 0 ? void 0 : _packageData$settings.automaticPublishing) === true || org.automaticPublishing === true;
76384
76391
  }));
76385
76392
  case 15:
76386
76393
  case "end":
@@ -76579,42 +76586,71 @@ function usePackagePublishing(_ref) {
76579
76586
  }, basePublishParams));
76580
76587
  var disabled = isPublishing || !(data !== null && data !== void 0 && data.basedCatalogId) && !(data !== null && data !== void 0 && data.basedPackageId) || !(data !== null && data !== void 0 && data.name) || isInherited || servedByBase && !baseChangesPending;
76581
76588
  var fetchOrganizationsWithAutomaticPublishing = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
76582
- var filtered;
76589
+ var packageData, packageResponse, filtered;
76583
76590
  return _regeneratorRuntime.wrap(function _callee$(_context) {
76584
76591
  while (1) switch (_context.prev = _context.next) {
76585
76592
  case 0:
76586
76593
  setLoadingOrganizations(true);
76587
76594
  _context.prev = 1;
76588
- _context.next = 4;
76595
+ //the packages list loads only the current organization's publish entry and settings, but the selection depends on
76596
+ //those of the other organizations (an own published entry, automatic publishing for the package); without the
76597
+ //full package the row's data still serves
76598
+ packageData = data;
76599
+ _context.prev = 3;
76600
+ _context.next = 6;
76601
+ return fetch("".concat(apiConfig.enricherService, "/packages/").concat(packageId), {
76602
+ headers: {
76603
+ Authorization: "Bearer ".concat(root.dataStore.jwt)
76604
+ }
76605
+ });
76606
+ case 6:
76607
+ packageResponse = _context.sent;
76608
+ if (!packageResponse.ok) {
76609
+ _context.next = 11;
76610
+ break;
76611
+ }
76612
+ _context.next = 10;
76613
+ return packageResponse.json();
76614
+ case 10:
76615
+ packageData = _context.sent;
76616
+ case 11:
76617
+ _context.next = 16;
76618
+ break;
76619
+ case 13:
76620
+ _context.prev = 13;
76621
+ _context.t0 = _context["catch"](3);
76622
+ packageData = data;
76623
+ case 16:
76624
+ _context.next = 18;
76589
76625
  return fetchAutomaticPublishingOrganizations({
76590
76626
  authServiceUrl: apiConfig.authService,
76591
76627
  organizationId: organizationId,
76592
76628
  jwt: root.dataStore.jwt,
76593
- packageData: data
76629
+ packageData: packageData
76594
76630
  });
76595
- case 4:
76631
+ case 18:
76596
76632
  filtered = _context.sent;
76597
76633
  setAvailableOrganizations(filtered);
76598
76634
  setSelectedOrganizationIds(filtered.map(function (org) {
76599
76635
  return org._id;
76600
76636
  }));
76601
76637
  return _context.abrupt("return", filtered);
76602
- case 10:
76603
- _context.prev = 10;
76604
- _context.t0 = _context["catch"](1);
76605
- modalState.showErrorModal("Error fetching organizations: ".concat(_context.t0 instanceof Error ? _context.t0.message : String(_context.t0)));
76638
+ case 24:
76639
+ _context.prev = 24;
76640
+ _context.t1 = _context["catch"](1);
76641
+ modalState.showErrorModal("Error fetching organizations: ".concat(_context.t1 instanceof Error ? _context.t1.message : String(_context.t1)));
76606
76642
  setAvailableOrganizations([]);
76607
76643
  return _context.abrupt("return", []);
76608
- case 15:
76609
- _context.prev = 15;
76644
+ case 29:
76645
+ _context.prev = 29;
76610
76646
  setLoadingOrganizations(false);
76611
- return _context.finish(15);
76612
- case 18:
76647
+ return _context.finish(29);
76648
+ case 32:
76613
76649
  case "end":
76614
76650
  return _context.stop();
76615
76651
  }
76616
- }, _callee, null, [[1, 10, 15, 18]]);
76617
- })), [apiConfig.authService, organizationId, root.dataStore.jwt, modalState, data]);
76652
+ }, _callee, null, [[1, 24, 29, 32], [3, 13]]);
76653
+ })), [apiConfig.authService, apiConfig.enricherService, packageId, organizationId, root.dataStore.jwt, modalState, data]);
76618
76654
  var performPublish = React.useCallback(/*#__PURE__*/function () {
76619
76655
  var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(publish) {
76620
76656
  var automaticPublishingOrgIds,
@@ -83293,7 +83329,7 @@ function createNavigationToolset(ctx) {
83293
83329
  toolNames: NAVIGATION_TOOL_NAMES,
83294
83330
  // Structural facts read fresh per turn; the backend formats them into its dynamic prompt sections.
83295
83331
  getFacts: function getFacts() {
83296
- var _root$dataStore;
83332
+ var _root$contextStore$pe2, _root$dataStore;
83297
83333
  var _currentEditorIds2 = currentEditorIds(root, ctx),
83298
83334
  catalogId = _currentEditorIds2.catalogId,
83299
83335
  packageId = _currentEditorIds2.packageId;
@@ -83310,11 +83346,15 @@ function createNavigationToolset(ctx) {
83310
83346
  })
83311
83347
  } : undefined;
83312
83348
  };
83349
+ // Peek, never seed: the catalog editor owns that context. Its record may still be the bare id from the route.
83350
+ var openCatalog = (_root$contextStore$pe2 = root.contextStore.peekContext('catalog')) === null || _root$contextStore$pe2 === void 0 ? void 0 : _root$contextStore$pe2.selectedCatalog;
83313
83351
  return {
83314
83352
  catalogId: catalogId,
83353
+ catalogName: catalogId && (openCatalog === null || openCatalog === void 0 ? void 0 : openCatalog._id) === catalogId ? openCatalog.name || undefined : undefined,
83315
83354
  // A reload or a cross-catalog navigateTo can switch the organization silently — name it with every answer.
83316
83355
  organizationId: (_root$dataStore = root.dataStore) === null || _root$dataStore === void 0 ? void 0 : _root$dataStore.selectedOrganizationId,
83317
83356
  currentPath: root.navigationState.path,
83357
+ supportUrl: ctx.supportUrl,
83318
83358
  grids: root.gridRegistry.entries.map(function (entry) {
83319
83359
  var _handle$getDivaColumn, _handle$getDivaColumn2, _handle$getDivaColumn3, _handle$getDivaColumn4, _entry$getActions, _entry$getActions2;
83320
83360
  var handle = entry.getHandle();
@@ -88899,11 +88939,11 @@ function _showEntityFromLink() {
88899
88939
  return _showEntityFromLink.apply(this, arguments);
88900
88940
  }
88901
88941
 
88902
- function ownKeys$y(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
88903
- function _objectSpread$y(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$y(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$y(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
88904
88942
  function _createForOfIteratorHelper$g(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$g(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
88905
88943
  function _unsupportedIterableToArray$g(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$g(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$g(r, a) : void 0; } }
88906
88944
  function _arrayLikeToArray$g(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; }
88945
+ function ownKeys$y(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
88946
+ function _objectSpread$y(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$y(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$y(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
88907
88947
 
88908
88948
  /** The media/asset tools this toolset executes — defined by the diva AI service (tools/browser/media.ts). */
88909
88949
  var MEDIA_TOOL_NAMES = ['uploadAsset', 'generateImageAsset', 'setAssetCell', 'generateArticleSvg', 'getAssetUrls', 'publishCatalogTestManifest'];
@@ -89236,7 +89276,7 @@ function _uploadToMediaService() {
89236
89276
  }
89237
89277
  }, _callee5);
89238
89278
  }));
89239
- return function asText(_x47) {
89279
+ return function asText(_x52) {
89240
89280
  return _ref2.apply(this, arguments);
89241
89281
  };
89242
89282
  }();
@@ -89535,10 +89575,7 @@ function getAssetUrls(_x16, _x17, _x18) {
89535
89575
  return _getAssetUrls.apply(this, arguments);
89536
89576
  }
89537
89577
 
89538
- /**
89539
- * Generates ONE image through the DIVA AI service and stores it on the media service. The bytes
89540
- * never leave the browser — the caller only sees the `mediaItemId`, so no size cap applies here.
89541
- */
89578
+ /** A generated image is a media item only: reporting it as done would tell the user their articles have images. */
89542
89579
  function _getAssetUrls() {
89543
89580
  _getAssetUrls = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee9(root, args, signal) {
89544
89581
  var raw, ids, invalid, assets, missing, unresolved, _iterator3, _step3, _failure$reason, id, _yield$lookUpMediaIte2, info, failure;
@@ -89630,6 +89667,12 @@ function _getAssetUrls() {
89630
89667
  }));
89631
89668
  return _getAssetUrls.apply(this, arguments);
89632
89669
  }
89670
+ var NOT_ATTACHED_NOTE = 'NOT ATTACHED: no article, option or other row shows it yet. Images asked for rows are not done until setAssetCell wrote them — never report them as done before that.';
89671
+
89672
+ /**
89673
+ * Generates ONE image through the DIVA AI service and stores it on the media service. The bytes
89674
+ * never leave the browser — the caller only sees the `mediaItemId`, so no size cap applies here.
89675
+ */
89633
89676
  function generateImageAsset(_x19, _x20, _x21) {
89634
89677
  return _generateImageAsset.apply(this, arguments);
89635
89678
  }
@@ -89899,7 +89942,8 @@ function _generateImageAsset() {
89899
89942
  model: (_payload$model = (_payload4 = payload) === null || _payload4 === void 0 ? void 0 : _payload4.model) !== null && _payload$model !== void 0 ? _payload$model : model,
89900
89943
  finalPrompt: (_payload5 = payload) === null || _payload5 === void 0 ? void 0 : _payload5.finalPrompt,
89901
89944
  usage: (_payload$usageTrackin = (_payload6 = payload) === null || _payload6 === void 0 || (_payload6 = _payload6.usageTracking) === null || _payload6 === void 0 ? void 0 : _payload6.usageLimits) !== null && _payload$usageTrackin !== void 0 ? _payload$usageTrackin : undefined,
89902
- note: 'Generated and uploaded — the bytes stayed in the browser. LOOK at it before using it: open the url, or set it with setAssetCell and ' + 'check the tile. It is unused until referenced.'
89945
+ attached: false,
89946
+ note: 'Generated and uploaded — the bytes stayed in the browser. LOOK at it before using it: open the url, or set it with setAssetCell and ' + "check the tile. ".concat(NOT_ATTACHED_NOTE)
89903
89947
  }));
89904
89948
  case 106:
89905
89949
  _context10.prev = 106;
@@ -90162,6 +90206,11 @@ function _refusedAssetKeys() {
90162
90206
  return _refusedAssetKeys.apply(this, arguments);
90163
90207
  }
90164
90208
  /** Writes an asset cell (append/replace/remove) honoring the column's customParams shape — shared by the agent tools and the SVG generator UI. */
90209
+ /** The grid's marker for a sent row the server answered about neither way. */
90210
+ var NO_ANSWER = 'No answer from the server';
90211
+ var TAKEN_BACK_NOTE = ' The refused entry was taken back: the cell is as the server has it and nothing is left staged on the row.';
90212
+ var STILL_STAGED_NOTE = ' The refused entry is still STAGED in the cell, because the row also holds unsaved edits of the user — run discardStagedChanges on this table before writing the row again, or every later save of it sends the refused entry along.';
90213
+ var NOT_TAKEN_BACK_NOTE = ' The refused entry could not be taken back (the row is no longer on screen as it was) — check with getContext whether the table still holds staged changes before writing the row again.';
90165
90214
  var SKIPPED_NOTE = 'the commit did NOT send this row to the server (its grid row was gone, or it still carried validation errors) — locateRow it and re-run this key on its own';
90166
90215
 
90167
90216
  /** A confirmed clear already emptied the cell — a later failure on that row is NOT a no-op, and must say so. */
@@ -90182,11 +90231,15 @@ function assetWriteVerdict(outcome, nodeId) {
90182
90231
  if (failure) {
90183
90232
  // The server quotes a raw .NET pattern; an asset entry's text field is its media NAME (IDM caps it at 40 characters).
90184
90233
  var maxLength = patternLengthLimit(failure.errors.join(' '));
90185
- var lengthNote = maxLength ? " \u2014 the media name holds at most ".concat(maxLength, " characters: shorten it, and run discardStagedChanges on this table first, because the refused entry stays staged in the cell") : '';
90186
- return {
90234
+ var lengthNote = maxLength ? " \u2014 the media name holds at most ".concat(maxLength, " characters: shorten it") : '';
90235
+ return _objectSpread$y({
90187
90236
  state: 'rejected',
90188
90237
  error: "the server rejected the write: ".concat(failure.errors.join('; ') || 'no reason given').concat(lengthNote)
90189
- };
90238
+ }, failure.errors.length && failure.errors.every(function (error) {
90239
+ return error === NO_ANSWER;
90240
+ }) ? {
90241
+ unanswered: true
90242
+ } : {});
90190
90243
  }
90191
90244
  if (outcome !== null && outcome !== void 0 && (_outcome$skipped = outcome.skipped) !== null && _outcome$skipped !== void 0 && _outcome$skipped.includes(nodeId)) return {
90192
90245
  state: 'skipped',
@@ -90197,32 +90250,78 @@ function assetWriteVerdict(outcome, nodeId) {
90197
90250
  persisted: outcome ? outcome.committed.includes(nodeId) : undefined
90198
90251
  };
90199
90252
  }
90200
- function writeAssetCell(_x28, _x29) {
90253
+
90254
+ /**
90255
+ * Takes back what the tool staged on a row the server refused or the commit never sent. Left staged, the refused
90256
+ * entry blocks every later write on the table and rides along in the next save of the row, which the server
90257
+ * refuses again. A row that was pending before the tool staged it holds edits of the user as well and is left alone,
90258
+ * and so is a row on which more than the asset column is pending by the time the refusal is settled.
90259
+ */
90260
+ function settleRefusal(_x28, _x29, _x30, _x31, _x32) {
90261
+ return _settleRefusal.apply(this, arguments);
90262
+ }
90263
+ function _settleRefusal() {
90264
+ _settleRefusal = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee13(handle, nodeId, column, verdict, wasPending) {
90265
+ var _handle$discardStaged;
90266
+ var takenBack;
90267
+ return _regeneratorRuntime.wrap(function _callee13$(_context13) {
90268
+ while (1) switch (_context13.prev = _context13.next) {
90269
+ case 0:
90270
+ if (!(verdict.state === 'persisted' || verdict.state === 'rejected' && verdict.unanswered)) {
90271
+ _context13.next = 2;
90272
+ break;
90273
+ }
90274
+ return _context13.abrupt("return", verdict);
90275
+ case 2:
90276
+ if (!wasPending) {
90277
+ _context13.next = 4;
90278
+ break;
90279
+ }
90280
+ return _context13.abrupt("return", _objectSpread$y(_objectSpread$y({}, verdict), {}, {
90281
+ error: "".concat(verdict.error).concat(STILL_STAGED_NOTE)
90282
+ }));
90283
+ case 4:
90284
+ _context13.next = 6;
90285
+ return (_handle$discardStaged = handle.discardStagedRow) === null || _handle$discardStaged === void 0 ? void 0 : _handle$discardStaged.call(handle, nodeId, column);
90286
+ case 6:
90287
+ takenBack = _context13.sent;
90288
+ return _context13.abrupt("return", _objectSpread$y(_objectSpread$y({}, verdict), {}, {
90289
+ error: "".concat(verdict.error).concat(takenBack ? TAKEN_BACK_NOTE : NOT_TAKEN_BACK_NOTE)
90290
+ }));
90291
+ case 8:
90292
+ case "end":
90293
+ return _context13.stop();
90294
+ }
90295
+ }, _callee13);
90296
+ }));
90297
+ return _settleRefusal.apply(this, arguments);
90298
+ }
90299
+ function writeAssetCell(_x33, _x34) {
90201
90300
  return _writeAssetCell.apply(this, arguments);
90202
90301
  }
90203
90302
  function _writeAssetCell() {
90204
- _writeAssetCell = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee14(root, args) {
90205
- var _args$grid2, _divaDef$customParams, _params$mediaItemIdFi, _node, _node3, _handle$commitStagedC2, _handle$refresh;
90206
- var entry, handle, api, divaDef, params, idField, allDefs, findLoadedNode, refusal, node, autoLocated, filterBefore, filterChanged, restoreFilter, _node2, located, carriers, assetObject, newValue, current, list, approved, assetsCleared, _handle$commitStagedC, cleared, clearedNote, outcome, verdict, persisted;
90207
- return _regeneratorRuntime.wrap(function _callee14$(_context14) {
90208
- while (1) switch (_context14.prev = _context14.next) {
90303
+ _writeAssetCell = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee15(root, args) {
90304
+ var _args$grid2, _divaDef$customParams, _params$mediaItemIdFi, _node, _node3, _handle$hasPendingCha, _handle$hasPendingCha2, _handle$commitStagedC2, _handle$hasPendingCha5, _handle$refresh;
90305
+ var entry, handle, api, divaDef, params, idField, allDefs, findLoadedNode, refusal, node, autoLocated, filterBefore, filterChanged, restoreFilter, _node2, located, carriers, assetObject, newValue, current, list, approved, wasPending, assetsCleared, _handle$commitStagedC, _handle$hasPendingCha3, _handle$hasPendingCha4, cleared, clearedNote, outcome, verdict, persisted, gridRefreshed;
90306
+ return _regeneratorRuntime.wrap(function _callee15$(_context15) {
90307
+ while (1) switch (_context15.prev = _context15.next) {
90209
90308
  case 0:
90210
90309
  entry = findGrid(root, args.grid);
90211
90310
  if (entry) {
90212
- _context14.next = 3;
90311
+ _context15.next = 3;
90213
90312
  break;
90214
90313
  }
90215
- return _context14.abrupt("return", {
90314
+ return _context15.abrupt("return", {
90216
90315
  error: "No table '".concat((_args$grid2 = args.grid) !== null && _args$grid2 !== void 0 ? _args$grid2 : '', "' on the current view \u2014 listGrids shows what is on screen.")
90217
90316
  });
90218
90317
  case 3:
90219
90318
  handle = entry.getHandle();
90220
90319
  api = handle === null || handle === void 0 ? void 0 : handle.getGridApi();
90221
90320
  if (!(!handle || !api)) {
90222
- _context14.next = 7;
90321
+ _context15.next = 7;
90223
90322
  break;
90224
90323
  }
90225
- return _context14.abrupt("return", {
90324
+ return _context15.abrupt("return", {
90226
90325
  error: "Table '".concat(entry.label, "' is not ready.")
90227
90326
  });
90228
90327
  case 7:
@@ -90230,18 +90329,18 @@ function _writeAssetCell() {
90230
90329
  return def.field === args.column;
90231
90330
  });
90232
90331
  if (divaDef) {
90233
- _context14.next = 10;
90332
+ _context15.next = 10;
90234
90333
  break;
90235
90334
  }
90236
- return _context14.abrupt("return", {
90335
+ return _context15.abrupt("return", {
90237
90336
  error: "Column '".concat(args.column, "' not found on '").concat(entry.label, "'.")
90238
90337
  });
90239
90338
  case 10:
90240
90339
  if (!(divaDef.cellDataType !== 'asset')) {
90241
- _context14.next = 12;
90340
+ _context15.next = 12;
90242
90341
  break;
90243
90342
  }
90244
- return _context14.abrupt("return", {
90343
+ return _context15.abrupt("return", {
90245
90344
  error: "Column '".concat(args.column, "' is not an asset column \u2014 use stageTableEdits for regular cells.")
90246
90345
  });
90247
90346
  case 12:
@@ -90251,10 +90350,10 @@ function _writeAssetCell() {
90251
90350
  if (allDefs.some(function (def) {
90252
90351
  return def.field === args.keyColumn;
90253
90352
  })) {
90254
- _context14.next = 17;
90353
+ _context15.next = 17;
90255
90354
  break;
90256
90355
  }
90257
- return _context14.abrupt("return", {
90356
+ return _context15.abrupt("return", {
90258
90357
  error: "keyColumn '".concat(args.keyColumn, "' is not a column of '").concat(entry.label, "' \u2014 fields: ").concat(allDefs.map(function (def) {
90259
90358
  return def.field;
90260
90359
  }).filter(Boolean).join(', '), ".")
@@ -90267,15 +90366,15 @@ function _writeAssetCell() {
90267
90366
  });
90268
90367
  return found;
90269
90368
  };
90270
- _context14.next = 20;
90369
+ _context15.next = 20;
90271
90370
  return refusedAssetKeys(api, args.keyColumn, [args.keyValue]);
90272
90371
  case 20:
90273
- refusal = _context14.sent.get(args.keyValue);
90372
+ refusal = _context15.sent.get(args.keyValue);
90274
90373
  if (!refusal) {
90275
- _context14.next = 23;
90374
+ _context15.next = 23;
90276
90375
  break;
90277
90376
  }
90278
- return _context14.abrupt("return", {
90377
+ return _context15.abrupt("return", {
90279
90378
  error: refusal
90280
90379
  });
90281
90380
  case 23:
@@ -90284,71 +90383,71 @@ function _writeAssetCell() {
90284
90383
  filterBefore = api.getFilterModel();
90285
90384
  filterChanged = false;
90286
90385
  restoreFilter = /*#__PURE__*/function () {
90287
- var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee13() {
90288
- return _regeneratorRuntime.wrap(function _callee13$(_context13) {
90289
- while (1) switch (_context13.prev = _context13.next) {
90386
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
90387
+ return _regeneratorRuntime.wrap(function _callee14$(_context14) {
90388
+ while (1) switch (_context14.prev = _context14.next) {
90290
90389
  case 0:
90291
90390
  if (filterChanged) {
90292
- _context13.next = 2;
90391
+ _context14.next = 2;
90293
90392
  break;
90294
90393
  }
90295
- return _context13.abrupt("return");
90394
+ return _context14.abrupt("return");
90296
90395
  case 2:
90297
90396
  filterChanged = false;
90298
90397
  api.setFilterModel(Object.keys(filterBefore !== null && filterBefore !== void 0 ? filterBefore : {}).length ? filterBefore : null);
90299
- _context13.next = 6;
90398
+ _context14.next = 6;
90300
90399
  return waitForRows(api);
90301
90400
  case 6:
90302
90401
  case "end":
90303
- return _context13.stop();
90402
+ return _context14.stop();
90304
90403
  }
90305
- }, _callee13);
90404
+ }, _callee14);
90306
90405
  }));
90307
90406
  return function restoreFilter() {
90308
90407
  return _ref3.apply(this, arguments);
90309
90408
  };
90310
90409
  }();
90311
90410
  if ((_node = node) !== null && _node !== void 0 && _node.id) {
90312
- _context14.next = 47;
90411
+ _context15.next = 47;
90313
90412
  break;
90314
90413
  }
90315
- _context14.prev = 29;
90316
- _context14.next = 32;
90414
+ _context15.prev = 29;
90415
+ _context15.next = 32;
90317
90416
  return locateRowCore(api, args.keyColumn, args.keyValue, false);
90318
90417
  case 32:
90319
- located = _context14.sent;
90418
+ located = _context15.sent;
90320
90419
  filterChanged = located.filterApplied;
90321
- _context14.next = 36;
90420
+ _context15.next = 36;
90322
90421
  return waitForRows(api);
90323
90422
  case 36:
90324
90423
  carriers = loadedCarriers(api, args.keyColumn, args.keyValue);
90325
90424
  if (!(carriers.length > 1)) {
90326
- _context14.next = 41;
90425
+ _context15.next = 41;
90327
90426
  break;
90328
90427
  }
90329
- _context14.next = 40;
90428
+ _context15.next = 40;
90330
90429
  return restoreFilter();
90331
90430
  case 40:
90332
- return _context14.abrupt("return", {
90431
+ return _context15.abrupt("return", {
90333
90432
  error: notUniqueRefusal(args.keyColumn, args.keyValue, carriers)
90334
90433
  });
90335
90434
  case 41:
90336
90435
  node = findLoadedNode();
90337
90436
  autoLocated = !!((_node2 = node) !== null && _node2 !== void 0 && _node2.id);
90338
- _context14.next = 47;
90437
+ _context15.next = 47;
90339
90438
  break;
90340
90439
  case 45:
90341
- _context14.prev = 45;
90342
- _context14.t0 = _context14["catch"](29);
90440
+ _context15.prev = 45;
90441
+ _context15.t0 = _context15["catch"](29);
90343
90442
  case 47:
90344
90443
  if ((_node3 = node) !== null && _node3 !== void 0 && _node3.id) {
90345
- _context14.next = 51;
90444
+ _context15.next = 51;
90346
90445
  break;
90347
90446
  }
90348
- _context14.next = 50;
90447
+ _context15.next = 50;
90349
90448
  return restoreFilter();
90350
90449
  case 50:
90351
- return _context14.abrupt("return", {
90450
+ return _context15.abrupt("return", {
90352
90451
  error: "No loaded row with ".concat(args.keyColumn, " = '").concat(args.keyValue, "' on '").concat(entry.label, "' \u2014 auto-locate did not find it either: the value must match EXACTLY (check for typos/whitespace; the row may not exist).")
90353
90452
  });
90354
90453
  case 51:
@@ -90372,135 +90471,150 @@ function _writeAssetCell() {
90372
90471
  newValue = args.mode === 'remove' ? undefined : params.isObject ? assetObject : args.asset.mediaItemId;
90373
90472
  }
90374
90473
  if (!args.approve) {
90375
- _context14.next = 65;
90474
+ _context15.next = 65;
90376
90475
  break;
90377
90476
  }
90378
- _context14.next = 60;
90477
+ _context15.next = 60;
90379
90478
  return args.approve(entry);
90380
90479
  case 60:
90381
- approved = _context14.sent;
90480
+ approved = _context15.sent;
90382
90481
  if (approved) {
90383
- _context14.next = 65;
90482
+ _context15.next = 65;
90384
90483
  break;
90385
90484
  }
90386
- _context14.next = 64;
90485
+ _context15.next = 64;
90387
90486
  return restoreFilter();
90388
90487
  case 64:
90389
- return _context14.abrupt("return", {
90488
+ return _context15.abrupt("return", {
90390
90489
  applied: false,
90391
90490
  note: 'The user DECLINED the change — nothing was written. Do not retry; ask what to do instead.'
90392
90491
  });
90393
90492
  case 65:
90394
- // A replace on an occupied list is written like the asset cell writes it: the old entries leave in a commit of
90493
+ wasPending = (_handle$hasPendingCha = (_handle$hasPendingCha2 = handle.hasPendingChanges) === null || _handle$hasPendingCha2 === void 0 ? void 0 : _handle$hasPendingCha2.call(handle, node.id)) !== null && _handle$hasPendingCha !== void 0 ? _handle$hasPendingCha : false; // A replace on an occupied list is written like the asset cell writes it: the old entries leave in a commit of
90395
90494
  // their own, the new one arrives in the next — the endpoint keys its asset handling on those shapes.
90396
90495
  assetsCleared = false;
90397
90496
  if (!(params.multiple && args.mode === 'replace' && Array.isArray(current) && current.length)) {
90398
- _context14.next = 88;
90497
+ _context15.next = 98;
90399
90498
  break;
90400
90499
  }
90401
- _context14.next = 69;
90500
+ _context15.next = 70;
90402
90501
  return handle.setNodeDataValue(node.id, _defineProperty({}, args.column, []), {
90403
90502
  suppressAutoCommit: true
90404
90503
  });
90405
- case 69:
90406
- if (_context14.sent) {
90407
- _context14.next = 73;
90504
+ case 70:
90505
+ if (_context15.sent) {
90506
+ _context15.next = 74;
90408
90507
  break;
90409
90508
  }
90410
- _context14.next = 72;
90509
+ _context15.next = 73;
90411
90510
  return restoreFilter();
90412
- case 72:
90413
- return _context14.abrupt("return", {
90511
+ case 73:
90512
+ return _context15.abrupt("return", {
90414
90513
  error: 'The row rejected the update.'
90415
90514
  });
90416
- case 73:
90417
- _context14.t1 = assetWriteVerdict;
90418
- _context14.next = 76;
90515
+ case 74:
90516
+ _context15.t1 = settleRefusal;
90517
+ _context15.t2 = handle;
90518
+ _context15.t3 = node.id;
90519
+ _context15.t4 = args.column;
90520
+ _context15.t5 = assetWriteVerdict;
90521
+ _context15.next = 81;
90419
90522
  return (_handle$commitStagedC = handle.commitStagedChanges) === null || _handle$commitStagedC === void 0 ? void 0 : _handle$commitStagedC.call(handle);
90420
- case 76:
90421
- _context14.t2 = _context14.sent;
90422
- _context14.t3 = node.id;
90423
- cleared = (0, _context14.t1)(_context14.t2, _context14.t3);
90523
+ case 81:
90524
+ _context15.t6 = _context15.sent;
90525
+ _context15.t7 = node.id;
90526
+ _context15.t8 = (0, _context15.t5)(_context15.t6, _context15.t7);
90527
+ _context15.t9 = wasPending;
90528
+ _context15.next = 87;
90529
+ return (0, _context15.t1)(_context15.t2, _context15.t3, _context15.t4, _context15.t8, _context15.t9);
90530
+ case 87:
90531
+ cleared = _context15.sent;
90424
90532
  if (!(cleared.state !== 'persisted')) {
90425
- _context14.next = 83;
90533
+ _context15.next = 92;
90426
90534
  break;
90427
90535
  }
90428
- _context14.next = 82;
90536
+ _context15.next = 91;
90429
90537
  return restoreFilter();
90430
- case 82:
90431
- return _context14.abrupt("return", {
90538
+ case 91:
90539
+ return _context15.abrupt("return", {
90432
90540
  error: "".concat(clearRejected(cleared.error)[0].toUpperCase()).concat(clearRejected(cleared.error).slice(1), ".")
90433
90541
  });
90434
- case 83:
90542
+ case 92:
90435
90543
  if (!(cleared.persisted === false)) {
90436
- _context14.next = 87;
90544
+ _context15.next = 96;
90437
90545
  break;
90438
90546
  }
90439
- _context14.next = 86;
90547
+ _context15.next = 95;
90440
90548
  return restoreFilter();
90441
- case 86:
90442
- return _context14.abrupt("return", {
90549
+ case 95:
90550
+ return _context15.abrupt("return", {
90443
90551
  error: "".concat(UNCONFIRMED_CLEAR[0].toUpperCase()).concat(UNCONFIRMED_CLEAR.slice(1), ".")
90444
90552
  });
90445
- case 87:
90553
+ case 96:
90446
90554
  assetsCleared = cleared.persisted === true;
90447
- case 88:
90555
+ // The confirmed clear saved the row's earlier edits too: the replacement starts on what is pending now.
90556
+ wasPending = (_handle$hasPendingCha3 = (_handle$hasPendingCha4 = handle.hasPendingChanges) === null || _handle$hasPendingCha4 === void 0 ? void 0 : _handle$hasPendingCha4.call(handle, node.id)) !== null && _handle$hasPendingCha3 !== void 0 ? _handle$hasPendingCha3 : false;
90557
+ case 98:
90448
90558
  clearedNote = assetsCleared ? CLEARED_ASSETS_NOTE : '';
90449
- _context14.next = 91;
90559
+ _context15.next = 101;
90450
90560
  return handle.setNodeDataValue(node.id, _defineProperty({}, args.column, newValue), {
90451
90561
  suppressAutoCommit: true
90452
90562
  });
90453
- case 91:
90454
- if (_context14.sent) {
90455
- _context14.next = 95;
90563
+ case 101:
90564
+ if (_context15.sent) {
90565
+ _context15.next = 105;
90456
90566
  break;
90457
90567
  }
90458
- _context14.next = 94;
90568
+ _context15.next = 104;
90459
90569
  return restoreFilter();
90460
- case 94:
90461
- return _context14.abrupt("return", {
90570
+ case 104:
90571
+ return _context15.abrupt("return", {
90462
90572
  error: "The row rejected the update.".concat(clearedNote)
90463
90573
  });
90464
- case 95:
90465
- _context14.next = 97;
90574
+ case 105:
90575
+ _context15.next = 107;
90466
90576
  return (_handle$commitStagedC2 = handle.commitStagedChanges) === null || _handle$commitStagedC2 === void 0 ? void 0 : _handle$commitStagedC2.call(handle);
90467
- case 97:
90468
- outcome = _context14.sent;
90469
- verdict = assetWriteVerdict(outcome, node.id);
90577
+ case 107:
90578
+ outcome = _context15.sent;
90579
+ _context15.next = 110;
90580
+ return settleRefusal(handle, node.id, args.column, assetWriteVerdict(outcome, node.id), wasPending);
90581
+ case 110:
90582
+ verdict = _context15.sent;
90470
90583
  if (!(verdict.state === 'rejected' || verdict.state === 'skipped')) {
90471
- _context14.next = 103;
90584
+ _context15.next = 115;
90472
90585
  break;
90473
90586
  }
90474
- _context14.next = 102;
90587
+ _context15.next = 114;
90475
90588
  return restoreFilter();
90476
- case 102:
90477
- return _context14.abrupt("return", {
90589
+ case 114:
90590
+ return _context15.abrupt("return", {
90478
90591
  error: "".concat(verdict.error[0].toUpperCase()).concat(verdict.error.slice(1), ".").concat(clearedNote)
90479
90592
  });
90480
- case 103:
90481
- persisted = verdict.persisted; // Refetch only once the server confirmed — a refresh while a write is still pending discards it.
90482
- if (persisted === true) (_handle$refresh = handle.refresh) === null || _handle$refresh === void 0 || _handle$refresh.call(handle);
90593
+ case 115:
90594
+ persisted = verdict.persisted; // Refetch only once the server confirmed and nothing else is staged — a refresh discards every pending change.
90595
+ gridRefreshed = persisted === true && !((_handle$hasPendingCha5 = handle.hasPendingChanges) !== null && _handle$hasPendingCha5 !== void 0 && _handle$hasPendingCha5.call(handle));
90596
+ if (gridRefreshed) (_handle$refresh = handle.refresh) === null || _handle$refresh === void 0 || _handle$refresh.call(handle);
90483
90597
  if (!(persisted !== false)) {
90484
- _context14.next = 108;
90598
+ _context15.next = 121;
90485
90599
  break;
90486
90600
  }
90487
- _context14.next = 108;
90601
+ _context15.next = 121;
90488
90602
  return restoreFilter();
90489
- case 108:
90490
- return _context14.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
90603
+ case 121:
90604
+ return _context15.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
90491
90605
  applied: true
90492
90606
  }, persisted === undefined ? {} : {
90493
90607
  persisted: persisted
90494
- }), persisted === true ? {
90608
+ }), gridRefreshed ? {
90495
90609
  gridRefreshed: true
90496
90610
  } : {}), autoLocated ? {
90497
90611
  autoLocated: true
90498
90612
  } : {}));
90499
- case 109:
90613
+ case 122:
90500
90614
  case "end":
90501
- return _context14.stop();
90615
+ return _context15.stop();
90502
90616
  }
90503
- }, _callee14, null, [[29, 45]]);
90617
+ }, _callee15, null, [[29, 45]]);
90504
90618
  }));
90505
90619
  return _writeAssetCell.apply(this, arguments);
90506
90620
  }
@@ -90513,33 +90627,33 @@ var ROW_NOT_FOUND = 'no row matched this keyValue — the value must match EXACT
90513
90627
  * already-staged-but-uncommitted row, so a row located this way is committed on its own, immediately,
90514
90628
  * before the next lookup runs.
90515
90629
  */
90516
- function writeAssetCellsBatch(_x30, _x31, _x32, _x33, _x34, _x35, _x36, _x37) {
90630
+ function writeAssetCellsBatch(_x35, _x36, _x37, _x38, _x39, _x40, _x41, _x42) {
90517
90631
  return _writeAssetCellsBatch.apply(this, arguments);
90518
90632
  }
90519
90633
  /** Per-article result of a generateArticleSvg batch run — ids and findings only, never the markup. */
90520
90634
  function _writeAssetCellsBatch() {
90521
- _writeAssetCellsBatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee16(root, grid, keyColumn, column, defaultMode, cells, approve, signal) {
90522
- var _divaDef$customParams2, _params$mediaItemIdFi2, _handle$refresh2;
90523
- var entry, handle, api, allDefs, divaDef, params, idField, loadedNodes, newValueFor, needsClearFirst, stageAndCommit, refusals, preflight, writable, stageable, needsLookup, written, failed, remaining, startedAt, recordVerdict, filterBefore, filterChanged, _iterator8, _step8, _node4, _handle$commitStagedC5, cell, node, located, carriers, assetsCleared, _handle$commitStagedC4, cleared, newValue, outcome, nodesByKey, blocked, _cleared, notStarted, persistedCount, gridRefreshed;
90524
- return _regeneratorRuntime.wrap(function _callee16$(_context16) {
90525
- while (1) switch (_context16.prev = _context16.next) {
90635
+ _writeAssetCellsBatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee17(root, grid, keyColumn, column, defaultMode, cells, approve, signal) {
90636
+ var _divaDef$customParams2, _params$mediaItemIdFi2, _handle$hasPendingCha12, _handle$refresh2;
90637
+ var entry, handle, api, allDefs, divaDef, params, idField, loadedNodes, newValueFor, needsClearFirst, stageAndCommit, refusals, preflight, writable, stageable, needsLookup, written, failed, remaining, startedAt, recordVerdict, filterBefore, filterChanged, _iterator8, _step8, _node4, _handle$hasPendingCha8, _handle$hasPendingCha9, _handle$commitStagedC5, cell, node, located, carriers, wasPending, assetsCleared, _handle$commitStagedC4, _handle$hasPendingCha10, _handle$hasPendingCha11, cleared, newValue, outcome, nodesByKey, blocked, _cleared, notStarted, persistedCount, gridRefreshed;
90638
+ return _regeneratorRuntime.wrap(function _callee17$(_context17) {
90639
+ while (1) switch (_context17.prev = _context17.next) {
90526
90640
  case 0:
90527
90641
  entry = findGrid(root, grid);
90528
90642
  if (entry) {
90529
- _context16.next = 3;
90643
+ _context17.next = 3;
90530
90644
  break;
90531
90645
  }
90532
- return _context16.abrupt("return", {
90646
+ return _context17.abrupt("return", {
90533
90647
  error: "No table '".concat(grid !== null && grid !== void 0 ? grid : '', "' on the current view \u2014 listGrids shows what is on screen.")
90534
90648
  });
90535
90649
  case 3:
90536
90650
  handle = entry.getHandle();
90537
90651
  api = handle === null || handle === void 0 ? void 0 : handle.getGridApi();
90538
90652
  if (!(!handle || !api)) {
90539
- _context16.next = 7;
90653
+ _context17.next = 7;
90540
90654
  break;
90541
90655
  }
90542
- return _context16.abrupt("return", {
90656
+ return _context17.abrupt("return", {
90543
90657
  error: "Table '".concat(entry.label, "' is not ready.")
90544
90658
  });
90545
90659
  case 7:
@@ -90548,28 +90662,28 @@ function _writeAssetCellsBatch() {
90548
90662
  return def.field === column;
90549
90663
  });
90550
90664
  if (divaDef) {
90551
- _context16.next = 11;
90665
+ _context17.next = 11;
90552
90666
  break;
90553
90667
  }
90554
- return _context16.abrupt("return", {
90668
+ return _context17.abrupt("return", {
90555
90669
  error: "Column '".concat(column, "' not found on '").concat(entry.label, "'.")
90556
90670
  });
90557
90671
  case 11:
90558
90672
  if (!(divaDef.cellDataType !== 'asset')) {
90559
- _context16.next = 13;
90673
+ _context17.next = 13;
90560
90674
  break;
90561
90675
  }
90562
- return _context16.abrupt("return", {
90676
+ return _context17.abrupt("return", {
90563
90677
  error: "Column '".concat(column, "' is not an asset column \u2014 use stageTableEdits for regular cells.")
90564
90678
  });
90565
90679
  case 13:
90566
90680
  if (allDefs.some(function (def) {
90567
90681
  return def.field === keyColumn;
90568
90682
  })) {
90569
- _context16.next = 15;
90683
+ _context17.next = 15;
90570
90684
  break;
90571
90685
  }
90572
- return _context16.abrupt("return", {
90686
+ return _context17.abrupt("return", {
90573
90687
  error: "keyColumn '".concat(keyColumn, "' is not a column of '").concat(entry.label, "'.")
90574
90688
  });
90575
90689
  case 15:
@@ -90610,111 +90724,135 @@ function _writeAssetCellsBatch() {
90610
90724
  };
90611
90725
  /** Stages one value per cell and commits them together; every staged cell's verdict goes to `onVerdict`. */
90612
90726
  stageAndCommit = /*#__PURE__*/function () {
90613
- var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee15(targets, valueOf, onVerdict, cleared) {
90727
+ var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee16(targets, valueOf, onVerdict, cleared) {
90614
90728
  var _handle$commitStagedC3;
90615
- var noteFor, nodesByKey, staged, _iterator7, _step7, _cell, node, outcome, _i2, _staged, _staged$_i, cell, nodeId;
90616
- return _regeneratorRuntime.wrap(function _callee15$(_context15) {
90617
- while (1) switch (_context15.prev = _context15.next) {
90729
+ var noteFor, nodesByKey, staged, pendingBefore, _iterator7, _step7, _handle$hasPendingCha6, _handle$hasPendingCha7, _cell, node, outcome, settled, _i2, _staged, _settled$get, _staged$_i, cell, nodeId, _pendingBefore$get;
90730
+ return _regeneratorRuntime.wrap(function _callee16$(_context16) {
90731
+ while (1) switch (_context16.prev = _context16.next) {
90618
90732
  case 0:
90619
90733
  noteFor = function noteFor(cell) {
90620
90734
  return cleared !== null && cleared !== void 0 && cleared.has(cell.keyValue) ? CLEARED_ASSETS_NOTE : '';
90621
90735
  }; // The approval blocks for as long as the user takes — re-read the rows instead of writing stale ones.
90622
90736
  nodesByKey = loadedNodes();
90623
- staged = [];
90737
+ staged = []; // Per row, before the tool's FIRST write to it: several cells may name the same row.
90738
+ pendingBefore = new Map();
90624
90739
  _iterator7 = _createForOfIteratorHelper$g(targets);
90625
- _context15.prev = 4;
90740
+ _context16.prev = 5;
90626
90741
  _iterator7.s();
90627
- case 6:
90742
+ case 7:
90628
90743
  if ((_step7 = _iterator7.n()).done) {
90629
- _context15.next = 20;
90744
+ _context16.next = 22;
90630
90745
  break;
90631
90746
  }
90632
90747
  _cell = _step7.value;
90633
90748
  node = nodesByKey.get(_cell.keyValue);
90634
90749
  if (node !== null && node !== void 0 && node.id) {
90635
- _context15.next = 12;
90750
+ _context16.next = 13;
90636
90751
  break;
90637
90752
  }
90638
90753
  failed.push({
90639
90754
  keyValue: _cell.keyValue,
90640
90755
  error: "".concat(ROW_NOT_FOUND).concat(noteFor(_cell))
90641
90756
  });
90642
- return _context15.abrupt("continue", 18);
90643
- case 12:
90644
- _context15.next = 14;
90757
+ return _context16.abrupt("continue", 20);
90758
+ case 13:
90759
+ if (!pendingBefore.has(node.id)) pendingBefore.set(node.id, (_handle$hasPendingCha6 = (_handle$hasPendingCha7 = handle.hasPendingChanges) === null || _handle$hasPendingCha7 === void 0 ? void 0 : _handle$hasPendingCha7.call(handle, node.id)) !== null && _handle$hasPendingCha6 !== void 0 ? _handle$hasPendingCha6 : false);
90760
+ _context16.next = 16;
90645
90761
  return handle.setNodeDataValue(node.id, _defineProperty({}, column, valueOf(node, _cell)), {
90646
90762
  suppressAutoCommit: true
90647
90763
  });
90648
- case 14:
90649
- if (_context15.sent) {
90650
- _context15.next = 17;
90764
+ case 16:
90765
+ if (_context16.sent) {
90766
+ _context16.next = 19;
90651
90767
  break;
90652
90768
  }
90653
90769
  failed.push({
90654
90770
  keyValue: _cell.keyValue,
90655
90771
  error: "the row rejected the update".concat(noteFor(_cell))
90656
90772
  });
90657
- return _context15.abrupt("continue", 18);
90658
- case 17:
90773
+ return _context16.abrupt("continue", 20);
90774
+ case 19:
90659
90775
  staged.push({
90660
90776
  cell: _cell,
90661
90777
  nodeId: node.id
90662
90778
  });
90663
- case 18:
90664
- _context15.next = 6;
90665
- break;
90666
90779
  case 20:
90667
- _context15.next = 25;
90780
+ _context16.next = 7;
90668
90781
  break;
90669
90782
  case 22:
90670
- _context15.prev = 22;
90671
- _context15.t0 = _context15["catch"](4);
90672
- _iterator7.e(_context15.t0);
90673
- case 25:
90674
- _context15.prev = 25;
90783
+ _context16.next = 27;
90784
+ break;
90785
+ case 24:
90786
+ _context16.prev = 24;
90787
+ _context16.t0 = _context16["catch"](5);
90788
+ _iterator7.e(_context16.t0);
90789
+ case 27:
90790
+ _context16.prev = 27;
90675
90791
  _iterator7.f();
90676
- return _context15.finish(25);
90677
- case 28:
90792
+ return _context16.finish(27);
90793
+ case 30:
90678
90794
  if (staged.length) {
90679
- _context15.next = 30;
90795
+ _context16.next = 32;
90680
90796
  break;
90681
90797
  }
90682
- return _context15.abrupt("return");
90683
- case 30:
90684
- _context15.next = 32;
90685
- return (_handle$commitStagedC3 = handle.commitStagedChanges) === null || _handle$commitStagedC3 === void 0 ? void 0 : _handle$commitStagedC3.call(handle);
90798
+ return _context16.abrupt("return");
90686
90799
  case 32:
90687
- outcome = _context15.sent;
90688
- for (_i2 = 0, _staged = staged; _i2 < _staged.length; _i2++) {
90689
- _staged$_i = _staged[_i2], cell = _staged$_i.cell, nodeId = _staged$_i.nodeId;
90690
- onVerdict(cell, assetWriteVerdict(outcome, nodeId));
90691
- }
90800
+ _context16.next = 34;
90801
+ return (_handle$commitStagedC3 = handle.commitStagedChanges) === null || _handle$commitStagedC3 === void 0 ? void 0 : _handle$commitStagedC3.call(handle);
90692
90802
  case 34:
90803
+ outcome = _context16.sent;
90804
+ // One settlement per row: the commit's verdict is per row, and a row taken back once has nothing left to take back.
90805
+ settled = new Map();
90806
+ _i2 = 0, _staged = staged;
90807
+ case 37:
90808
+ if (!(_i2 < _staged.length)) {
90809
+ _context16.next = 50;
90810
+ break;
90811
+ }
90812
+ _staged$_i = _staged[_i2], cell = _staged$_i.cell, nodeId = _staged$_i.nodeId;
90813
+ if (settled.has(nodeId)) {
90814
+ _context16.next = 46;
90815
+ break;
90816
+ }
90817
+ _context16.t1 = settled;
90818
+ _context16.t2 = nodeId;
90819
+ _context16.next = 44;
90820
+ return settleRefusal(handle, nodeId, column, assetWriteVerdict(outcome, nodeId), (_pendingBefore$get = pendingBefore.get(nodeId)) !== null && _pendingBefore$get !== void 0 ? _pendingBefore$get : false);
90821
+ case 44:
90822
+ _context16.t3 = _context16.sent;
90823
+ _context16.t1.set.call(_context16.t1, _context16.t2, _context16.t3);
90824
+ case 46:
90825
+ onVerdict(cell, (_settled$get = settled.get(nodeId)) !== null && _settled$get !== void 0 ? _settled$get : assetWriteVerdict(outcome, nodeId));
90826
+ case 47:
90827
+ _i2++;
90828
+ _context16.next = 37;
90829
+ break;
90830
+ case 50:
90693
90831
  case "end":
90694
- return _context15.stop();
90832
+ return _context16.stop();
90695
90833
  }
90696
- }, _callee15, null, [[4, 22, 25, 28]]);
90834
+ }, _callee16, null, [[5, 24, 27, 30]]);
90697
90835
  }));
90698
- return function stageAndCommit(_x48, _x49, _x50, _x51) {
90836
+ return function stageAndCommit(_x53, _x54, _x55, _x56) {
90699
90837
  return _ref4.apply(this, arguments);
90700
90838
  };
90701
90839
  }();
90702
90840
  if (cells.length) {
90703
- _context16.next = 23;
90841
+ _context17.next = 23;
90704
90842
  break;
90705
90843
  }
90706
- return _context16.abrupt("return", {
90844
+ return _context17.abrupt("return", {
90707
90845
  written: [],
90708
90846
  failed: [],
90709
90847
  note: "'cells' was empty."
90710
90848
  });
90711
90849
  case 23:
90712
- _context16.next = 25;
90850
+ _context17.next = 25;
90713
90851
  return refusedAssetKeys(api, keyColumn, _toConsumableArray(new Set(cells.map(function (cell) {
90714
90852
  return cell.keyValue;
90715
90853
  }))));
90716
90854
  case 25:
90717
- refusals = _context16.sent;
90855
+ refusals = _context17.sent;
90718
90856
  preflight = loadedNodes();
90719
90857
  writable = cells.filter(function (cell) {
90720
90858
  return !refusals.has(cell.keyValue);
@@ -90728,21 +90866,21 @@ function _writeAssetCellsBatch() {
90728
90866
  return !((_preflight$get2 = preflight.get(cell.keyValue)) !== null && _preflight$get2 !== void 0 && _preflight$get2.id);
90729
90867
  }); // ONE approval covers the WHOLE batch, including rows that still need to be located — writing anything
90730
90868
  // (even the sequential lookups below) must never happen before the user has consented to all of it.
90731
- _context16.t0 = writable.length && approve;
90732
- if (!_context16.t0) {
90733
- _context16.next = 35;
90869
+ _context17.t0 = writable.length && approve;
90870
+ if (!_context17.t0) {
90871
+ _context17.next = 35;
90734
90872
  break;
90735
90873
  }
90736
- _context16.next = 34;
90874
+ _context17.next = 34;
90737
90875
  return approve(entry, stageable.length + needsLookup.length);
90738
90876
  case 34:
90739
- _context16.t0 = !_context16.sent;
90877
+ _context17.t0 = !_context17.sent;
90740
90878
  case 35:
90741
- if (!_context16.t0) {
90742
- _context16.next = 37;
90879
+ if (!_context17.t0) {
90880
+ _context17.next = 37;
90743
90881
  break;
90744
90882
  }
90745
- return _context16.abrupt("return", {
90883
+ return _context17.abrupt("return", {
90746
90884
  applied: false,
90747
90885
  note: 'The user DECLINED the change — nothing was written. Do not retry; ask what to do instead.'
90748
90886
  });
@@ -90777,180 +90915,199 @@ function _writeAssetCellsBatch() {
90777
90915
  }; // Rows not in the loaded window: resolve, stage and commit EACH ONE on its own before the next lookup's
90778
90916
  // filter change can put anything else at risk (see writeAssetCellsBatch's own doc comment above).
90779
90917
  if (!needsLookup.length) {
90780
- _context16.next = 117;
90918
+ _context17.next = 133;
90781
90919
  break;
90782
90920
  }
90783
90921
  filterBefore = api.getFilterModel();
90784
90922
  filterChanged = false;
90785
90923
  _iterator8 = _createForOfIteratorHelper$g(needsLookup);
90786
- _context16.prev = 46;
90924
+ _context17.prev = 46;
90787
90925
  _iterator8.s();
90788
90926
  case 48:
90789
90927
  if ((_step8 = _iterator8.n()).done) {
90790
- _context16.next = 105;
90928
+ _context17.next = 121;
90791
90929
  break;
90792
90930
  }
90793
90931
  cell = _step8.value;
90794
90932
  if (!stopBatch(startedAt, TIME_BUDGET_MS, signal)) {
90795
- _context16.next = 53;
90933
+ _context17.next = 53;
90796
90934
  break;
90797
90935
  }
90798
90936
  remaining.push(cell.keyValue);
90799
- return _context16.abrupt("continue", 103);
90937
+ return _context17.abrupt("continue", 119);
90800
90938
  case 53:
90801
90939
  node = void 0;
90802
- _context16.prev = 54;
90803
- _context16.next = 57;
90940
+ _context17.prev = 54;
90941
+ _context17.next = 57;
90804
90942
  return locateRowCore(api, keyColumn, cell.keyValue, false);
90805
90943
  case 57:
90806
- located = _context16.sent;
90944
+ located = _context17.sent;
90807
90945
  filterChanged = filterChanged || located.filterApplied;
90808
- _context16.next = 65;
90946
+ _context17.next = 65;
90809
90947
  break;
90810
90948
  case 61:
90811
- _context16.prev = 61;
90812
- _context16.t1 = _context16["catch"](54);
90949
+ _context17.prev = 61;
90950
+ _context17.t1 = _context17["catch"](54);
90813
90951
  failed.push({
90814
90952
  keyValue: cell.keyValue,
90815
- error: _context16.t1 instanceof Error ? _context16.t1.message : String(_context16.t1)
90953
+ error: _context17.t1 instanceof Error ? _context17.t1.message : String(_context17.t1)
90816
90954
  });
90817
- return _context16.abrupt("continue", 103);
90955
+ return _context17.abrupt("continue", 119);
90818
90956
  case 65:
90819
90957
  carriers = loadedCarriers(api, keyColumn, cell.keyValue);
90820
90958
  if (!(carriers.length > 1)) {
90821
- _context16.next = 69;
90959
+ _context17.next = 69;
90822
90960
  break;
90823
90961
  }
90824
90962
  failed.push({
90825
90963
  keyValue: cell.keyValue,
90826
90964
  error: notUniqueRefusal(keyColumn, cell.keyValue, carriers)
90827
90965
  });
90828
- return _context16.abrupt("continue", 103);
90966
+ return _context17.abrupt("continue", 119);
90829
90967
  case 69:
90830
90968
  // locateRowCore only guarantees the row is LOADED — re-read it by an exact key match, same as the single-cell path.
90831
90969
  node = loadedNodes().get(cell.keyValue);
90832
90970
  if ((_node4 = node) !== null && _node4 !== void 0 && _node4.id) {
90833
- _context16.next = 73;
90971
+ _context17.next = 73;
90834
90972
  break;
90835
90973
  }
90836
90974
  failed.push({
90837
90975
  keyValue: cell.keyValue,
90838
90976
  error: ROW_NOT_FOUND
90839
90977
  });
90840
- return _context16.abrupt("continue", 103);
90978
+ return _context17.abrupt("continue", 119);
90841
90979
  case 73:
90980
+ wasPending = (_handle$hasPendingCha8 = (_handle$hasPendingCha9 = handle.hasPendingChanges) === null || _handle$hasPendingCha9 === void 0 ? void 0 : _handle$hasPendingCha9.call(handle, node.id)) !== null && _handle$hasPendingCha8 !== void 0 ? _handle$hasPendingCha8 : false;
90842
90981
  assetsCleared = false;
90843
90982
  if (!needsClearFirst(node, cell)) {
90844
- _context16.next = 93;
90983
+ _context17.next = 103;
90845
90984
  break;
90846
90985
  }
90847
- _context16.next = 77;
90986
+ _context17.next = 78;
90848
90987
  return handle.setNodeDataValue(node.id, _defineProperty({}, column, []), {
90849
90988
  suppressAutoCommit: true
90850
90989
  });
90851
- case 77:
90852
- if (_context16.sent) {
90853
- _context16.next = 80;
90990
+ case 78:
90991
+ if (_context17.sent) {
90992
+ _context17.next = 81;
90854
90993
  break;
90855
90994
  }
90856
90995
  failed.push({
90857
90996
  keyValue: cell.keyValue,
90858
90997
  error: 'the row rejected the update'
90859
90998
  });
90860
- return _context16.abrupt("continue", 103);
90861
- case 80:
90862
- _context16.t2 = assetWriteVerdict;
90863
- _context16.next = 83;
90999
+ return _context17.abrupt("continue", 119);
91000
+ case 81:
91001
+ _context17.t2 = settleRefusal;
91002
+ _context17.t3 = handle;
91003
+ _context17.t4 = node.id;
91004
+ _context17.t5 = column;
91005
+ _context17.t6 = assetWriteVerdict;
91006
+ _context17.next = 88;
90864
91007
  return (_handle$commitStagedC4 = handle.commitStagedChanges) === null || _handle$commitStagedC4 === void 0 ? void 0 : _handle$commitStagedC4.call(handle);
90865
- case 83:
90866
- _context16.t3 = _context16.sent;
90867
- _context16.t4 = node.id;
90868
- cleared = (0, _context16.t2)(_context16.t3, _context16.t4);
91008
+ case 88:
91009
+ _context17.t7 = _context17.sent;
91010
+ _context17.t8 = node.id;
91011
+ _context17.t9 = (0, _context17.t6)(_context17.t7, _context17.t8);
91012
+ _context17.t10 = wasPending;
91013
+ _context17.next = 94;
91014
+ return (0, _context17.t2)(_context17.t3, _context17.t4, _context17.t5, _context17.t9, _context17.t10);
91015
+ case 94:
91016
+ cleared = _context17.sent;
90869
91017
  if (!(cleared.state !== 'persisted')) {
90870
- _context16.next = 89;
91018
+ _context17.next = 98;
90871
91019
  break;
90872
91020
  }
90873
91021
  failed.push({
90874
91022
  keyValue: cell.keyValue,
90875
91023
  error: clearRejected(cleared.error)
90876
91024
  });
90877
- return _context16.abrupt("continue", 103);
90878
- case 89:
91025
+ return _context17.abrupt("continue", 119);
91026
+ case 98:
90879
91027
  if (!(cleared.persisted === false)) {
90880
- _context16.next = 92;
91028
+ _context17.next = 101;
90881
91029
  break;
90882
91030
  }
90883
91031
  failed.push({
90884
91032
  keyValue: cell.keyValue,
90885
91033
  error: UNCONFIRMED_CLEAR
90886
91034
  });
90887
- return _context16.abrupt("continue", 103);
90888
- case 92:
91035
+ return _context17.abrupt("continue", 119);
91036
+ case 101:
90889
91037
  assetsCleared = cleared.persisted === true;
90890
- case 93:
91038
+ // The confirmed clear saved the row's earlier edits too: the replacement starts on what is pending now.
91039
+ wasPending = (_handle$hasPendingCha10 = (_handle$hasPendingCha11 = handle.hasPendingChanges) === null || _handle$hasPendingCha11 === void 0 ? void 0 : _handle$hasPendingCha11.call(handle, node.id)) !== null && _handle$hasPendingCha10 !== void 0 ? _handle$hasPendingCha10 : false;
91040
+ case 103:
90891
91041
  newValue = newValueFor(node, cell);
90892
- _context16.next = 96;
91042
+ _context17.next = 106;
90893
91043
  return handle.setNodeDataValue(node.id, _defineProperty({}, column, newValue), {
90894
91044
  suppressAutoCommit: true
90895
91045
  });
90896
- case 96:
90897
- if (_context16.sent) {
90898
- _context16.next = 99;
91046
+ case 106:
91047
+ if (_context17.sent) {
91048
+ _context17.next = 109;
90899
91049
  break;
90900
91050
  }
90901
91051
  failed.push({
90902
91052
  keyValue: cell.keyValue,
90903
91053
  error: "the row rejected the update".concat(assetsCleared ? CLEARED_ASSETS_NOTE : '')
90904
91054
  });
90905
- return _context16.abrupt("continue", 103);
90906
- case 99:
90907
- _context16.next = 101;
91055
+ return _context17.abrupt("continue", 119);
91056
+ case 109:
91057
+ _context17.next = 111;
90908
91058
  return (_handle$commitStagedC5 = handle.commitStagedChanges) === null || _handle$commitStagedC5 === void 0 ? void 0 : _handle$commitStagedC5.call(handle);
90909
- case 101:
90910
- outcome = _context16.sent;
90911
- recordVerdict(cell.keyValue, assetWriteVerdict(outcome, node.id), assetsCleared);
90912
- case 103:
90913
- _context16.next = 48;
91059
+ case 111:
91060
+ outcome = _context17.sent;
91061
+ _context17.t11 = recordVerdict;
91062
+ _context17.t12 = cell.keyValue;
91063
+ _context17.next = 116;
91064
+ return settleRefusal(handle, node.id, column, assetWriteVerdict(outcome, node.id), wasPending);
91065
+ case 116:
91066
+ _context17.t13 = _context17.sent;
91067
+ _context17.t14 = assetsCleared;
91068
+ (0, _context17.t11)(_context17.t12, _context17.t13, _context17.t14);
91069
+ case 119:
91070
+ _context17.next = 48;
90914
91071
  break;
90915
- case 105:
90916
- _context16.next = 110;
91072
+ case 121:
91073
+ _context17.next = 126;
90917
91074
  break;
90918
- case 107:
90919
- _context16.prev = 107;
90920
- _context16.t5 = _context16["catch"](46);
90921
- _iterator8.e(_context16.t5);
90922
- case 110:
90923
- _context16.prev = 110;
91075
+ case 123:
91076
+ _context17.prev = 123;
91077
+ _context17.t15 = _context17["catch"](46);
91078
+ _iterator8.e(_context17.t15);
91079
+ case 126:
91080
+ _context17.prev = 126;
90924
91081
  _iterator8.f();
90925
- return _context16.finish(110);
90926
- case 113:
91082
+ return _context17.finish(126);
91083
+ case 129:
90927
91084
  if (!filterChanged) {
90928
- _context16.next = 117;
91085
+ _context17.next = 133;
90929
91086
  break;
90930
91087
  }
90931
91088
  api.setFilterModel(Object.keys(filterBefore !== null && filterBefore !== void 0 ? filterBefore : {}).length ? filterBefore : null);
90932
91089
  // The Server-Side Row Model reloads on the restore — the stageable rows below are re-read from it.
90933
- _context16.next = 117;
91090
+ _context17.next = 133;
90934
91091
  return waitForRows(api);
90935
- case 117:
91092
+ case 133:
90936
91093
  if (!(stageable.length && stopBatch(startedAt, TIME_BUDGET_MS, signal))) {
90937
- _context16.next = 121;
91094
+ _context17.next = 137;
90938
91095
  break;
90939
91096
  }
90940
91097
  remaining.push.apply(remaining, _toConsumableArray(stageable.map(function (cell) {
90941
91098
  return cell.keyValue;
90942
91099
  })));
90943
- _context16.next = 129;
91100
+ _context17.next = 145;
90944
91101
  break;
90945
- case 121:
91102
+ case 137:
90946
91103
  if (!stageable.length) {
90947
- _context16.next = 129;
91104
+ _context17.next = 145;
90948
91105
  break;
90949
91106
  }
90950
91107
  nodesByKey = loadedNodes();
90951
91108
  blocked = new Set();
90952
91109
  _cleared = new Set();
90953
- _context16.next = 127;
91110
+ _context17.next = 143;
90954
91111
  return stageAndCommit(stageable.filter(function (cell) {
90955
91112
  return needsClearFirst(nodesByKey.get(cell.keyValue), cell);
90956
91113
  }), function () {
@@ -90974,20 +91131,20 @@ function _writeAssetCellsBatch() {
90974
91131
  }
90975
91132
  if (verdict.persisted === true) _cleared.add(cell.keyValue);
90976
91133
  });
90977
- case 127:
90978
- _context16.next = 129;
91134
+ case 143:
91135
+ _context17.next = 145;
90979
91136
  return stageAndCommit(stageable.filter(function (cell) {
90980
91137
  return !blocked.has(cell.keyValue);
90981
91138
  }), newValueFor, function (cell, verdict) {
90982
91139
  return recordVerdict(cell.keyValue, verdict, _cleared.has(cell.keyValue));
90983
91140
  }, _cleared);
90984
- case 129:
91141
+ case 145:
90985
91142
  notStarted = remaining.length ? " ".concat(signal !== null && signal !== void 0 && signal.aborted ? 'The turn was ABORTED' : 'TIME BUDGET reached', ": the ").concat(remaining.length, " entries in 'remaining' were NOT STARTED \u2014 re-call with only those; everything in 'written' is DONE.") : '';
90986
91143
  if (!(written.length === 0)) {
90987
- _context16.next = 132;
91144
+ _context17.next = 148;
90988
91145
  break;
90989
91146
  }
90990
- return _context16.abrupt("return", _objectSpread$y(_objectSpread$y({
91147
+ return _context17.abrupt("return", _objectSpread$y(_objectSpread$y({
90991
91148
  written: written,
90992
91149
  failed: failed
90993
91150
  }, remaining.length ? {
@@ -90995,13 +91152,14 @@ function _writeAssetCellsBatch() {
90995
91152
  } : {}), {}, {
90996
91153
  note: "NOTHING was written".concat(failed.length ? ' — every started entry failed; see `failed`' : '', ".").concat(notStarted)
90997
91154
  }));
90998
- case 132:
91155
+ case 148:
90999
91156
  persistedCount = written.filter(function (w) {
91000
91157
  return w.persisted === true;
91001
- }).length; // Refetch only when EVERY write was confirmed — a refresh discards the pending ones.
91002
- gridRefreshed = persistedCount === written.length;
91158
+ }).length; // Refetch only when EVERY write was confirmed and nothing else is staged (a refused row left with the user's edits,
91159
+ // their own edits elsewhere) — a refresh discards every pending change.
91160
+ gridRefreshed = persistedCount === written.length && !((_handle$hasPendingCha12 = handle.hasPendingChanges) !== null && _handle$hasPendingCha12 !== void 0 && _handle$hasPendingCha12.call(handle));
91003
91161
  if (gridRefreshed) (_handle$refresh2 = handle.refresh) === null || _handle$refresh2 === void 0 || _handle$refresh2.call(handle);
91004
- return _context16.abrupt("return", _objectSpread$y(_objectSpread$y({
91162
+ return _context17.abrupt("return", _objectSpread$y(_objectSpread$y({
91005
91163
  written: written,
91006
91164
  failed: failed
91007
91165
  }, remaining.length ? {
@@ -91010,11 +91168,11 @@ function _writeAssetCellsBatch() {
91010
91168
  gridRefreshed: gridRefreshed,
91011
91169
  note: "".concat(persistedCount, "/").concat(cells.length, " cells PERSISTED on the server") + (needsLookup.length ? " (".concat(needsLookup.length, " located server-side and committed individually, ").concat(stageable.length, " in one commit).") : ' in one commit.') + (gridRefreshed ? ' The grid was refreshed from the server — the new assets are on screen.' : '') + (failed.length ? " ".concat(failed.length, " entr(y|ies) failed \u2014 see `failed`; retry only those.") : '') + (persistedCount < written.length ? ' Entries with persisted:false were staged but NOT confirmed — do not touch the table (no locateRow, no filter, no scroll): a reload discards them. Re-run those keys instead.' : '') + notStarted
91012
91170
  }));
91013
- case 136:
91171
+ case 152:
91014
91172
  case "end":
91015
- return _context16.stop();
91173
+ return _context17.stop();
91016
91174
  }
91017
- }, _callee16, null, [[46, 107, 110, 113], [54, 61]]);
91175
+ }, _callee17, null, [[46, 123, 126, 129], [54, 61]]);
91018
91176
  }));
91019
91177
  return _writeAssetCellsBatch.apply(this, arguments);
91020
91178
  }
@@ -91026,7 +91184,7 @@ var BATCH_SHARED_KEYS = ['style', 'styleUrl', 'format', 'canvasCm', 'jpgSizePx',
91026
91184
  * Generates and uploads a whole serie in ONE call. Deliberately does NOT attach: one setAssetCell
91027
91185
  * `cells:[…]` costs the user one approval bar instead of one per article. Markup stays out of the result.
91028
91186
  */
91029
- function generateArticleSvgBatch(_x38, _x39, _x40, _x41, _x42) {
91187
+ function generateArticleSvgBatch(_x43, _x44, _x45, _x46, _x47) {
91030
91188
  return _generateArticleSvgBatch.apply(this, arguments);
91031
91189
  }
91032
91190
  /**
@@ -91034,25 +91192,25 @@ function generateArticleSvgBatch(_x38, _x39, _x40, _x41, _x42) {
91034
91192
  * because asset cells store `{mediaitemId, url, name}` objects that only exist after an upload.
91035
91193
  */
91036
91194
  function _generateArticleSvgBatch() {
91037
- _generateArticleSvgBatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee17(root, shared, entries, storedStyle, signal) {
91195
+ _generateArticleSvgBatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee18(root, shared, entries, storedStyle, signal) {
91038
91196
  var _shared$format;
91039
91197
  var inherited, _iterator9, _step9, key, results, failed, startedAt, remaining, _iterator10, _step10, _step10$value, index, entry, merged, typeNo, _merged$format, _merged$fileName, _generated$warnings, spec, inline, generated, format, extension, rawName, fileName, file, uploaded, column;
91040
- return _regeneratorRuntime.wrap(function _callee17$(_context17) {
91041
- while (1) switch (_context17.prev = _context17.next) {
91198
+ return _regeneratorRuntime.wrap(function _callee18$(_context18) {
91199
+ while (1) switch (_context18.prev = _context18.next) {
91042
91200
  case 0:
91043
91201
  if (!(entries.length === 0)) {
91044
- _context17.next = 2;
91202
+ _context18.next = 2;
91045
91203
  break;
91046
91204
  }
91047
- return _context17.abrupt("return", {
91205
+ return _context18.abrupt("return", {
91048
91206
  error: 'batch is empty — pass one article spec per entry.'
91049
91207
  });
91050
91208
  case 2:
91051
91209
  if (!(entries.length > BATCH_MAX_ARTICLES)) {
91052
- _context17.next = 4;
91210
+ _context18.next = 4;
91053
91211
  break;
91054
91212
  }
91055
- return _context17.abrupt("return", {
91213
+ return _context18.abrupt("return", {
91056
91214
  error: "batch supports at most ".concat(BATCH_MAX_ARTICLES, " articles per call \u2014 got ").concat(entries.length, ". Split the serie.")
91057
91215
  });
91058
91216
  case 4:
@@ -91074,24 +91232,24 @@ function _generateArticleSvgBatch() {
91074
91232
  startedAt = Date.now();
91075
91233
  remaining = [];
91076
91234
  _iterator10 = _createForOfIteratorHelper$g(entries.entries());
91077
- _context17.prev = 12;
91235
+ _context18.prev = 12;
91078
91236
  _iterator10.s();
91079
91237
  case 14:
91080
91238
  if ((_step10 = _iterator10.n()).done) {
91081
- _context17.next = 55;
91239
+ _context18.next = 55;
91082
91240
  break;
91083
91241
  }
91084
91242
  _step10$value = _slicedToArray(_step10.value, 2), index = _step10$value[0], entry = _step10$value[1];
91085
91243
  merged = _objectSpread$y(_objectSpread$y({}, inherited), entry);
91086
91244
  typeNo = merged.typeNo === undefined ? undefined : String(merged.typeNo);
91087
91245
  if (!stopBatch(startedAt, TIME_BUDGET_MS, signal)) {
91088
- _context17.next = 21;
91246
+ _context18.next = 21;
91089
91247
  break;
91090
91248
  }
91091
91249
  remaining.push(typeNo !== null && typeNo !== void 0 ? typeNo : "#".concat(index + 1));
91092
- return _context17.abrupt("continue", 53);
91250
+ return _context18.abrupt("continue", 53);
91093
91251
  case 21:
91094
- _context17.prev = 21;
91252
+ _context18.prev = 21;
91095
91253
  spec = _objectSpread$y({}, merged);
91096
91254
  if (storedStyle) {
91097
91255
  inline = _typeof(merged.style) === 'object' && merged.style ? merged.style : undefined;
@@ -91100,7 +91258,7 @@ function _generateArticleSvgBatch() {
91100
91258
  generated = buildArticleTopViewSvg(spec);
91101
91259
  format = String((_merged$format = merged.format) !== null && _merged$format !== void 0 ? _merged$format : 'svg').trim().toLowerCase();
91102
91260
  if (['svg', 'jpg'].includes(format)) {
91103
- _context17.next = 28;
91261
+ _context18.next = 28;
91104
91262
  break;
91105
91263
  }
91106
91264
  throw new Error("format must be 'svg' or 'jpg' \u2014 got '".concat(merged.format, "'."));
@@ -91109,32 +91267,32 @@ function _generateArticleSvgBatch() {
91109
91267
  rawName = String((_merged$fileName = merged.fileName) !== null && _merged$fileName !== void 0 ? _merged$fileName : typeNo ? "top-".concat(typeNo).concat(extension) : "top-view-".concat(index + 1).concat(extension));
91110
91268
  fileName = rawName.toLowerCase().endsWith(extension) ? rawName : "".concat(rawName.replace(/\.(svg|jpe?g)$/i, '')).concat(extension);
91111
91269
  if (!(format === 'jpg')) {
91112
- _context17.next = 42;
91270
+ _context18.next = 42;
91113
91271
  break;
91114
91272
  }
91115
- _context17.t1 = File;
91116
- _context17.next = 35;
91273
+ _context18.t1 = File;
91274
+ _context18.next = 35;
91117
91275
  return svgToJpegBlob(generated.svg, Math.max(64, Math.min(4096, Number(merged.jpgSizePx) || 1024)));
91118
91276
  case 35:
91119
- _context17.t2 = _context17.sent;
91120
- _context17.t3 = [_context17.t2];
91121
- _context17.t4 = fileName;
91122
- _context17.t5 = {
91277
+ _context18.t2 = _context18.sent;
91278
+ _context18.t3 = [_context18.t2];
91279
+ _context18.t4 = fileName;
91280
+ _context18.t5 = {
91123
91281
  type: 'image/jpeg'
91124
91282
  };
91125
- _context17.t0 = new _context17.t1(_context17.t3, _context17.t4, _context17.t5);
91126
- _context17.next = 43;
91283
+ _context18.t0 = new _context18.t1(_context18.t3, _context18.t4, _context18.t5);
91284
+ _context18.next = 43;
91127
91285
  break;
91128
91286
  case 42:
91129
- _context17.t0 = new File([generated.svg], fileName, {
91287
+ _context18.t0 = new File([generated.svg], fileName, {
91130
91288
  type: 'image/svg+xml'
91131
91289
  });
91132
91290
  case 43:
91133
- file = _context17.t0;
91134
- _context17.next = 46;
91291
+ file = _context18.t0;
91292
+ _context18.next = 46;
91135
91293
  return uploadToMediaService(root, file, fileName, undefined, signal);
91136
91294
  case 46:
91137
- uploaded = _context17.sent;
91295
+ uploaded = _context18.sent;
91138
91296
  results.push(_objectSpread$y(_objectSpread$y({}, typeNo ? {
91139
91297
  typeNo: typeNo
91140
91298
  } : {}), {}, {
@@ -91146,35 +91304,35 @@ function _generateArticleSvgBatch() {
91146
91304
  }, (_generated$warnings = generated.warnings) !== null && _generated$warnings !== void 0 && _generated$warnings.length ? {
91147
91305
  warnings: generated.warnings
91148
91306
  } : {}));
91149
- _context17.next = 53;
91307
+ _context18.next = 53;
91150
91308
  break;
91151
91309
  case 50:
91152
- _context17.prev = 50;
91153
- _context17.t6 = _context17["catch"](21);
91310
+ _context18.prev = 50;
91311
+ _context18.t6 = _context18["catch"](21);
91154
91312
  failed.push(_objectSpread$y(_objectSpread$y({
91155
91313
  index: index
91156
91314
  }, typeNo ? {
91157
91315
  typeNo: typeNo
91158
91316
  } : {}), {}, {
91159
- error: _context17.t6 instanceof Error ? _context17.t6.message : String(_context17.t6)
91317
+ error: _context18.t6 instanceof Error ? _context18.t6.message : String(_context18.t6)
91160
91318
  }));
91161
91319
  case 53:
91162
- _context17.next = 14;
91320
+ _context18.next = 14;
91163
91321
  break;
91164
91322
  case 55:
91165
- _context17.next = 60;
91323
+ _context18.next = 60;
91166
91324
  break;
91167
91325
  case 57:
91168
- _context17.prev = 57;
91169
- _context17.t7 = _context17["catch"](12);
91170
- _iterator10.e(_context17.t7);
91326
+ _context18.prev = 57;
91327
+ _context18.t7 = _context18["catch"](12);
91328
+ _iterator10.e(_context18.t7);
91171
91329
  case 60:
91172
- _context17.prev = 60;
91330
+ _context18.prev = 60;
91173
91331
  _iterator10.f();
91174
- return _context17.finish(60);
91332
+ return _context18.finish(60);
91175
91333
  case 63:
91176
91334
  column = shared.column ? String(shared.column) : String((_shared$format = shared.format) !== null && _shared$format !== void 0 ? _shared$format : 'svg') === 'jpg' ? 'images' : 'svgs';
91177
- return _context17.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
91335
+ return _context18.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
91178
91336
  batch: true,
91179
91337
  uploaded: results.length
91180
91338
  }, failed.length ? {
@@ -91187,9 +91345,9 @@ function _generateArticleSvgBatch() {
91187
91345
  }));
91188
91346
  case 65:
91189
91347
  case "end":
91190
- return _context17.stop();
91348
+ return _context18.stop();
91191
91349
  }
91192
- }, _callee17, null, [[12, 57, 60, 63], [21, 50]]);
91350
+ }, _callee18, null, [[12, 57, 60, 63], [21, 50]]);
91193
91351
  }));
91194
91352
  return _generateArticleSvgBatch.apply(this, arguments);
91195
91353
  }
@@ -91260,7 +91418,7 @@ function createMediaToolset(ctx) {
91260
91418
  }
91261
91419
  }, _callee, null, [[5, 11]]);
91262
91420
  }));
91263
- return function uploadOne(_x46) {
91421
+ return function uploadOne(_x51) {
91264
91422
  return _ref.apply(this, arguments);
91265
91423
  };
91266
91424
  }(); // BATCH: sequential on purpose — a parallel burst of three-request handshakes fails halfway.
@@ -91474,7 +91632,8 @@ function createMediaToolset(ctx) {
91474
91632
  } : {}), usage ? {
91475
91633
  usage: usage
91476
91634
  } : {}), {}, {
91477
- note: "".concat(_results.length - _failed.length, "/").concat(_results.length, " generated (usage = cumulative counters after the last one).") + (_failed.length ? ' Failed entries carry their reason — retry only those.' : '') + (_remaining.length ? " ".concat(notStartedNote(_remaining), " \u2014 re-call with only those; everything in 'generated' is DONE.") : '') + ' LOOK at the results before wiring (one contact sheet, not one review per file), then write them with setAssetCell cells.'
91635
+ note: "".concat(_results.length - _failed.length, "/").concat(_results.length, " generated (usage = cumulative counters after the last one).") + (_failed.length ? ' Failed entries carry their reason — retry only those.' : '') + (_remaining.length ? " ".concat(notStartedNote(_remaining), " \u2014 re-call with only those; everything in 'generated' is DONE.") : '') + ' LOOK at the results before wiring (one contact sheet, not one review per file), then write them with setAssetCell cells.' + " ".concat(NOT_ATTACHED_NOTE),
91636
+ attached: false
91478
91637
  }));
91479
91638
  case 99:
91480
91639
  return _context2.abrupt("return", generateImageAsset(root, args, signal));
@@ -91878,7 +92037,7 @@ function createMediaToolset(ctx) {
91878
92037
  }
91879
92038
  }, _callee2, null, [[14, 35, 38, 41], [66, 91, 94, 97], [76, 82], [131, 145], [149, 163], [183, 189], [199, 218]]);
91880
92039
  }));
91881
- function dispatch(_x43, _x44, _x45) {
92040
+ function dispatch(_x48, _x49, _x50) {
91882
92041
  return _dispatch.apply(this, arguments);
91883
92042
  }
91884
92043
  return dispatch;
@@ -91900,7 +92059,7 @@ var hasPlannedArticle = function hasPlannedArticle(planner) {
91900
92059
  return Object.keys((_planner$getDivaArtic = planner.getDivaArticles()) !== null && _planner$getDivaArtic !== void 0 ? _planner$getDivaArtic : {}).length > 0;
91901
92060
  };
91902
92061
  var DivaAgent = function DivaAgent(_ref) {
91903
- var _findRegisteredTool, _registeredTool$eleme, _registeredTool$eleme2, _registeredTool$param, _registeredTool$eleme3, _root$i18n$language, _root$navigationState3, _core$state$organizat, _core$state$organizat2, _root$navigationState4, _catalogMatch$, _root$dataStore$curre;
92062
+ var _findRegisteredTool, _registeredTool$eleme, _registeredTool$eleme2, _registeredTool$param, _core$state$navigatio, _core$state$organizat, _core$state$organizat2, _registeredTool$eleme3, _root$i18n$language, _root$navigationState3, _core$state$organizat3, _core$state$organizat4, _root$navigationState4, _catalogMatch$, _root$dataStore$curre;
91904
92063
  var tool = _ref.tool;
91905
92064
  var root = useStore();
91906
92065
  var core = useDivaCore();
@@ -91934,6 +92093,9 @@ var DivaAgent = function DivaAgent(_ref) {
91934
92093
  catalogId: catalogId
91935
92094
  });
91936
92095
  }, [registeredTool.parameters, catalogId]);
92096
+ // The read-only advisor refers what it cannot settle to the portal's support form. The organization placeholder is
92097
+ // resolved as the navigator's own support link does; ${zToken} never is — the JWT must not reach the prompt.
92098
+ var supportUrl = (_core$state$navigatio = core.state.navigationConfiguration) === null || _core$state$navigatio === void 0 || (_core$state$navigatio = _core$state$navigatio.supportUrl) === null || _core$state$navigatio === void 0 ? void 0 : _core$state$navigatio.replace('${organizationId}', (_core$state$organizat = (_core$state$organizat2 = core.state.organization) === null || _core$state$organizat2 === void 0 ? void 0 : _core$state$organizat2._id) !== null && _core$state$organizat !== void 0 ? _core$state$organizat : '');
91937
92099
 
91938
92100
  // Same initial-language formula as the WYSIWYG so the instance keys match.
91939
92101
  var availableLanguages = ((_registeredTool$eleme3 = registeredTool.elementProps) === null || _registeredTool$eleme3 === void 0 ? void 0 : _registeredTool$eleme3.isoLanguageIds) || ['DE'];
@@ -92017,7 +92179,8 @@ var DivaAgent = function DivaAgent(_ref) {
92017
92179
  catalogId: catalogId,
92018
92180
  packageId: packageId,
92019
92181
  autoApprove: !!settings.autoApprove,
92020
- getSelection: getExpectedSelection
92182
+ getSelection: getExpectedSelection,
92183
+ supportUrl: supportUrl
92021
92184
  });
92022
92185
  var media = createMediaToolset({
92023
92186
  root: root,
@@ -92036,7 +92199,7 @@ var DivaAgent = function DivaAgent(_ref) {
92036
92199
  return [mergeToolsets(base, [navigation, media, content])];
92037
92200
  },
92038
92201
  // liveParameters/catalogId track the ROUTE so the toolsets are rebuilt when navigation moves catalog.
92039
- [tool, language, liveParameters, catalogId, packageId, getExpectedSelection]);
92202
+ [tool, language, liveParameters, catalogId, packageId, getExpectedSelection, supportUrl]);
92040
92203
 
92041
92204
  // A reloadPage call left the view's serie/article behind: re-apply it, so the planner comes back on the same article.
92042
92205
  // Not aborted on cleanup — StrictMode runs this twice, and only the first run finds the stored selection. It stops once
@@ -92245,7 +92408,7 @@ var DivaAgent = function DivaAgent(_ref) {
92245
92408
  }, [root, t]);
92246
92409
 
92247
92410
  // Chat pool is keyed per organization; the catalog/package context is only a TAG on each conversation.
92248
- var contextKey = "organization:".concat((_core$state$organizat = (_core$state$organizat2 = core.state.organization) === null || _core$state$organizat2 === void 0 ? void 0 : _core$state$organizat2._id) !== null && _core$state$organizat !== void 0 ? _core$state$organizat : 'unknown');
92411
+ var contextKey = "organization:".concat((_core$state$organizat3 = (_core$state$organizat4 = core.state.organization) === null || _core$state$organizat4 === void 0 ? void 0 : _core$state$organizat4._id) !== null && _core$state$organizat3 !== void 0 ? _core$state$organizat3 : 'unknown');
92249
92412
  var navPath = (_root$navigationState4 = root.navigationState.path) !== null && _root$navigationState4 !== void 0 ? _root$navigationState4 : '';
92250
92413
  var packageMatch = navPath.match(/^\/?packages\/([^/]+)/);
92251
92414
  var catalogMatch = navPath.match(/^\/?catalogs\/([^/]+)/);
@@ -92261,6 +92424,7 @@ var DivaAgent = function DivaAgent(_ref) {
92261
92424
  return root.actions.userHasPermission(object);
92262
92425
  }, (_root$dataStore$curre = root.dataStore.currentOrganization) === null || _root$dataStore$curre === void 0 ? void 0 : _root$dataStore$curre.settings),
92263
92426
  chatPermitted = _agentAccess.chat,
92427
+ editPermitted = _agentAccess.edit,
92264
92428
  mcpPermitted = _agentAccess.mcp;
92265
92429
 
92266
92430
  // Without the chat the panel is being unmounted (useTools) — mounting the chat now would only collect 403s.
@@ -92294,6 +92458,7 @@ var DivaAgent = function DivaAgent(_ref) {
92294
92458
  readyForAutoContinue: (!serie || !!planner || !!initError) && !pendingNav && !restoringSelection,
92295
92459
  onEntityLink: onEntityLink,
92296
92460
  enableBridge: mcpPermitted,
92461
+ allowAutoApprove: editPermitted,
92297
92462
  style: {
92298
92463
  flex: '1 1 0',
92299
92464
  minHeight: 0,