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

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.
@@ -66998,6 +66998,7 @@ var Options$1 = /*#__PURE__*/forwardRef(function Options(_ref, ref) {
66998
66998
  }
66999
66999
  },
67000
67000
  allowedTypes: ['image/png', 'image/jpeg', 'image/webp'],
67001
+ // Serie only: IDM scopes an option's detail info by SERIE_REF and has no article scope for it.
67001
67002
  additionalFields: [{
67002
67003
  type: 'lookup',
67003
67004
  field: 'serieNo',
@@ -67013,18 +67014,6 @@ var Options$1 = /*#__PURE__*/forwardRef(function Options(_ref, ref) {
67013
67014
  lookupField: '_id',
67014
67015
  targetField: 'serieId'
67015
67016
  }]
67016
- }, {
67017
- type: 'lookup',
67018
- field: 'itemTypeNo',
67019
- label: 'backoffice.idmCatalog.prices.label.typeNo',
67020
- lookupLabelTemplate: '${name} (${value})',
67021
- apiInterface: {
67022
- read: apiConfig.idmService + '/catalogs/${catalogId}/series/${serieId}/items'
67023
- },
67024
- lookupValue: 'shortText',
67025
- lookupKey: 'typeNo',
67026
- translated: true,
67027
- dependsOn: ['serieId']
67028
67017
  }]
67029
67018
  }
67030
67019
  }, {
@@ -67046,6 +67035,7 @@ var Options$1 = /*#__PURE__*/forwardRef(function Options(_ref, ref) {
67046
67035
  }
67047
67036
  },
67048
67037
  allowedTypes: ['image/png', 'image/jpeg', 'image/webp'],
67038
+ // Serie only: IDM scopes an option's detail info by SERIE_REF and has no article scope for it.
67049
67039
  additionalFields: [{
67050
67040
  type: 'lookup',
67051
67041
  field: 'serieNo',
@@ -67061,18 +67051,6 @@ var Options$1 = /*#__PURE__*/forwardRef(function Options(_ref, ref) {
67061
67051
  lookupField: '_id',
67062
67052
  targetField: 'serieId'
67063
67053
  }]
67064
- }, {
67065
- type: 'lookup',
67066
- field: 'itemTypeNo',
67067
- label: 'backoffice.idmCatalog.prices.label.typeNo',
67068
- lookupLabelTemplate: '${name} (${value})',
67069
- apiInterface: {
67070
- read: apiConfig.idmService + '/catalogs/${catalogId}/series/${serieId}/items'
67071
- },
67072
- lookupValue: 'shortText',
67073
- lookupKey: 'typeNo',
67074
- translated: true,
67075
- dependsOn: ['serieId']
67076
67054
  }]
67077
67055
  }
67078
67056
  }, {
@@ -84358,7 +84336,7 @@ function createNavigationToolset(ctx) {
84358
84336
  if (type === 'asset') {
84359
84337
  return {
84360
84338
  ok: false,
84361
- error: "Column '".concat(column, "' is an ASSET cell \u2014 not writable via stageTableEdits. Use uploadAsset (URL/SVG \u2192 mediaItemId) + setAssetCell('").concat(column, "'), or generateArticleSvg for an item's top-view SVG.")
84339
+ error: "Column '".concat(column, "' is an ASSET cell \u2014 not writable via stageTableEdits. Use uploadAsset (URL/SVG \u2192 mediaItemId) + setAssetCell('").concat(column, "'), generateImageAsset with a target for an AI-generated image, or generateArticleSvg for an item's top-view SVG.")
84362
84340
  };
84363
84341
  }
84364
84342
  var enumData = enumEntriesOf(divaDef === null || divaDef === void 0 || (_divaDef$customParams6 = divaDef.customParams) === null || _divaDef$customParams6 === void 0 ? void 0 : _divaDef$customParams6.enumData);
@@ -88988,6 +88966,39 @@ var TIME_BUDGET_MS = 100000;
88988
88966
  /** IDM's media name (DETAIL_INFO INTERNAL_NAME, languagetext40) holds at most this many characters. */
88989
88967
  var IDM_MEDIA_NAME_MAX = 40;
88990
88968
 
88969
+ /**
88970
+ * The upload takes any file name, but an IDM asset cell stores the MEDIA ITEM's own name (idm ItemService
88971
+ * CreateMediaitemAndDetailinfo), so a longer one makes every later write of it fail — a cell 'name' does not help.
88972
+ */
88973
+ var longNameNote = function longNameNote(fileNames) {
88974
+ var tooLong = fileNames.filter(function (fileName) {
88975
+ return fileName.length > IDM_MEDIA_NAME_MAX;
88976
+ });
88977
+ return tooLong.length ? " NAME TOO LONG for an IDM asset cell (at most ".concat(IDM_MEDIA_NAME_MAX, " characters): ").concat(tooLong.join(', '), " \u2014 writing it into a catalog table with setAssetCell WILL be refused, because IDM takes the media item's own name: upload it again under a name of at most ").concat(IDM_MEDIA_NAME_MAX, " characters.") : '';
88978
+ };
88979
+
88980
+ /** A media name an IDM asset cell takes: cut to the limit, keeping the extension (it names the file type in the cell). */
88981
+ function fitMediaName(fileName) {
88982
+ if (fileName.length <= IDM_MEDIA_NAME_MAX) return fileName;
88983
+ var dot = fileName.lastIndexOf('.');
88984
+ var suffix = dot > 0 && fileName.length - dot <= 6 ? fileName.slice(dot) : '';
88985
+ return "".concat(fileName.slice(0, IDM_MEDIA_NAME_MAX - suffix.length).trimEnd()).concat(suffix);
88986
+ }
88987
+
88988
+ /** The note part about media names cut to the IDM limit before the upload. */
88989
+ var shortenedNameNote = function shortenedNameNote(names) {
88990
+ return names.length ? " NAME SHORTENED to ".concat(names.join(', '), ": an IDM asset cell takes the media item's own name, which holds at most ").concat(IDM_MEDIA_NAME_MAX, " characters.") : '';
88991
+ };
88992
+
88993
+ /**
88994
+ * How long after its start a call that generates AND attaches may still write. The bridge cuts every call at 270 s
88995
+ * (CALL_EXECUTION_TIMEOUT_MS in diva-agent's bridge) and the receipt of every image generated so far is lost with it,
88996
+ * so the attach stops starting rows — and withdraws an unanswered approval bar — well before that.
88997
+ */
88998
+ var ATTACH_DEADLINE_MS = 220000;
88999
+ /** What a call with targets keeps of that deadline for the write bar and the writes: no new image starts after it. */
89000
+ var ATTACH_RESERVE_MS = 60000;
89001
+
88991
89002
  /** Batches stop at the turn's abort or time budget and hand the untouched rest back. */
88992
89003
  var stopBatch = function stopBatch(startedAt, budgetMs, signal) {
88993
89004
  return (signal === null || signal === void 0 ? void 0 : signal.aborted) || Date.now() - startedAt > budgetMs;
@@ -89260,7 +89271,7 @@ function _uploadToMediaService() {
89260
89271
  'Content-Type': 'application/json'
89261
89272
  };
89262
89273
  asText = /*#__PURE__*/function () {
89263
- var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5(response) {
89274
+ var _ref11 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5(response) {
89264
89275
  return _regeneratorRuntime.wrap(function _callee5$(_context5) {
89265
89276
  while (1) switch (_context5.prev = _context5.next) {
89266
89277
  case 0:
@@ -89276,8 +89287,8 @@ function _uploadToMediaService() {
89276
89287
  }
89277
89288
  }, _callee5);
89278
89289
  }));
89279
- return function asText(_x52) {
89280
- return _ref2.apply(this, arguments);
89290
+ return function asText(_x59) {
89291
+ return _ref11.apply(this, arguments);
89281
89292
  };
89282
89293
  }();
89283
89294
  _context6.next = 12;
@@ -89667,7 +89678,7 @@ function _getAssetUrls() {
89667
89678
  }));
89668
89679
  return _getAssetUrls.apply(this, arguments);
89669
89680
  }
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.';
89681
+ var NOT_ATTACHED_NOTE = 'NOT ATTACHED: no article, option or other row shows it yet. Images asked for rows are not done until they are written into their cells (target, or setAssetCell) — never report them as done before that.';
89671
89682
 
89672
89683
  /**
89673
89684
  * Generates ONE image through the DIVA AI service and stores it on the media service. The bytes
@@ -89681,12 +89692,12 @@ function generateImageAsset(_x19, _x20, _x21) {
89681
89692
  function _generateImageAsset() {
89682
89693
  _generateImageAsset = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee10(root, args, signal) {
89683
89694
  var _args$fileName3, _args$prompt, _args$mode, _args$model, _args$resolution, _args$promptId, _payload, _images$0$url, _images$;
89684
- var fileName, prompt, mode, base, jwt, organizationId, referenceUrls, unresolved, _iterator4, _step4, _raw, mediaItemId, url, localReference, clause, finalPrompt, model, engine, resolution, promptId, body, response, raw, detail, payload, images, _payload2, _payload3, dataUrl, file, _MIME_BY_EXTENSION$ex3, blob, _payload$model, _payload4, _payload5, _payload$usageTrackin, _payload6, uploaded;
89695
+ var requestedFileName, fileName, shortened, prompt, mode, base, jwt, organizationId, referenceUrls, unresolved, _iterator4, _step4, _raw, mediaItemId, url, localReference, clause, finalPrompt, model, engine, resolution, promptId, body, response, raw, detail, payload, images, _payload2, _payload3, dataUrl, file, _MIME_BY_EXTENSION$ex3, blob, _payload$model, _payload4, _payload5, _payload$usageTrackin, _payload6, uploaded;
89685
89696
  return _regeneratorRuntime.wrap(function _callee10$(_context10) {
89686
89697
  while (1) switch (_context10.prev = _context10.next) {
89687
89698
  case 0:
89688
- fileName = String((_args$fileName3 = args.fileName) !== null && _args$fileName3 !== void 0 ? _args$fileName3 : '').trim();
89689
- if (fileName) {
89699
+ requestedFileName = String((_args$fileName3 = args.fileName) !== null && _args$fileName3 !== void 0 ? _args$fileName3 : '').trim();
89700
+ if (requestedFileName) {
89690
89701
  _context10.next = 3;
89691
89702
  break;
89692
89703
  }
@@ -89694,116 +89705,119 @@ function _generateImageAsset() {
89694
89705
  error: "fileName (with extension, e.g. 'foot-191.png') is required."
89695
89706
  });
89696
89707
  case 3:
89697
- if (extensionOf(fileName)) {
89708
+ if (extensionOf(requestedFileName)) {
89698
89709
  _context10.next = 5;
89699
89710
  break;
89700
89711
  }
89701
89712
  return _context10.abrupt("return", {
89702
- error: "".concat(fileName, ": fileName needs an extension (e.g. '.png') \u2014 it decides the media type.")
89713
+ error: "".concat(requestedFileName, ": fileName needs an extension (e.g. '.png') \u2014 it decides the media type.")
89703
89714
  });
89704
89715
  case 5:
89716
+ // The media item's name is what an IDM asset cell stores — fitted here, a later write cannot be refused for it.
89717
+ fileName = fitMediaName(requestedFileName);
89718
+ shortened = fileName !== requestedFileName;
89705
89719
  prompt = String((_args$prompt = args.prompt) !== null && _args$prompt !== void 0 ? _args$prompt : '').trim();
89706
89720
  if (prompt) {
89707
- _context10.next = 8;
89721
+ _context10.next = 10;
89708
89722
  break;
89709
89723
  }
89710
89724
  return _context10.abrupt("return", {
89711
89725
  error: 'prompt is required — describe what the image should show.'
89712
89726
  });
89713
- case 8:
89727
+ case 10:
89714
89728
  mode = String((_args$mode = args.mode) !== null && _args$mode !== void 0 ? _args$mode : '').trim();
89715
89729
  if (['product', 'texture', 'free'].includes(mode)) {
89716
- _context10.next = 11;
89730
+ _context10.next = 13;
89717
89731
  break;
89718
89732
  }
89719
89733
  return _context10.abrupt("return", {
89720
89734
  error: "mode must be 'product', 'texture' or 'free' \u2014 got '".concat(args.mode, "'.")
89721
89735
  });
89722
- case 11:
89736
+ case 13:
89723
89737
  base = root.configurationStore.apiConfig.aiService;
89724
89738
  jwt = root.dataStore.jwt;
89725
89739
  organizationId = root.dataStore.selectedOrganizationId;
89726
89740
  if (!(!base || !jwt || !organizationId)) {
89727
- _context10.next = 16;
89741
+ _context10.next = 18;
89728
89742
  break;
89729
89743
  }
89730
89744
  return _context10.abrupt("return", {
89731
89745
  error: 'AI service, session or organization context is missing.'
89732
89746
  });
89733
- case 16:
89747
+ case 18:
89734
89748
  // References first: validating after a paid generation is the expensive order.
89735
89749
  referenceUrls = Array.isArray(args.referenceUrls) ? args.referenceUrls.map(function (entry) {
89736
89750
  return String(entry).trim();
89737
89751
  }).filter(Boolean) : [];
89738
89752
  unresolved = [];
89739
89753
  if (!Array.isArray(args.referenceMediaItemIds)) {
89740
- _context10.next = 41;
89754
+ _context10.next = 43;
89741
89755
  break;
89742
89756
  }
89743
89757
  _iterator4 = _createForOfIteratorHelper$g(args.referenceMediaItemIds);
89744
- _context10.prev = 20;
89758
+ _context10.prev = 22;
89745
89759
  _iterator4.s();
89746
- case 22:
89760
+ case 24:
89747
89761
  if ((_step4 = _iterator4.n()).done) {
89748
- _context10.next = 33;
89762
+ _context10.next = 35;
89749
89763
  break;
89750
89764
  }
89751
89765
  _raw = _step4.value;
89752
89766
  mediaItemId = String(_raw !== null && _raw !== void 0 ? _raw : '').trim();
89753
89767
  if (mediaItemId) {
89754
- _context10.next = 27;
89768
+ _context10.next = 29;
89755
89769
  break;
89756
89770
  }
89757
- return _context10.abrupt("continue", 31);
89758
- case 27:
89759
- _context10.next = 29;
89760
- return mediaItemUrl(root, mediaItemId, signal);
89771
+ return _context10.abrupt("continue", 33);
89761
89772
  case 29:
89773
+ _context10.next = 31;
89774
+ return mediaItemUrl(root, mediaItemId, signal);
89775
+ case 31:
89762
89776
  url = _context10.sent;
89763
89777
  if (url) referenceUrls.push(url);else unresolved.push(mediaItemId);
89764
- case 31:
89765
- _context10.next = 22;
89766
- break;
89767
89778
  case 33:
89768
- _context10.next = 38;
89779
+ _context10.next = 24;
89769
89780
  break;
89770
89781
  case 35:
89771
- _context10.prev = 35;
89772
- _context10.t0 = _context10["catch"](20);
89782
+ _context10.next = 40;
89783
+ break;
89784
+ case 37:
89785
+ _context10.prev = 37;
89786
+ _context10.t0 = _context10["catch"](22);
89773
89787
  _iterator4.e(_context10.t0);
89774
- case 38:
89775
- _context10.prev = 38;
89788
+ case 40:
89789
+ _context10.prev = 40;
89776
89790
  _iterator4.f();
89777
- return _context10.finish(38);
89778
- case 41:
89791
+ return _context10.finish(40);
89792
+ case 43:
89779
89793
  if (!unresolved.length) {
89780
- _context10.next = 43;
89794
+ _context10.next = 45;
89781
89795
  break;
89782
89796
  }
89783
89797
  return _context10.abrupt("return", {
89784
89798
  error: "No downloadable url for media item(s) ".concat(unresolved.join(', '), " \u2014 pass 'referenceUrls' directly instead.")
89785
89799
  });
89786
- case 43:
89800
+ case 45:
89787
89801
  // A loopback reference is only wrong when the AI service is REMOTE — localhost is then the server's own machine.
89788
89802
  localReference = referenceUrls.find(function (url) {
89789
89803
  return LOOPBACK_HOST.test(url);
89790
89804
  });
89791
89805
  if (!(localReference && !LOOPBACK_HOST.test(base))) {
89792
- _context10.next = 46;
89806
+ _context10.next = 48;
89793
89807
  break;
89794
89808
  }
89795
89809
  return _context10.abrupt("return", {
89796
89810
  error: "Reference '".concat(localReference, "' is a loopback url, and the AI service at ").concat(base, " is not local. The SERVICE downloads references, not ") + 'the browser, so localhost there points at the server itself. Upload the file with uploadAsset first and pass the returned media item ' + '(referenceMediaItemIds) or its CDN url.'
89797
89811
  });
89798
- case 46:
89812
+ case 48:
89799
89813
  if (!(mode === 'product' && !referenceUrls.length)) {
89800
- _context10.next = 48;
89814
+ _context10.next = 50;
89801
89815
  break;
89802
89816
  }
89803
89817
  return _context10.abrupt("return", {
89804
89818
  error: "mode 'product' promises an IDENTICAL product, which is only possible against a source image — pass referenceUrls or " + "referenceMediaItemIds. Without a reference the model invents a similar-looking product; use mode 'free' if that is really what you want."
89805
89819
  });
89806
- case 48:
89820
+ case 50:
89807
89821
  clause = mode === 'product' ? PRODUCT_PRESERVE_CLAUSE : mode === 'texture' ? TEXTURE_CLAUSE : '';
89808
89822
  finalPrompt = clause ? "".concat(prompt.replace(/\s*$/, ''), "\n\n").concat(clause) : prompt;
89809
89823
  model = String((_args$model = args.model) !== null && _args$model !== void 0 ? _args$model : '').trim() || DEFAULT_IMAGE_MODEL;
@@ -89811,7 +89825,7 @@ function _generateImageAsset() {
89811
89825
  resolution = String((_args$resolution = args.resolution) !== null && _args$resolution !== void 0 ? _args$resolution : '').trim() || DEFAULT_RESOLUTION;
89812
89826
  promptId = String((_args$promptId = args.promptId) !== null && _args$promptId !== void 0 ? _args$promptId : '').trim() || undefined;
89813
89827
  if (!args.dryRun) {
89814
- _context10.next = 56;
89828
+ _context10.next = 58;
89815
89829
  break;
89816
89830
  }
89817
89831
  return _context10.abrupt("return", {
@@ -89823,7 +89837,7 @@ function _generateImageAsset() {
89823
89837
  resolution: resolution,
89824
89838
  note: 'Nothing was generated and nothing was charged. Re-run without dryRun to produce the image.'
89825
89839
  });
89826
- case 56:
89840
+ case 58:
89827
89841
  body = _objectSpread$y(_objectSpread$y({
89828
89842
  organizationId: organizationId,
89829
89843
  referenceImages: referenceUrls,
@@ -89838,15 +89852,15 @@ function _generateImageAsset() {
89838
89852
  temperature: args.temperature
89839
89853
  } : {}); // A call cancelled before the request goes out sends nothing — that costs no budget.
89840
89854
  if (!(signal !== null && signal !== void 0 && signal.aborted)) {
89841
- _context10.next = 59;
89855
+ _context10.next = 61;
89842
89856
  break;
89843
89857
  }
89844
89858
  return _context10.abrupt("return", {
89845
89859
  error: 'The call was cancelled before the generation started — nothing was generated or charged.'
89846
89860
  });
89847
- case 59:
89848
- _context10.prev = 59;
89849
- _context10.next = 62;
89861
+ case 61:
89862
+ _context10.prev = 61;
89863
+ _context10.next = 64;
89850
89864
  return fetch("".concat(base, "/generate-image-with-references"), {
89851
89865
  method: 'POST',
89852
89866
  headers: {
@@ -89855,25 +89869,25 @@ function _generateImageAsset() {
89855
89869
  },
89856
89870
  body: JSON.stringify(body)
89857
89871
  });
89858
- case 62:
89872
+ case 64:
89859
89873
  response = _context10.sent;
89860
- _context10.next = 68;
89874
+ _context10.next = 70;
89861
89875
  break;
89862
- case 65:
89863
- _context10.prev = 65;
89864
- _context10.t1 = _context10["catch"](59);
89876
+ case 67:
89877
+ _context10.prev = 67;
89878
+ _context10.t1 = _context10["catch"](61);
89865
89879
  return _context10.abrupt("return", {
89866
89880
  error: "The AI service could not be reached: ".concat(_context10.t1 instanceof Error ? _context10.t1.message : String(_context10.t1))
89867
89881
  });
89868
- case 68:
89869
- _context10.next = 70;
89882
+ case 70:
89883
+ _context10.next = 72;
89870
89884
  return response.text()["catch"](function () {
89871
89885
  return '';
89872
89886
  });
89873
- case 70:
89887
+ case 72:
89874
89888
  raw = _context10.sent;
89875
89889
  if (response.ok) {
89876
- _context10.next = 74;
89890
+ _context10.next = 76;
89877
89891
  break;
89878
89892
  }
89879
89893
  detail = raw.slice(0, 400);
@@ -89881,81 +89895,84 @@ function _generateImageAsset() {
89881
89895
  error: "Image generation failed: HTTP ".concat(response.status, " \u2014 ").concat(detail),
89882
89896
  hint: response.status === 429 ? "The organization's AI budget or the rate limit is exhausted — usage limits live under admin, this is not a retryable error." : response.status === 400 && /reference/i.test(detail) ? 'The service could not download a reference image — it must be publicly reachable FROM THE SERVER.' : undefined
89883
89897
  });
89884
- case 74:
89885
- _context10.prev = 74;
89898
+ case 76:
89899
+ _context10.prev = 76;
89886
89900
  payload = JSON.parse(raw);
89887
- _context10.next = 81;
89901
+ _context10.next = 83;
89888
89902
  break;
89889
- case 78:
89890
- _context10.prev = 78;
89891
- _context10.t2 = _context10["catch"](74);
89903
+ case 80:
89904
+ _context10.prev = 80;
89905
+ _context10.t2 = _context10["catch"](76);
89892
89906
  return _context10.abrupt("return", {
89893
89907
  error: "The AI service answered with a body this tool could not parse: ".concat(raw.slice(0, 200))
89894
89908
  });
89895
- case 81:
89909
+ case 83:
89896
89910
  images = Array.isArray((_payload = payload) === null || _payload === void 0 ? void 0 : _payload.images) ? payload.images : [];
89897
89911
  if (images.length) {
89898
- _context10.next = 84;
89912
+ _context10.next = 86;
89899
89913
  break;
89900
89914
  }
89901
89915
  return _context10.abrupt("return", {
89902
89916
  error: "The AI service returned no image".concat((_payload2 = payload) !== null && _payload2 !== void 0 && _payload2.error ? " (".concat(payload.error, ")") : '', "."),
89903
89917
  finalPrompt: (_payload3 = payload) === null || _payload3 === void 0 ? void 0 : _payload3.finalPrompt
89904
89918
  });
89905
- case 84:
89919
+ case 86:
89906
89920
  dataUrl = String((_images$0$url = (_images$ = images[0]) === null || _images$ === void 0 ? void 0 : _images$.url) !== null && _images$0$url !== void 0 ? _images$0$url : '');
89907
89921
  if (/^data:image\//i.test(dataUrl)) {
89908
- _context10.next = 87;
89922
+ _context10.next = 89;
89909
89923
  break;
89910
89924
  }
89911
89925
  return _context10.abrupt("return", {
89912
89926
  error: 'The generated image did not come back as image data.'
89913
89927
  });
89914
- case 87:
89915
- _context10.prev = 87;
89916
- _context10.next = 90;
89917
- return fetch(dataUrl);
89918
- case 90:
89928
+ case 89:
89929
+ _context10.prev = 89;
89919
89930
  _context10.next = 92;
89920
- return _context10.sent.blob();
89931
+ return fetch(dataUrl);
89921
89932
  case 92:
89933
+ _context10.next = 94;
89934
+ return _context10.sent.blob();
89935
+ case 94:
89922
89936
  blob = _context10.sent;
89923
89937
  file = new File([blob], fileName, {
89924
89938
  type: (_MIME_BY_EXTENSION$ex3 = MIME_BY_EXTENSION[extensionOf(fileName)]) !== null && _MIME_BY_EXTENSION$ex3 !== void 0 ? _MIME_BY_EXTENSION$ex3 : blob.type
89925
89939
  });
89926
- _context10.next = 99;
89940
+ _context10.next = 101;
89927
89941
  break;
89928
- case 96:
89929
- _context10.prev = 96;
89930
- _context10.t3 = _context10["catch"](87);
89942
+ case 98:
89943
+ _context10.prev = 98;
89944
+ _context10.t3 = _context10["catch"](89);
89931
89945
  return _context10.abrupt("return", {
89932
89946
  error: "The generated image could not be read: ".concat(_context10.t3 instanceof Error ? _context10.t3.message : String(_context10.t3))
89933
89947
  });
89934
- case 99:
89935
- _context10.prev = 99;
89936
- _context10.next = 102;
89948
+ case 101:
89949
+ _context10.prev = 101;
89950
+ _context10.next = 104;
89937
89951
  return uploadToMediaService(root, file, fileName);
89938
- case 102:
89952
+ case 104:
89939
89953
  uploaded = _context10.sent;
89940
- return _context10.abrupt("return", _objectSpread$y(_objectSpread$y({}, uploaded), {}, {
89954
+ return _context10.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({}, uploaded), {}, {
89941
89955
  mode: mode,
89942
89956
  model: (_payload$model = (_payload4 = payload) === null || _payload4 === void 0 ? void 0 : _payload4.model) !== null && _payload$model !== void 0 ? _payload$model : model,
89943
89957
  finalPrompt: (_payload5 = payload) === null || _payload5 === void 0 ? void 0 : _payload5.finalPrompt,
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,
89958
+ 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
89959
+ }, shortened ? {
89960
+ requestedFileName: requestedFileName
89961
+ } : {}), {}, {
89945
89962
  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)
89963
+ 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).concat(shortenedNameNote(shortened ? [fileName] : []))
89947
89964
  }));
89948
- case 106:
89949
- _context10.prev = 106;
89950
- _context10.t4 = _context10["catch"](99);
89965
+ case 108:
89966
+ _context10.prev = 108;
89967
+ _context10.t4 = _context10["catch"](101);
89951
89968
  return _context10.abrupt("return", {
89952
89969
  error: "The image was generated but the upload failed: ".concat(_context10.t4 instanceof Error ? _context10.t4.message : String(_context10.t4))
89953
89970
  });
89954
- case 109:
89971
+ case 111:
89955
89972
  case "end":
89956
89973
  return _context10.stop();
89957
89974
  }
89958
- }, _callee10, null, [[20, 35, 38, 41], [59, 65], [74, 78], [87, 96], [99, 106]]);
89975
+ }, _callee10, null, [[22, 37, 40, 43], [61, 67], [76, 80], [89, 98], [101, 108]]);
89959
89976
  }));
89960
89977
  return _generateImageAsset.apply(this, arguments);
89961
89978
  }
@@ -90205,7 +90222,31 @@ function _refusedAssetKeys() {
90205
90222
  }));
90206
90223
  return _refusedAssetKeys.apply(this, arguments);
90207
90224
  }
90225
+ /** Canonical write modes with their synonyms in one map, so the lookup is already typed. */
90226
+ var MODE_SYNONYMS = {
90227
+ append: 'append',
90228
+ replace: 'replace',
90229
+ remove: 'remove',
90230
+ add: 'append',
90231
+ overwrite: 'replace',
90232
+ set: 'replace',
90233
+ "delete": 'remove'
90234
+ };
90235
+
90236
+ /** An unrecognized non-empty mode is reported instead of silently APPENDING (the wrong write). */
90237
+ var parseAssetMode = function parseAssetMode(raw) {
90238
+ var value = String(raw !== null && raw !== void 0 ? raw : '').trim().toLowerCase();
90239
+ if (!value) return {};
90240
+ var mapped = MODE_SYNONYMS[value];
90241
+ return mapped ? {
90242
+ mode: mapped
90243
+ } : {
90244
+ invalid: String(raw)
90245
+ };
90246
+ };
90247
+
90208
90248
  /** Writes an asset cell (append/replace/remove) honoring the column's customParams shape — shared by the agent tools and the SVG generator UI. */
90249
+
90209
90250
  /** The grid's marker for a sent row the server answered about neither way. */
90210
90251
  var NO_ANSWER = 'No answer from the server';
90211
90252
  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.';
@@ -90222,19 +90263,55 @@ var clearRejected = function clearRejected(error) {
90222
90263
  return "".concat(error, " \u2014 this was the removal of the PREVIOUS assets; the replacement was not written");
90223
90264
  };
90224
90265
 
90225
- /** One verdict per written row — a skipped row was never sent; a row the server did not answer about arrives as rejected with its marker. */
90266
+ /** The grid's error for a row an all-or-nothing commit did not save because ANOTHER row failed (spreadsheet ApiHandler). */
90267
+ var ABORTED_BY_ANOTHER_ROW = 'Not saved: the request was rejected because another row failed.';
90268
+
90269
+ /**
90270
+ * One verdict per written row — a skipped row was never sent; a row the server did not answer about arrives as rejected
90271
+ * with its marker. idm saves a commit all or nothing: a row refused only because another row of the commit was, or one
90272
+ * that came back with the same error as other rows, must not read as refused for a reason of its own.
90273
+ */
90226
90274
  function assetWriteVerdict(outcome, nodeId) {
90227
90275
  var _outcome$skipped;
90276
+ var keyOf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function (rowId) {
90277
+ return rowId;
90278
+ };
90228
90279
  var failure = outcome === null || outcome === void 0 ? void 0 : outcome.failed.find(function (f) {
90229
90280
  return f.rowId === nodeId;
90230
90281
  });
90231
90282
  if (failure) {
90283
+ var _outcome$failed;
90284
+ var reason = failure.errors.join('; ');
90285
+ var others = ((_outcome$failed = outcome === null || outcome === void 0 ? void 0 : outcome.failed) !== null && _outcome$failed !== void 0 ? _outcome$failed : []).filter(function (f) {
90286
+ return f.rowId !== nodeId && !f.errors.every(function (error) {
90287
+ return error === NO_ANSWER;
90288
+ });
90289
+ });
90290
+ if (failure.errors.length && failure.errors.every(function (error) {
90291
+ return error === ABORTED_BY_ANOTHER_ROW;
90292
+ })) {
90293
+ var refused = others.filter(function (f) {
90294
+ return !f.errors.every(function (error) {
90295
+ return error === ABORTED_BY_ANOTHER_ROW;
90296
+ });
90297
+ }).map(function (f) {
90298
+ return keyOf(f.rowId);
90299
+ });
90300
+ return {
90301
+ state: 'rejected',
90302
+ error: "not saved: another row in the same commit was refused (".concat(refused.join(', ') || 'the server did not say which', ") \u2014 nothing is wrong with this row as far as the server said; write it again")
90303
+ };
90304
+ }
90305
+ var sharing = others.filter(function (f) {
90306
+ return f.errors.join('; ') === reason;
90307
+ }).length;
90308
+ var sharedNote = sharing ? " \u2014 ".concat(sharing + 1, " rows of this commit came back with this same error, and the server saves a commit all or nothing, so it may belong to only one of them: write them one at a time (setAssetCell without cells) to find it") : '';
90232
90309
  // The server quotes a raw .NET pattern; an asset entry's text field is its media NAME (IDM caps it at 40 characters).
90233
- var maxLength = patternLengthLimit(failure.errors.join(' '));
90234
- var lengthNote = maxLength ? " \u2014 the media name holds at most ".concat(maxLength, " characters: shorten it") : '';
90310
+ var maxLength = patternLengthLimit(reason);
90311
+ var lengthNote = maxLength ? " \u2014 IDM takes the media item's own name (its file name), which holds at most ".concat(maxLength, " characters: upload the file again under a shorter name (a shorter setAssetCell 'name' does not help)") : '';
90235
90312
  return _objectSpread$y({
90236
90313
  state: 'rejected',
90237
- error: "the server rejected the write: ".concat(failure.errors.join('; ') || 'no reason given').concat(lengthNote)
90314
+ error: "the server rejected the write: ".concat(reason || 'no reason given').concat(lengthNote).concat(sharedNote)
90238
90315
  }, failure.errors.length && failure.errors.every(function (error) {
90239
90316
  return error === NO_ANSWER;
90240
90317
  }) ? {
@@ -90260,6 +90337,10 @@ function assetWriteVerdict(outcome, nodeId) {
90260
90337
  function settleRefusal(_x28, _x29, _x30, _x31, _x32) {
90261
90338
  return _settleRefusal.apply(this, arguments);
90262
90339
  }
90340
+ /**
90341
+ * The IDM options tables, by read endpoint template (the organization's one shares its gridId with the features grids):
90342
+ * one option row serves every feature in its featureNos. Only a catalog's option images can be scoped to a serie.
90343
+ */
90263
90344
  function _settleRefusal() {
90264
90345
  _settleRefusal = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee13(handle, nodeId, column, verdict, wasPending) {
90265
90346
  var _handle$discardStaged;
@@ -90296,13 +90377,46 @@ function _settleRefusal() {
90296
90377
  }));
90297
90378
  return _settleRefusal.apply(this, arguments);
90298
90379
  }
90380
+ var SHARED_OPTION_TABLES = [{
90381
+ readUrlSuffix: '/catalogs/${catalogId}/options',
90382
+ serieScope: true
90383
+ }, {
90384
+ readUrlSuffix: '/${organizationId}/options',
90385
+ serieScope: false
90386
+ }];
90387
+ /**
90388
+ * The features a row of an IDM options table belongs to when they are more than one — its images show in every one of
90389
+ * them. Nothing on any other table, and nothing while the row's featureNos are not loaded.
90390
+ */
90391
+ function sharedOptionRow(entry, node) {
90392
+ var table = SHARED_OPTION_TABLES.find(function (candidate) {
90393
+ var _entry$readUrl;
90394
+ return (_entry$readUrl = entry.readUrl) === null || _entry$readUrl === void 0 ? void 0 : _entry$readUrl.endsWith(candidate.readUrlSuffix);
90395
+ });
90396
+ if (!table) return undefined;
90397
+ var featureNos = nestedValue(node === null || node === void 0 ? void 0 : node.data, 'featureNos');
90398
+ if (!Array.isArray(featureNos)) return undefined;
90399
+ var features = _toConsumableArray(new Set(featureNos.map(String)));
90400
+ return features.length > 1 ? {
90401
+ features: features,
90402
+ serieScope: table.serieScope
90403
+ } : undefined;
90404
+ }
90405
+
90406
+ /** What a write on a shared option row reports: the features the image shows in, and how to tell them apart. */
90407
+ var sharedRowFacts = function sharedRowFacts(shared) {
90408
+ return shared ? {
90409
+ sharedWith: shared.features,
90410
+ note: "Option row shared by features ".concat(shared.features.join(', '), ": its images show in ALL of them. A different picture per feature needs its own option row") + (shared.serieScope ? "; a picture per serie needs the image entry's serie scope (serieNo, set in the cell's Edit Metadata dialog — setAssetCell does not write it)." : '.')
90411
+ } : {};
90412
+ };
90299
90413
  function writeAssetCell(_x33, _x34) {
90300
90414
  return _writeAssetCell.apply(this, arguments);
90301
90415
  }
90302
90416
  function _writeAssetCell() {
90303
90417
  _writeAssetCell = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee15(root, args) {
90304
90418
  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;
90419
+ var entry, handle, api, divaDef, params, idField, allDefs, findLoadedNode, refusal, node, autoLocated, filterBefore, filterChanged, restoreFilter, _node2, located, carriers, sharedWith, assetObject, newValue, current, list, approved, wasPending, assetsCleared, _handle$commitStagedC, _handle$hasPendingCha3, _handle$hasPendingCha4, cleared, clearedNote, outcome, verdict, persisted, gridRefreshed;
90306
90420
  return _regeneratorRuntime.wrap(function _callee15$(_context15) {
90307
90421
  while (1) switch (_context15.prev = _context15.next) {
90308
90422
  case 0:
@@ -90383,7 +90497,7 @@ function _writeAssetCell() {
90383
90497
  filterBefore = api.getFilterModel();
90384
90498
  filterChanged = false;
90385
90499
  restoreFilter = /*#__PURE__*/function () {
90386
- var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
90500
+ var _ref12 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
90387
90501
  return _regeneratorRuntime.wrap(function _callee14$(_context14) {
90388
90502
  while (1) switch (_context14.prev = _context14.next) {
90389
90503
  case 0:
@@ -90404,7 +90518,7 @@ function _writeAssetCell() {
90404
90518
  }, _callee14);
90405
90519
  }));
90406
90520
  return function restoreFilter() {
90407
- return _ref3.apply(this, arguments);
90521
+ return _ref12.apply(this, arguments);
90408
90522
  };
90409
90523
  }();
90410
90524
  if ((_node = node) !== null && _node !== void 0 && _node.id) {
@@ -90451,6 +90565,7 @@ function _writeAssetCell() {
90451
90565
  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).")
90452
90566
  });
90453
90567
  case 51:
90568
+ sharedWith = sharedOptionRow(entry, node);
90454
90569
  assetObject = _defineProperty({}, idField, args.asset.mediaItemId);
90455
90570
  if (args.asset.url && params.urlField) assetObject[params.urlField] = args.asset.url;
90456
90571
  if (args.asset.name && params.fileNameField) assetObject[params.fileNameField] = args.asset.name;
@@ -90471,137 +90586,137 @@ function _writeAssetCell() {
90471
90586
  newValue = args.mode === 'remove' ? undefined : params.isObject ? assetObject : args.asset.mediaItemId;
90472
90587
  }
90473
90588
  if (!args.approve) {
90474
- _context15.next = 65;
90589
+ _context15.next = 66;
90475
90590
  break;
90476
90591
  }
90477
- _context15.next = 60;
90592
+ _context15.next = 61;
90478
90593
  return args.approve(entry);
90479
- case 60:
90594
+ case 61:
90480
90595
  approved = _context15.sent;
90481
90596
  if (approved) {
90482
- _context15.next = 65;
90597
+ _context15.next = 66;
90483
90598
  break;
90484
90599
  }
90485
- _context15.next = 64;
90600
+ _context15.next = 65;
90486
90601
  return restoreFilter();
90487
- case 64:
90602
+ case 65:
90488
90603
  return _context15.abrupt("return", {
90489
90604
  applied: false,
90490
90605
  note: 'The user DECLINED the change — nothing was written. Do not retry; ask what to do instead.'
90491
90606
  });
90492
- case 65:
90607
+ case 66:
90493
90608
  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
90494
90609
  // their own, the new one arrives in the next — the endpoint keys its asset handling on those shapes.
90495
90610
  assetsCleared = false;
90496
90611
  if (!(params.multiple && args.mode === 'replace' && Array.isArray(current) && current.length)) {
90497
- _context15.next = 98;
90612
+ _context15.next = 99;
90498
90613
  break;
90499
90614
  }
90500
- _context15.next = 70;
90615
+ _context15.next = 71;
90501
90616
  return handle.setNodeDataValue(node.id, _defineProperty({}, args.column, []), {
90502
90617
  suppressAutoCommit: true
90503
90618
  });
90504
- case 70:
90619
+ case 71:
90505
90620
  if (_context15.sent) {
90506
- _context15.next = 74;
90621
+ _context15.next = 75;
90507
90622
  break;
90508
90623
  }
90509
- _context15.next = 73;
90624
+ _context15.next = 74;
90510
90625
  return restoreFilter();
90511
- case 73:
90626
+ case 74:
90512
90627
  return _context15.abrupt("return", {
90513
90628
  error: 'The row rejected the update.'
90514
90629
  });
90515
- case 74:
90630
+ case 75:
90516
90631
  _context15.t1 = settleRefusal;
90517
90632
  _context15.t2 = handle;
90518
90633
  _context15.t3 = node.id;
90519
90634
  _context15.t4 = args.column;
90520
90635
  _context15.t5 = assetWriteVerdict;
90521
- _context15.next = 81;
90636
+ _context15.next = 82;
90522
90637
  return (_handle$commitStagedC = handle.commitStagedChanges) === null || _handle$commitStagedC === void 0 ? void 0 : _handle$commitStagedC.call(handle);
90523
- case 81:
90638
+ case 82:
90524
90639
  _context15.t6 = _context15.sent;
90525
90640
  _context15.t7 = node.id;
90526
90641
  _context15.t8 = (0, _context15.t5)(_context15.t6, _context15.t7);
90527
90642
  _context15.t9 = wasPending;
90528
- _context15.next = 87;
90643
+ _context15.next = 88;
90529
90644
  return (0, _context15.t1)(_context15.t2, _context15.t3, _context15.t4, _context15.t8, _context15.t9);
90530
- case 87:
90645
+ case 88:
90531
90646
  cleared = _context15.sent;
90532
90647
  if (!(cleared.state !== 'persisted')) {
90533
- _context15.next = 92;
90648
+ _context15.next = 93;
90534
90649
  break;
90535
90650
  }
90536
- _context15.next = 91;
90651
+ _context15.next = 92;
90537
90652
  return restoreFilter();
90538
- case 91:
90653
+ case 92:
90539
90654
  return _context15.abrupt("return", {
90540
90655
  error: "".concat(clearRejected(cleared.error)[0].toUpperCase()).concat(clearRejected(cleared.error).slice(1), ".")
90541
90656
  });
90542
- case 92:
90657
+ case 93:
90543
90658
  if (!(cleared.persisted === false)) {
90544
- _context15.next = 96;
90659
+ _context15.next = 97;
90545
90660
  break;
90546
90661
  }
90547
- _context15.next = 95;
90662
+ _context15.next = 96;
90548
90663
  return restoreFilter();
90549
- case 95:
90664
+ case 96:
90550
90665
  return _context15.abrupt("return", {
90551
90666
  error: "".concat(UNCONFIRMED_CLEAR[0].toUpperCase()).concat(UNCONFIRMED_CLEAR.slice(1), ".")
90552
90667
  });
90553
- case 96:
90668
+ case 97:
90554
90669
  assetsCleared = cleared.persisted === true;
90555
90670
  // The confirmed clear saved the row's earlier edits too: the replacement starts on what is pending now.
90556
90671
  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:
90672
+ case 99:
90558
90673
  clearedNote = assetsCleared ? CLEARED_ASSETS_NOTE : '';
90559
- _context15.next = 101;
90674
+ _context15.next = 102;
90560
90675
  return handle.setNodeDataValue(node.id, _defineProperty({}, args.column, newValue), {
90561
90676
  suppressAutoCommit: true
90562
90677
  });
90563
- case 101:
90678
+ case 102:
90564
90679
  if (_context15.sent) {
90565
- _context15.next = 105;
90680
+ _context15.next = 106;
90566
90681
  break;
90567
90682
  }
90568
- _context15.next = 104;
90683
+ _context15.next = 105;
90569
90684
  return restoreFilter();
90570
- case 104:
90685
+ case 105:
90571
90686
  return _context15.abrupt("return", {
90572
90687
  error: "The row rejected the update.".concat(clearedNote)
90573
90688
  });
90574
- case 105:
90575
- _context15.next = 107;
90689
+ case 106:
90690
+ _context15.next = 108;
90576
90691
  return (_handle$commitStagedC2 = handle.commitStagedChanges) === null || _handle$commitStagedC2 === void 0 ? void 0 : _handle$commitStagedC2.call(handle);
90577
- case 107:
90692
+ case 108:
90578
90693
  outcome = _context15.sent;
90579
- _context15.next = 110;
90694
+ _context15.next = 111;
90580
90695
  return settleRefusal(handle, node.id, args.column, assetWriteVerdict(outcome, node.id), wasPending);
90581
- case 110:
90696
+ case 111:
90582
90697
  verdict = _context15.sent;
90583
90698
  if (!(verdict.state === 'rejected' || verdict.state === 'skipped')) {
90584
- _context15.next = 115;
90699
+ _context15.next = 116;
90585
90700
  break;
90586
90701
  }
90587
- _context15.next = 114;
90702
+ _context15.next = 115;
90588
90703
  return restoreFilter();
90589
- case 114:
90704
+ case 115:
90590
90705
  return _context15.abrupt("return", {
90591
90706
  error: "".concat(verdict.error[0].toUpperCase()).concat(verdict.error.slice(1), ".").concat(clearedNote)
90592
90707
  });
90593
- case 115:
90708
+ case 116:
90594
90709
  persisted = verdict.persisted; // Refetch only once the server confirmed and nothing else is staged — a refresh discards every pending change.
90595
90710
  gridRefreshed = persisted === true && !((_handle$hasPendingCha5 = handle.hasPendingChanges) !== null && _handle$hasPendingCha5 !== void 0 && _handle$hasPendingCha5.call(handle));
90596
90711
  if (gridRefreshed) (_handle$refresh = handle.refresh) === null || _handle$refresh === void 0 || _handle$refresh.call(handle);
90597
90712
  if (!(persisted !== false)) {
90598
- _context15.next = 121;
90713
+ _context15.next = 122;
90599
90714
  break;
90600
90715
  }
90601
- _context15.next = 121;
90716
+ _context15.next = 122;
90602
90717
  return restoreFilter();
90603
- case 121:
90604
- return _context15.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
90718
+ case 122:
90719
+ return _context15.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y(_objectSpread$y({
90605
90720
  applied: true
90606
90721
  }, persisted === undefined ? {} : {
90607
90722
  persisted: persisted
@@ -90609,8 +90724,8 @@ function _writeAssetCell() {
90609
90724
  gridRefreshed: true
90610
90725
  } : {}), autoLocated ? {
90611
90726
  autoLocated: true
90612
- } : {}));
90613
- case 122:
90727
+ } : {}), sharedRowFacts(sharedWith)));
90728
+ case 123:
90614
90729
  case "end":
90615
90730
  return _context15.stop();
90616
90731
  }
@@ -90619,6 +90734,41 @@ function _writeAssetCell() {
90619
90734
  return _writeAssetCell.apply(this, arguments);
90620
90735
  }
90621
90736
  var ROW_NOT_FOUND = 'no row matched this keyValue — the value must match EXACTLY (check for typos/whitespace; the row may not exist)';
90737
+ /** The on-screen table, its asset column and its key column of an asset write — or why the write cannot happen. */
90738
+ function resolveAssetColumn(root, grid, keyColumn, column) {
90739
+ var entry = findGrid(root, grid);
90740
+ if (!entry) return {
90741
+ error: "No table '".concat(grid !== null && grid !== void 0 ? grid : '', "' on the current view \u2014 listGrids shows what is on screen.")
90742
+ };
90743
+ var handle = entry.getHandle();
90744
+ var api = handle === null || handle === void 0 ? void 0 : handle.getGridApi();
90745
+ if (!handle || !api) return {
90746
+ error: "Table '".concat(entry.label, "' is not ready.")
90747
+ };
90748
+ var allDefs = handle.getDivaColumnDefs();
90749
+ var divaDef = allDefs.find(function (def) {
90750
+ return def.field === column;
90751
+ });
90752
+ if (!divaDef) return {
90753
+ error: "Column '".concat(column, "' not found on '").concat(entry.label, "'.")
90754
+ };
90755
+ if (divaDef.cellDataType !== 'asset') return {
90756
+ error: "Column '".concat(column, "' is not an asset column \u2014 use stageTableEdits for regular cells.")
90757
+ };
90758
+ if (!allDefs.some(function (def) {
90759
+ return def.field === keyColumn;
90760
+ })) {
90761
+ return {
90762
+ error: "keyColumn '".concat(keyColumn, "' is not a column of '").concat(entry.label, "'.")
90763
+ };
90764
+ }
90765
+ return {
90766
+ entry: entry,
90767
+ handle: handle,
90768
+ api: api,
90769
+ divaDef: divaDef
90770
+ };
90771
+ }
90622
90772
 
90623
90773
  /**
90624
90774
  * Stages the already-loaded cells together and commits them with ONE server round-trip. Rows outside
@@ -90627,66 +90777,28 @@ var ROW_NOT_FOUND = 'no row matched this keyValue — the value must match EXACT
90627
90777
  * already-staged-but-uncommitted row, so a row located this way is committed on its own, immediately,
90628
90778
  * before the next lookup runs.
90629
90779
  */
90630
- function writeAssetCellsBatch(_x35, _x36, _x37, _x38, _x39, _x40, _x41, _x42) {
90780
+ function writeAssetCellsBatch(_x35, _x36, _x37, _x38, _x39, _x40, _x41, _x42, _x43) {
90631
90781
  return _writeAssetCellsBatch.apply(this, arguments);
90632
90782
  }
90633
- /** Per-article result of a generateArticleSvg batch run — ids and findings only, never the markup. */
90783
+ /** The asset cell a generated image goes into — addressed like a setAssetCell entry. */
90634
90784
  function _writeAssetCellsBatch() {
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;
90785
+ _writeAssetCellsBatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee17(root, grid, keyColumn, column, defaultMode, cells, approve, signal, /** The time budget of the writes; default: TIME_BUDGET_MS from the moment the user approved. */
90786
+ budget) {
90787
+ var _divaDef$customParams2, _params$mediaItemIdFi2, _budget$startedAt, _budget$budgetMs, _handle$hasPendingCha12, _handle$refresh2;
90788
+ var resolved, entry, handle, api, divaDef, params, idField, loadedNodes, newValueFor, needsClearFirst, stageAndCommit, refusals, preflight, writable, stageable, needsLookup, written, sharedWith, failed, remaining, startedAt, budgetMs, 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
90789
  return _regeneratorRuntime.wrap(function _callee17$(_context17) {
90639
90790
  while (1) switch (_context17.prev = _context17.next) {
90640
90791
  case 0:
90641
- entry = findGrid(root, grid);
90642
- if (entry) {
90792
+ resolved = resolveAssetColumn(root, grid, keyColumn, column);
90793
+ if (!('error' in resolved)) {
90643
90794
  _context17.next = 3;
90644
90795
  break;
90645
90796
  }
90646
90797
  return _context17.abrupt("return", {
90647
- error: "No table '".concat(grid !== null && grid !== void 0 ? grid : '', "' on the current view \u2014 listGrids shows what is on screen.")
90798
+ error: resolved.error
90648
90799
  });
90649
90800
  case 3:
90650
- handle = entry.getHandle();
90651
- api = handle === null || handle === void 0 ? void 0 : handle.getGridApi();
90652
- if (!(!handle || !api)) {
90653
- _context17.next = 7;
90654
- break;
90655
- }
90656
- return _context17.abrupt("return", {
90657
- error: "Table '".concat(entry.label, "' is not ready.")
90658
- });
90659
- case 7:
90660
- allDefs = handle.getDivaColumnDefs();
90661
- divaDef = allDefs.find(function (def) {
90662
- return def.field === column;
90663
- });
90664
- if (divaDef) {
90665
- _context17.next = 11;
90666
- break;
90667
- }
90668
- return _context17.abrupt("return", {
90669
- error: "Column '".concat(column, "' not found on '").concat(entry.label, "'.")
90670
- });
90671
- case 11:
90672
- if (!(divaDef.cellDataType !== 'asset')) {
90673
- _context17.next = 13;
90674
- break;
90675
- }
90676
- return _context17.abrupt("return", {
90677
- error: "Column '".concat(column, "' is not an asset column \u2014 use stageTableEdits for regular cells.")
90678
- });
90679
- case 13:
90680
- if (allDefs.some(function (def) {
90681
- return def.field === keyColumn;
90682
- })) {
90683
- _context17.next = 15;
90684
- break;
90685
- }
90686
- return _context17.abrupt("return", {
90687
- error: "keyColumn '".concat(keyColumn, "' is not a column of '").concat(entry.label, "'.")
90688
- });
90689
- case 15:
90801
+ entry = resolved.entry, handle = resolved.handle, api = resolved.api, divaDef = resolved.divaDef;
90690
90802
  params = (_divaDef$customParams2 = divaDef.customParams) !== null && _divaDef$customParams2 !== void 0 ? _divaDef$customParams2 : {};
90691
90803
  idField = (_params$mediaItemIdFi2 = params.mediaItemIdField) !== null && _params$mediaItemIdFi2 !== void 0 ? _params$mediaItemIdFi2 : 'mediaitemId';
90692
90804
  loadedNodes = function loadedNodes() {
@@ -90724,9 +90836,9 @@ function _writeAssetCellsBatch() {
90724
90836
  };
90725
90837
  /** Stages one value per cell and commits them together; every staged cell's verdict goes to `onVerdict`. */
90726
90838
  stageAndCommit = /*#__PURE__*/function () {
90727
- var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee16(targets, valueOf, onVerdict, cleared) {
90839
+ var _ref13 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee16(targets, valueOf, onVerdict, cleared) {
90728
90840
  var _handle$commitStagedC3;
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;
90841
+ var noteFor, nodesByKey, staged, pendingBefore, _iterator7, _step7, _handle$hasPendingCha6, _handle$hasPendingCha7, _cell, node, outcome, keyByNode, keyOf, settled, _i2, _staged, _settled$get, _staged$_i, cell, nodeId, _pendingBefore$get;
90730
90842
  return _regeneratorRuntime.wrap(function _callee16$(_context16) {
90731
90843
  while (1) switch (_context16.prev = _context16.next) {
90732
90844
  case 0:
@@ -90741,7 +90853,7 @@ function _writeAssetCellsBatch() {
90741
90853
  _iterator7.s();
90742
90854
  case 7:
90743
90855
  if ((_step7 = _iterator7.n()).done) {
90744
- _context16.next = 22;
90856
+ _context16.next = 23;
90745
90857
  break;
90746
90858
  }
90747
90859
  _cell = _step7.value;
@@ -90754,91 +90866,101 @@ function _writeAssetCellsBatch() {
90754
90866
  keyValue: _cell.keyValue,
90755
90867
  error: "".concat(ROW_NOT_FOUND).concat(noteFor(_cell))
90756
90868
  });
90757
- return _context16.abrupt("continue", 20);
90869
+ return _context16.abrupt("continue", 21);
90758
90870
  case 13:
90871
+ sharedWith.set(_cell.keyValue, sharedOptionRow(entry, node));
90759
90872
  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;
90873
+ _context16.next = 17;
90761
90874
  return handle.setNodeDataValue(node.id, _defineProperty({}, column, valueOf(node, _cell)), {
90762
90875
  suppressAutoCommit: true
90763
90876
  });
90764
- case 16:
90877
+ case 17:
90765
90878
  if (_context16.sent) {
90766
- _context16.next = 19;
90879
+ _context16.next = 20;
90767
90880
  break;
90768
90881
  }
90769
90882
  failed.push({
90770
90883
  keyValue: _cell.keyValue,
90771
90884
  error: "the row rejected the update".concat(noteFor(_cell))
90772
90885
  });
90773
- return _context16.abrupt("continue", 20);
90774
- case 19:
90886
+ return _context16.abrupt("continue", 21);
90887
+ case 20:
90775
90888
  staged.push({
90776
90889
  cell: _cell,
90777
90890
  nodeId: node.id
90778
90891
  });
90779
- case 20:
90892
+ case 21:
90780
90893
  _context16.next = 7;
90781
90894
  break;
90782
- case 22:
90783
- _context16.next = 27;
90895
+ case 23:
90896
+ _context16.next = 28;
90784
90897
  break;
90785
- case 24:
90786
- _context16.prev = 24;
90898
+ case 25:
90899
+ _context16.prev = 25;
90787
90900
  _context16.t0 = _context16["catch"](5);
90788
90901
  _iterator7.e(_context16.t0);
90789
- case 27:
90790
- _context16.prev = 27;
90902
+ case 28:
90903
+ _context16.prev = 28;
90791
90904
  _iterator7.f();
90792
- return _context16.finish(27);
90793
- case 30:
90905
+ return _context16.finish(28);
90906
+ case 31:
90794
90907
  if (staged.length) {
90795
- _context16.next = 32;
90908
+ _context16.next = 33;
90796
90909
  break;
90797
90910
  }
90798
90911
  return _context16.abrupt("return");
90799
- case 32:
90800
- _context16.next = 34;
90912
+ case 33:
90913
+ _context16.next = 35;
90801
90914
  return (_handle$commitStagedC3 = handle.commitStagedChanges) === null || _handle$commitStagedC3 === void 0 ? void 0 : _handle$commitStagedC3.call(handle);
90802
- case 34:
90915
+ case 35:
90803
90916
  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.
90917
+ // Other failed rows are named by their key; a row the tool did not stage holds edits of the user.
90918
+ keyByNode = new Map(staged.map(function (_ref14) {
90919
+ var cell = _ref14.cell,
90920
+ nodeId = _ref14.nodeId;
90921
+ return [nodeId, "".concat(keyColumn, " = '").concat(cell.keyValue, "'")];
90922
+ }));
90923
+ keyOf = function keyOf(rowId) {
90924
+ var _keyByNode$get;
90925
+ return (_keyByNode$get = keyByNode.get(rowId)) !== null && _keyByNode$get !== void 0 ? _keyByNode$get : "row ".concat(rowId, " (unsaved edits of the user)");
90926
+ }; // One settlement per row: the commit's verdict is per row, and a row taken back once has nothing left to take back.
90805
90927
  settled = new Map();
90806
90928
  _i2 = 0, _staged = staged;
90807
- case 37:
90929
+ case 40:
90808
90930
  if (!(_i2 < _staged.length)) {
90809
- _context16.next = 50;
90931
+ _context16.next = 53;
90810
90932
  break;
90811
90933
  }
90812
90934
  _staged$_i = _staged[_i2], cell = _staged$_i.cell, nodeId = _staged$_i.nodeId;
90813
90935
  if (settled.has(nodeId)) {
90814
- _context16.next = 46;
90936
+ _context16.next = 49;
90815
90937
  break;
90816
90938
  }
90817
90939
  _context16.t1 = settled;
90818
90940
  _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:
90941
+ _context16.next = 47;
90942
+ return settleRefusal(handle, nodeId, column, assetWriteVerdict(outcome, nodeId, keyOf), (_pendingBefore$get = pendingBefore.get(nodeId)) !== null && _pendingBefore$get !== void 0 ? _pendingBefore$get : false);
90943
+ case 47:
90822
90944
  _context16.t3 = _context16.sent;
90823
90945
  _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:
90946
+ case 49:
90947
+ onVerdict(cell, (_settled$get = settled.get(nodeId)) !== null && _settled$get !== void 0 ? _settled$get : assetWriteVerdict(outcome, nodeId, keyOf));
90948
+ case 50:
90827
90949
  _i2++;
90828
- _context16.next = 37;
90950
+ _context16.next = 40;
90829
90951
  break;
90830
- case 50:
90952
+ case 53:
90831
90953
  case "end":
90832
90954
  return _context16.stop();
90833
90955
  }
90834
- }, _callee16, null, [[5, 24, 27, 30]]);
90956
+ }, _callee16, null, [[5, 25, 28, 31]]);
90835
90957
  }));
90836
- return function stageAndCommit(_x53, _x54, _x55, _x56) {
90837
- return _ref4.apply(this, arguments);
90958
+ return function stageAndCommit(_x60, _x61, _x62, _x63) {
90959
+ return _ref13.apply(this, arguments);
90838
90960
  };
90839
90961
  }();
90840
90962
  if (cells.length) {
90841
- _context17.next = 23;
90963
+ _context17.next = 12;
90842
90964
  break;
90843
90965
  }
90844
90966
  return _context17.abrupt("return", {
@@ -90846,12 +90968,12 @@ function _writeAssetCellsBatch() {
90846
90968
  failed: [],
90847
90969
  note: "'cells' was empty."
90848
90970
  });
90849
- case 23:
90850
- _context17.next = 25;
90971
+ case 12:
90972
+ _context17.next = 14;
90851
90973
  return refusedAssetKeys(api, keyColumn, _toConsumableArray(new Set(cells.map(function (cell) {
90852
90974
  return cell.keyValue;
90853
90975
  }))));
90854
- case 25:
90976
+ case 14:
90855
90977
  refusals = _context17.sent;
90856
90978
  preflight = loadedNodes();
90857
90979
  writable = cells.filter(function (cell) {
@@ -90868,24 +90990,26 @@ function _writeAssetCellsBatch() {
90868
90990
  // (even the sequential lookups below) must never happen before the user has consented to all of it.
90869
90991
  _context17.t0 = writable.length && approve;
90870
90992
  if (!_context17.t0) {
90871
- _context17.next = 35;
90993
+ _context17.next = 24;
90872
90994
  break;
90873
90995
  }
90874
- _context17.next = 34;
90996
+ _context17.next = 23;
90875
90997
  return approve(entry, stageable.length + needsLookup.length);
90876
- case 34:
90998
+ case 23:
90877
90999
  _context17.t0 = !_context17.sent;
90878
- case 35:
91000
+ case 24:
90879
91001
  if (!_context17.t0) {
90880
- _context17.next = 37;
91002
+ _context17.next = 26;
90881
91003
  break;
90882
91004
  }
90883
91005
  return _context17.abrupt("return", {
90884
91006
  applied: false,
90885
91007
  note: 'The user DECLINED the change — nothing was written. Do not retry; ask what to do instead.'
90886
91008
  });
90887
- case 37:
91009
+ case 26:
90888
91010
  written = [];
91011
+ /** Per key, the features of a shared option row — read from the row the write was staged on. */
91012
+ sharedWith = new Map();
90889
91013
  failed = cells.filter(function (cell) {
90890
91014
  return refusals.has(cell.keyValue);
90891
91015
  }).map(function (cell) {
@@ -90896,7 +91020,8 @@ function _writeAssetCellsBatch() {
90896
91020
  });
90897
91021
  /** Entries never started because the turn was aborted or the time budget ran out — the caller re-calls with exactly these. */
90898
91022
  remaining = [];
90899
- startedAt = Date.now();
91023
+ startedAt = (_budget$startedAt = budget === null || budget === void 0 ? void 0 : budget.startedAt) !== null && _budget$startedAt !== void 0 ? _budget$startedAt : Date.now();
91024
+ budgetMs = (_budget$budgetMs = budget === null || budget === void 0 ? void 0 : budget.budgetMs) !== null && _budget$budgetMs !== void 0 ? _budget$budgetMs : TIME_BUDGET_MS;
90900
91025
  recordVerdict = function recordVerdict(keyValue, verdict) {
90901
91026
  var assetsCleared = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
90902
91027
  if (verdict.state === 'rejected' || verdict.state === 'skipped') {
@@ -90906,208 +91031,209 @@ function _writeAssetCellsBatch() {
90906
91031
  });
90907
91032
  return;
90908
91033
  }
90909
- written.push(_objectSpread$y({
91034
+ written.push(_objectSpread$y(_objectSpread$y({
90910
91035
  keyValue: keyValue,
90911
91036
  applied: true
90912
91037
  }, verdict.persisted === undefined ? {} : {
90913
91038
  persisted: verdict.persisted
90914
- }));
91039
+ }), sharedRowFacts(sharedWith.get(keyValue))));
90915
91040
  }; // Rows not in the loaded window: resolve, stage and commit EACH ONE on its own before the next lookup's
90916
91041
  // filter change can put anything else at risk (see writeAssetCellsBatch's own doc comment above).
90917
91042
  if (!needsLookup.length) {
90918
- _context17.next = 133;
91043
+ _context17.next = 125;
90919
91044
  break;
90920
91045
  }
90921
91046
  filterBefore = api.getFilterModel();
90922
91047
  filterChanged = false;
90923
91048
  _iterator8 = _createForOfIteratorHelper$g(needsLookup);
90924
- _context17.prev = 46;
91049
+ _context17.prev = 37;
90925
91050
  _iterator8.s();
90926
- case 48:
91051
+ case 39:
90927
91052
  if ((_step8 = _iterator8.n()).done) {
90928
- _context17.next = 121;
91053
+ _context17.next = 113;
90929
91054
  break;
90930
91055
  }
90931
91056
  cell = _step8.value;
90932
- if (!stopBatch(startedAt, TIME_BUDGET_MS, signal)) {
90933
- _context17.next = 53;
91057
+ if (!stopBatch(startedAt, budgetMs, signal)) {
91058
+ _context17.next = 44;
90934
91059
  break;
90935
91060
  }
90936
91061
  remaining.push(cell.keyValue);
90937
- return _context17.abrupt("continue", 119);
90938
- case 53:
91062
+ return _context17.abrupt("continue", 111);
91063
+ case 44:
90939
91064
  node = void 0;
90940
- _context17.prev = 54;
90941
- _context17.next = 57;
91065
+ _context17.prev = 45;
91066
+ _context17.next = 48;
90942
91067
  return locateRowCore(api, keyColumn, cell.keyValue, false);
90943
- case 57:
91068
+ case 48:
90944
91069
  located = _context17.sent;
90945
91070
  filterChanged = filterChanged || located.filterApplied;
90946
- _context17.next = 65;
91071
+ _context17.next = 56;
90947
91072
  break;
90948
- case 61:
90949
- _context17.prev = 61;
90950
- _context17.t1 = _context17["catch"](54);
91073
+ case 52:
91074
+ _context17.prev = 52;
91075
+ _context17.t1 = _context17["catch"](45);
90951
91076
  failed.push({
90952
91077
  keyValue: cell.keyValue,
90953
91078
  error: _context17.t1 instanceof Error ? _context17.t1.message : String(_context17.t1)
90954
91079
  });
90955
- return _context17.abrupt("continue", 119);
90956
- case 65:
91080
+ return _context17.abrupt("continue", 111);
91081
+ case 56:
90957
91082
  carriers = loadedCarriers(api, keyColumn, cell.keyValue);
90958
91083
  if (!(carriers.length > 1)) {
90959
- _context17.next = 69;
91084
+ _context17.next = 60;
90960
91085
  break;
90961
91086
  }
90962
91087
  failed.push({
90963
91088
  keyValue: cell.keyValue,
90964
91089
  error: notUniqueRefusal(keyColumn, cell.keyValue, carriers)
90965
91090
  });
90966
- return _context17.abrupt("continue", 119);
90967
- case 69:
91091
+ return _context17.abrupt("continue", 111);
91092
+ case 60:
90968
91093
  // locateRowCore only guarantees the row is LOADED — re-read it by an exact key match, same as the single-cell path.
90969
91094
  node = loadedNodes().get(cell.keyValue);
90970
91095
  if ((_node4 = node) !== null && _node4 !== void 0 && _node4.id) {
90971
- _context17.next = 73;
91096
+ _context17.next = 64;
90972
91097
  break;
90973
91098
  }
90974
91099
  failed.push({
90975
91100
  keyValue: cell.keyValue,
90976
91101
  error: ROW_NOT_FOUND
90977
91102
  });
90978
- return _context17.abrupt("continue", 119);
90979
- case 73:
91103
+ return _context17.abrupt("continue", 111);
91104
+ case 64:
91105
+ sharedWith.set(cell.keyValue, sharedOptionRow(entry, node));
90980
91106
  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;
90981
91107
  assetsCleared = false;
90982
91108
  if (!needsClearFirst(node, cell)) {
90983
- _context17.next = 103;
91109
+ _context17.next = 95;
90984
91110
  break;
90985
91111
  }
90986
- _context17.next = 78;
91112
+ _context17.next = 70;
90987
91113
  return handle.setNodeDataValue(node.id, _defineProperty({}, column, []), {
90988
91114
  suppressAutoCommit: true
90989
91115
  });
90990
- case 78:
91116
+ case 70:
90991
91117
  if (_context17.sent) {
90992
- _context17.next = 81;
91118
+ _context17.next = 73;
90993
91119
  break;
90994
91120
  }
90995
91121
  failed.push({
90996
91122
  keyValue: cell.keyValue,
90997
91123
  error: 'the row rejected the update'
90998
91124
  });
90999
- return _context17.abrupt("continue", 119);
91000
- case 81:
91125
+ return _context17.abrupt("continue", 111);
91126
+ case 73:
91001
91127
  _context17.t2 = settleRefusal;
91002
91128
  _context17.t3 = handle;
91003
91129
  _context17.t4 = node.id;
91004
91130
  _context17.t5 = column;
91005
91131
  _context17.t6 = assetWriteVerdict;
91006
- _context17.next = 88;
91132
+ _context17.next = 80;
91007
91133
  return (_handle$commitStagedC4 = handle.commitStagedChanges) === null || _handle$commitStagedC4 === void 0 ? void 0 : _handle$commitStagedC4.call(handle);
91008
- case 88:
91134
+ case 80:
91009
91135
  _context17.t7 = _context17.sent;
91010
91136
  _context17.t8 = node.id;
91011
91137
  _context17.t9 = (0, _context17.t6)(_context17.t7, _context17.t8);
91012
91138
  _context17.t10 = wasPending;
91013
- _context17.next = 94;
91139
+ _context17.next = 86;
91014
91140
  return (0, _context17.t2)(_context17.t3, _context17.t4, _context17.t5, _context17.t9, _context17.t10);
91015
- case 94:
91141
+ case 86:
91016
91142
  cleared = _context17.sent;
91017
91143
  if (!(cleared.state !== 'persisted')) {
91018
- _context17.next = 98;
91144
+ _context17.next = 90;
91019
91145
  break;
91020
91146
  }
91021
91147
  failed.push({
91022
91148
  keyValue: cell.keyValue,
91023
91149
  error: clearRejected(cleared.error)
91024
91150
  });
91025
- return _context17.abrupt("continue", 119);
91026
- case 98:
91151
+ return _context17.abrupt("continue", 111);
91152
+ case 90:
91027
91153
  if (!(cleared.persisted === false)) {
91028
- _context17.next = 101;
91154
+ _context17.next = 93;
91029
91155
  break;
91030
91156
  }
91031
91157
  failed.push({
91032
91158
  keyValue: cell.keyValue,
91033
91159
  error: UNCONFIRMED_CLEAR
91034
91160
  });
91035
- return _context17.abrupt("continue", 119);
91036
- case 101:
91161
+ return _context17.abrupt("continue", 111);
91162
+ case 93:
91037
91163
  assetsCleared = cleared.persisted === true;
91038
91164
  // The confirmed clear saved the row's earlier edits too: the replacement starts on what is pending now.
91039
91165
  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:
91166
+ case 95:
91041
91167
  newValue = newValueFor(node, cell);
91042
- _context17.next = 106;
91168
+ _context17.next = 98;
91043
91169
  return handle.setNodeDataValue(node.id, _defineProperty({}, column, newValue), {
91044
91170
  suppressAutoCommit: true
91045
91171
  });
91046
- case 106:
91172
+ case 98:
91047
91173
  if (_context17.sent) {
91048
- _context17.next = 109;
91174
+ _context17.next = 101;
91049
91175
  break;
91050
91176
  }
91051
91177
  failed.push({
91052
91178
  keyValue: cell.keyValue,
91053
91179
  error: "the row rejected the update".concat(assetsCleared ? CLEARED_ASSETS_NOTE : '')
91054
91180
  });
91055
- return _context17.abrupt("continue", 119);
91056
- case 109:
91057
- _context17.next = 111;
91181
+ return _context17.abrupt("continue", 111);
91182
+ case 101:
91183
+ _context17.next = 103;
91058
91184
  return (_handle$commitStagedC5 = handle.commitStagedChanges) === null || _handle$commitStagedC5 === void 0 ? void 0 : _handle$commitStagedC5.call(handle);
91059
- case 111:
91185
+ case 103:
91060
91186
  outcome = _context17.sent;
91061
91187
  _context17.t11 = recordVerdict;
91062
91188
  _context17.t12 = cell.keyValue;
91063
- _context17.next = 116;
91189
+ _context17.next = 108;
91064
91190
  return settleRefusal(handle, node.id, column, assetWriteVerdict(outcome, node.id), wasPending);
91065
- case 116:
91191
+ case 108:
91066
91192
  _context17.t13 = _context17.sent;
91067
91193
  _context17.t14 = assetsCleared;
91068
91194
  (0, _context17.t11)(_context17.t12, _context17.t13, _context17.t14);
91069
- case 119:
91070
- _context17.next = 48;
91195
+ case 111:
91196
+ _context17.next = 39;
91071
91197
  break;
91072
- case 121:
91073
- _context17.next = 126;
91198
+ case 113:
91199
+ _context17.next = 118;
91074
91200
  break;
91075
- case 123:
91076
- _context17.prev = 123;
91077
- _context17.t15 = _context17["catch"](46);
91201
+ case 115:
91202
+ _context17.prev = 115;
91203
+ _context17.t15 = _context17["catch"](37);
91078
91204
  _iterator8.e(_context17.t15);
91079
- case 126:
91080
- _context17.prev = 126;
91205
+ case 118:
91206
+ _context17.prev = 118;
91081
91207
  _iterator8.f();
91082
- return _context17.finish(126);
91083
- case 129:
91208
+ return _context17.finish(118);
91209
+ case 121:
91084
91210
  if (!filterChanged) {
91085
- _context17.next = 133;
91211
+ _context17.next = 125;
91086
91212
  break;
91087
91213
  }
91088
91214
  api.setFilterModel(Object.keys(filterBefore !== null && filterBefore !== void 0 ? filterBefore : {}).length ? filterBefore : null);
91089
91215
  // The Server-Side Row Model reloads on the restore — the stageable rows below are re-read from it.
91090
- _context17.next = 133;
91216
+ _context17.next = 125;
91091
91217
  return waitForRows(api);
91092
- case 133:
91093
- if (!(stageable.length && stopBatch(startedAt, TIME_BUDGET_MS, signal))) {
91094
- _context17.next = 137;
91218
+ case 125:
91219
+ if (!(stageable.length && stopBatch(startedAt, budgetMs, signal))) {
91220
+ _context17.next = 129;
91095
91221
  break;
91096
91222
  }
91097
91223
  remaining.push.apply(remaining, _toConsumableArray(stageable.map(function (cell) {
91098
91224
  return cell.keyValue;
91099
91225
  })));
91100
- _context17.next = 145;
91226
+ _context17.next = 137;
91101
91227
  break;
91102
- case 137:
91228
+ case 129:
91103
91229
  if (!stageable.length) {
91104
- _context17.next = 145;
91230
+ _context17.next = 137;
91105
91231
  break;
91106
91232
  }
91107
91233
  nodesByKey = loadedNodes();
91108
91234
  blocked = new Set();
91109
91235
  _cleared = new Set();
91110
- _context17.next = 143;
91236
+ _context17.next = 135;
91111
91237
  return stageAndCommit(stageable.filter(function (cell) {
91112
91238
  return needsClearFirst(nodesByKey.get(cell.keyValue), cell);
91113
91239
  }), function () {
@@ -91131,17 +91257,17 @@ function _writeAssetCellsBatch() {
91131
91257
  }
91132
91258
  if (verdict.persisted === true) _cleared.add(cell.keyValue);
91133
91259
  });
91134
- case 143:
91135
- _context17.next = 145;
91260
+ case 135:
91261
+ _context17.next = 137;
91136
91262
  return stageAndCommit(stageable.filter(function (cell) {
91137
91263
  return !blocked.has(cell.keyValue);
91138
91264
  }), newValueFor, function (cell, verdict) {
91139
91265
  return recordVerdict(cell.keyValue, verdict, _cleared.has(cell.keyValue));
91140
91266
  }, _cleared);
91141
- case 145:
91267
+ case 137:
91142
91268
  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.") : '';
91143
91269
  if (!(written.length === 0)) {
91144
- _context17.next = 148;
91270
+ _context17.next = 140;
91145
91271
  break;
91146
91272
  }
91147
91273
  return _context17.abrupt("return", _objectSpread$y(_objectSpread$y({
@@ -91152,7 +91278,7 @@ function _writeAssetCellsBatch() {
91152
91278
  } : {}), {}, {
91153
91279
  note: "NOTHING was written".concat(failed.length ? ' — every started entry failed; see `failed`' : '', ".").concat(notStarted)
91154
91280
  }));
91155
- case 148:
91281
+ case 140:
91156
91282
  persistedCount = written.filter(function (w) {
91157
91283
  return w.persisted === true;
91158
91284
  }).length; // Refetch only when EVERY write was confirmed and nothing else is staged (a refused row left with the user's edits,
@@ -91168,14 +91294,418 @@ function _writeAssetCellsBatch() {
91168
91294
  gridRefreshed: gridRefreshed,
91169
91295
  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
91170
91296
  }));
91171
- case 152:
91297
+ case 144:
91172
91298
  case "end":
91173
91299
  return _context17.stop();
91174
91300
  }
91175
- }, _callee17, null, [[46, 123, 126, 129], [54, 61]]);
91301
+ }, _callee17, null, [[37, 115, 118, 121], [45, 52]]);
91176
91302
  }));
91177
91303
  return _writeAssetCellsBatch.apply(this, arguments);
91178
91304
  }
91305
+ /** A generated image on its way into its target cell. */
91306
+ /** Where one generated image ended up: on its row, or why not. */
91307
+ /** Reads a `target` argument; none is fine (nothing is attached), a half one is refused before anything is spent. */
91308
+ function parseImageTarget(raw) {
91309
+ if (raw === undefined || raw === null) return {};
91310
+ if (_typeof(raw) !== 'object' || Array.isArray(raw)) return {
91311
+ error: 'target must be an object {grid?, keyColumn, keyValue, column, mode?}.'
91312
+ };
91313
+ var fields = raw;
91314
+ var text = function text(value) {
91315
+ return value === undefined || value === null ? '' : String(value).trim();
91316
+ };
91317
+ var missing = ['keyColumn', 'keyValue', 'column'].filter(function (field) {
91318
+ return !text(fields[field]);
91319
+ });
91320
+ if (missing.length) {
91321
+ return {
91322
+ error: "target needs ".concat(missing.join(', '), " \u2014 the row is addressed like a setAssetCell entry: keyColumn = keyValue, column = the asset column.")
91323
+ };
91324
+ }
91325
+ var mode = parseAssetMode(fields.mode);
91326
+ // 'remove' takes an image OUT of a cell — for a brand-new image there is nothing to remove.
91327
+ if (mode.invalid || mode.mode === 'remove') {
91328
+ var _mode$invalid;
91329
+ return {
91330
+ error: "target mode must be 'append' (default) or 'replace' \u2014 got '".concat((_mode$invalid = mode.invalid) !== null && _mode$invalid !== void 0 ? _mode$invalid : fields.mode, "'.")
91331
+ };
91332
+ }
91333
+ var decisionNo = fields.decisionNo === undefined || fields.decisionNo === null ? undefined : Number(fields.decisionNo);
91334
+ if (decisionNo !== undefined && !Number.isInteger(decisionNo)) {
91335
+ return {
91336
+ error: "target decisionNo must be a decision number \u2014 got '".concat(fields.decisionNo, "'.")
91337
+ };
91338
+ }
91339
+ return {
91340
+ target: _objectSpread$y(_objectSpread$y(_objectSpread$y({}, text(fields.grid) ? {
91341
+ grid: text(fields.grid)
91342
+ } : {}), {}, {
91343
+ keyColumn: text(fields.keyColumn),
91344
+ // Not trimmed: the row is matched EXACTLY, like a setAssetCell keyValue.
91345
+ keyValue: String(fields.keyValue),
91346
+ column: text(fields.column)
91347
+ }, mode.mode ? {
91348
+ mode: mode.mode
91349
+ } : {}), decisionNo !== undefined ? {
91350
+ decisionNo: decisionNo
91351
+ } : {})
91352
+ };
91353
+ }
91354
+
91355
+ /**
91356
+ * Why targets cannot take their images, keyed by problem with the entries it concerns. Checked BEFORE the spend, so
91357
+ * nobody pays for an image without a row to go to: the shape, and unless `checkRows` is off the table, its asset column
91358
+ * and that every keyValue marks exactly ONE existing row (a row that is not loaded is looked up on the server).
91359
+ */
91360
+ function imageTargetProblems(_x44, _x45, _x46) {
91361
+ return _imageTargetProblems.apply(this, arguments);
91362
+ }
91363
+ function _imageTargetProblems() {
91364
+ _imageTargetProblems = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee18(root, entries, checkRows) {
91365
+ var problems, add, groups, _iterator9, _step9, _step9$value, target, error, label, _target$grid, _groups$get, key, _iterator10, _step10, _loop;
91366
+ return _regeneratorRuntime.wrap(function _callee18$(_context20) {
91367
+ while (1) switch (_context20.prev = _context20.next) {
91368
+ case 0:
91369
+ problems = new Map();
91370
+ add = function add(problem, labels) {
91371
+ var _problems$get;
91372
+ return problems.set(problem, [].concat(_toConsumableArray((_problems$get = problems.get(problem)) !== null && _problems$get !== void 0 ? _problems$get : []), _toConsumableArray(labels)));
91373
+ };
91374
+ groups = new Map();
91375
+ _iterator9 = _createForOfIteratorHelper$g(entries);
91376
+ try {
91377
+ for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
91378
+ _step9$value = _step9.value, target = _step9$value.target, error = _step9$value.error, label = _step9$value.label;
91379
+ if (error) add(error, [label]);else if (target && checkRows) {
91380
+ key = JSON.stringify([(_target$grid = target.grid) !== null && _target$grid !== void 0 ? _target$grid : '', target.keyColumn, target.column]);
91381
+ groups.set(key, [].concat(_toConsumableArray((_groups$get = groups.get(key)) !== null && _groups$get !== void 0 ? _groups$get : []), [{
91382
+ target: target,
91383
+ label: label
91384
+ }]));
91385
+ }
91386
+ }
91387
+ } catch (err) {
91388
+ _iterator9.e(err);
91389
+ } finally {
91390
+ _iterator9.f();
91391
+ }
91392
+ _iterator10 = _createForOfIteratorHelper$g(groups.values());
91393
+ _context20.prev = 6;
91394
+ _loop = /*#__PURE__*/_regeneratorRuntime.mark(function _loop() {
91395
+ var group, _group$0$target, grid, keyColumn, column, resolved, keyValues, refusals, notLoaded, _iterator11, _step11, _step11$value, keyValue, refusal, _iterator12, _step12, _loop2;
91396
+ return _regeneratorRuntime.wrap(function _loop$(_context19) {
91397
+ while (1) switch (_context19.prev = _context19.next) {
91398
+ case 0:
91399
+ group = _step10.value;
91400
+ _group$0$target = group[0].target, grid = _group$0$target.grid, keyColumn = _group$0$target.keyColumn, column = _group$0$target.column;
91401
+ resolved = resolveAssetColumn(root, grid, keyColumn, column);
91402
+ if (!('error' in resolved)) {
91403
+ _context19.next = 6;
91404
+ break;
91405
+ }
91406
+ add(resolved.error, group.map(function (_ref15) {
91407
+ var label = _ref15.label;
91408
+ return label;
91409
+ }));
91410
+ return _context19.abrupt("return", 1);
91411
+ case 6:
91412
+ keyValues = _toConsumableArray(new Set(group.map(function (_ref16) {
91413
+ var target = _ref16.target;
91414
+ return target.keyValue;
91415
+ })));
91416
+ _context19.next = 9;
91417
+ return refusedAssetKeys(resolved.api, keyColumn, keyValues);
91418
+ case 9:
91419
+ refusals = _context19.sent;
91420
+ notLoaded = keyValues.filter(function (keyValue) {
91421
+ return !refusals.has(keyValue) && !loadedCarriers(resolved.api, keyColumn, keyValue).length;
91422
+ });
91423
+ if (!notLoaded.length) {
91424
+ _context19.next = 18;
91425
+ break;
91426
+ }
91427
+ _context19.t0 = _createForOfIteratorHelper$g;
91428
+ _context19.next = 15;
91429
+ return confirmUniqueKeys(resolved.api, keyColumn, notLoaded, Date.now() + 14000);
91430
+ case 15:
91431
+ _context19.t1 = _context19.sent;
91432
+ _iterator11 = (0, _context19.t0)(_context19.t1);
91433
+ try {
91434
+ for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
91435
+ _step11$value = _slicedToArray(_step11.value, 2), keyValue = _step11$value[0], refusal = _step11$value[1];
91436
+ refusals.set(keyValue, refusal);
91437
+ }
91438
+ } catch (err) {
91439
+ _iterator11.e(err);
91440
+ } finally {
91441
+ _iterator11.f();
91442
+ }
91443
+ case 18:
91444
+ _iterator12 = _createForOfIteratorHelper$g(refusals);
91445
+ _context19.prev = 19;
91446
+ _loop2 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop2() {
91447
+ var _step12$value, keyValue, refusal;
91448
+ return _regeneratorRuntime.wrap(function _loop2$(_context18) {
91449
+ while (1) switch (_context18.prev = _context18.next) {
91450
+ case 0:
91451
+ _step12$value = _slicedToArray(_step12.value, 2), keyValue = _step12$value[0], refusal = _step12$value[1];
91452
+ add(refusal, group.filter(function (_ref17) {
91453
+ var target = _ref17.target;
91454
+ return target.keyValue === keyValue;
91455
+ }).map(function (_ref18) {
91456
+ var label = _ref18.label;
91457
+ return label;
91458
+ }));
91459
+ case 2:
91460
+ case "end":
91461
+ return _context18.stop();
91462
+ }
91463
+ }, _loop2);
91464
+ });
91465
+ _iterator12.s();
91466
+ case 22:
91467
+ if ((_step12 = _iterator12.n()).done) {
91468
+ _context19.next = 26;
91469
+ break;
91470
+ }
91471
+ return _context19.delegateYield(_loop2(), "t2", 24);
91472
+ case 24:
91473
+ _context19.next = 22;
91474
+ break;
91475
+ case 26:
91476
+ _context19.next = 31;
91477
+ break;
91478
+ case 28:
91479
+ _context19.prev = 28;
91480
+ _context19.t3 = _context19["catch"](19);
91481
+ _iterator12.e(_context19.t3);
91482
+ case 31:
91483
+ _context19.prev = 31;
91484
+ _iterator12.f();
91485
+ return _context19.finish(31);
91486
+ case 34:
91487
+ case "end":
91488
+ return _context19.stop();
91489
+ }
91490
+ }, _loop, null, [[19, 28, 31, 34]]);
91491
+ });
91492
+ _iterator10.s();
91493
+ case 9:
91494
+ if ((_step10 = _iterator10.n()).done) {
91495
+ _context20.next = 15;
91496
+ break;
91497
+ }
91498
+ return _context20.delegateYield(_loop(), "t0", 11);
91499
+ case 11:
91500
+ if (!_context20.t0) {
91501
+ _context20.next = 13;
91502
+ break;
91503
+ }
91504
+ return _context20.abrupt("continue", 13);
91505
+ case 13:
91506
+ _context20.next = 9;
91507
+ break;
91508
+ case 15:
91509
+ _context20.next = 20;
91510
+ break;
91511
+ case 17:
91512
+ _context20.prev = 17;
91513
+ _context20.t1 = _context20["catch"](6);
91514
+ _iterator10.e(_context20.t1);
91515
+ case 20:
91516
+ _context20.prev = 20;
91517
+ _iterator10.f();
91518
+ return _context20.finish(20);
91519
+ case 23:
91520
+ return _context20.abrupt("return", problems);
91521
+ case 24:
91522
+ case "end":
91523
+ return _context20.stop();
91524
+ }
91525
+ }, _callee18, null, [[6, 17, 20, 23]]);
91526
+ }));
91527
+ return _imageTargetProblems.apply(this, arguments);
91528
+ }
91529
+ var ATTACH_NOT_STARTED = 'the call ran out of time (or the turn was aborted) before this row was written — the image is generated, do not generate it again: write its mediaItemId with setAssetCell';
91530
+ var ATTACH_DECLINED = 'the user DECLINED writing the generated images into the table — nothing was written; ask what to do instead';
91531
+ var ATTACH_EXPIRED = 'the approval bar for writing the images was not answered in time and was withdrawn — nothing was written; the images are generated, do not generate them again: write them with setAssetCell cells';
91532
+ var ATTACH_UNCONFIRMED = 'the write was staged but the server did NOT confirm it — do not touch the table (no locateRow, filter or scroll: a reload discards it) and write this key again with setAssetCell';
91533
+
91534
+ /**
91535
+ * Writes generated images into their target cells through the setAssetCell batch writer — the same refusals,
91536
+ * auto-locate, take-back of refused entries and ONE approval bar per table and column. Returns one outcome per image.
91537
+ */
91538
+ function attachGeneratedImages(_x47, _x48, _x49) {
91539
+ return _attachGeneratedImages.apply(this, arguments);
91540
+ }
91541
+ /** Per-article result of a generateArticleSvg batch run — ids and findings only, never the markup. */
91542
+ function _attachGeneratedImages() {
91543
+ _attachGeneratedImages = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee20(root, images, options) {
91544
+ var deadline, groups, outcomes, _iterator13, _step13, _loop3;
91545
+ return _regeneratorRuntime.wrap(function _callee20$(_context23) {
91546
+ while (1) switch (_context23.prev = _context23.next) {
91547
+ case 0:
91548
+ deadline = options.callStartedAt + ATTACH_DEADLINE_MS;
91549
+ groups = new Map();
91550
+ images.forEach(function (_ref19, index) {
91551
+ var _target$grid2, _groups$get2;
91552
+ var target = _ref19.target;
91553
+ var key = JSON.stringify([(_target$grid2 = target.grid) !== null && _target$grid2 !== void 0 ? _target$grid2 : '', target.keyColumn, target.column]);
91554
+ groups.set(key, [].concat(_toConsumableArray((_groups$get2 = groups.get(key)) !== null && _groups$get2 !== void 0 ? _groups$get2 : []), [index]));
91555
+ });
91556
+ outcomes = images.map(function () {
91557
+ return {
91558
+ attached: false,
91559
+ attachError: ATTACH_NOT_STARTED
91560
+ };
91561
+ });
91562
+ _iterator13 = _createForOfIteratorHelper$g(groups.values());
91563
+ _context23.prev = 5;
91564
+ _loop3 = /*#__PURE__*/_regeneratorRuntime.mark(function _loop3() {
91565
+ var _options$signal4;
91566
+ var indexes, _images$indexes$0$tar, grid, keyColumn, column, expired, approve, result, verdicts, add, asList, unanswered, groupError;
91567
+ return _regeneratorRuntime.wrap(function _loop3$(_context22) {
91568
+ while (1) switch (_context22.prev = _context22.next) {
91569
+ case 0:
91570
+ indexes = _step13.value;
91571
+ _images$indexes$0$tar = images[indexes[0]].target, grid = _images$indexes$0$tar.grid, keyColumn = _images$indexes$0$tar.keyColumn, column = _images$indexes$0$tar.column;
91572
+ expired = false; // The bar is withdrawn at the deadline: an answer after it would arrive after the bridge cut the call.
91573
+ approve = options.autoApprove ? undefined : (/*#__PURE__*/function () {
91574
+ var _ref20 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee19(entry, count) {
91575
+ var _options$signal, _options$signal2;
91576
+ var bounded, forward, timer, _options$signal3;
91577
+ return _regeneratorRuntime.wrap(function _callee19$(_context21) {
91578
+ while (1) switch (_context21.prev = _context21.next) {
91579
+ case 0:
91580
+ bounded = new AbortController();
91581
+ forward = function forward() {
91582
+ return bounded.abort();
91583
+ };
91584
+ if ((_options$signal = options.signal) !== null && _options$signal !== void 0 && _options$signal.aborted) bounded.abort();else (_options$signal2 = options.signal) === null || _options$signal2 === void 0 || _options$signal2.addEventListener('abort', forward);
91585
+ timer = setTimeout(function () {
91586
+ expired = true;
91587
+ bounded.abort();
91588
+ }, Math.max(0, deadline - Date.now()));
91589
+ _context21.prev = 4;
91590
+ _context21.next = 7;
91591
+ return entry.requestAgentApproval(count, "generateImageAsset \u2192 ".concat(count, " ").concat(count === 1 ? 'cell' : 'cells', " (").concat(column, ")"), bounded.signal);
91592
+ case 7:
91593
+ return _context21.abrupt("return", _context21.sent);
91594
+ case 8:
91595
+ _context21.prev = 8;
91596
+ clearTimeout(timer);
91597
+ (_options$signal3 = options.signal) === null || _options$signal3 === void 0 || _options$signal3.removeEventListener('abort', forward);
91598
+ return _context21.finish(8);
91599
+ case 12:
91600
+ case "end":
91601
+ return _context21.stop();
91602
+ }
91603
+ }, _callee19, null, [[4,, 8, 12]]);
91604
+ }));
91605
+ return function (_x64, _x65) {
91606
+ return _ref20.apply(this, arguments);
91607
+ };
91608
+ }());
91609
+ _context22.next = 6;
91610
+ return writeAssetCellsBatch(root, grid, keyColumn, column, 'append', indexes.map(function (index) {
91611
+ return {
91612
+ keyValue: images[index].target.keyValue,
91613
+ mediaItemId: images[index].mediaItemId,
91614
+ url: images[index].url,
91615
+ name: images[index].fileName,
91616
+ decisionNo: images[index].target.decisionNo,
91617
+ mode: images[index].target.mode
91618
+ };
91619
+ }), approve, options.signal, {
91620
+ startedAt: options.callStartedAt,
91621
+ budgetMs: ATTACH_DEADLINE_MS
91622
+ });
91623
+ case 6:
91624
+ result = _context22.sent;
91625
+ // Per key, the writer's verdicts in the order of its cells — several images may go into the same row.
91626
+ verdicts = new Map();
91627
+ add = function add(keyValue, outcome) {
91628
+ var _verdicts$get;
91629
+ return verdicts.set(String(keyValue), [].concat(_toConsumableArray((_verdicts$get = verdicts.get(String(keyValue))) !== null && _verdicts$get !== void 0 ? _verdicts$get : []), [outcome]));
91630
+ };
91631
+ asList = function asList(value) {
91632
+ return Array.isArray(value) ? value : [];
91633
+ };
91634
+ asList(result.written).forEach(function (written) {
91635
+ return add(written.keyValue, written.persisted === false ? {
91636
+ attached: false,
91637
+ attachError: ATTACH_UNCONFIRMED
91638
+ } : _objectSpread$y(_objectSpread$y({
91639
+ attached: true
91640
+ }, typeof written.persisted === 'boolean' ? {
91641
+ persisted: written.persisted
91642
+ } : {}), Array.isArray(written.sharedWith) ? {
91643
+ sharedWith: written.sharedWith.map(String),
91644
+ note: String(written.note)
91645
+ } : {}));
91646
+ });
91647
+ asList(result.failed).forEach(function (failed) {
91648
+ return add(failed.keyValue, {
91649
+ attached: false,
91650
+ attachError: String(failed.error)
91651
+ });
91652
+ });
91653
+ (Array.isArray(result.remaining) ? result.remaining : []).forEach(function (keyValue) {
91654
+ return add(keyValue, {
91655
+ attached: false,
91656
+ attachError: ATTACH_NOT_STARTED
91657
+ });
91658
+ });
91659
+ // A bar closed by the deadline or by the aborted turn is no decision of the user.
91660
+ unanswered = expired ? ATTACH_EXPIRED : (_options$signal4 = options.signal) !== null && _options$signal4 !== void 0 && _options$signal4.aborted ? ATTACH_NOT_STARTED : ATTACH_DECLINED;
91661
+ groupError = typeof result.error === 'string' ? result.error : result.applied === false ? unanswered : undefined;
91662
+ indexes.forEach(function (index) {
91663
+ var _verdicts$get$shift, _verdicts$get2;
91664
+ outcomes[index] = groupError ? {
91665
+ attached: false,
91666
+ attachError: groupError
91667
+ } : (_verdicts$get$shift = (_verdicts$get2 = verdicts.get(images[index].target.keyValue)) === null || _verdicts$get2 === void 0 ? void 0 : _verdicts$get2.shift()) !== null && _verdicts$get$shift !== void 0 ? _verdicts$get$shift : {
91668
+ attached: false,
91669
+ attachError: ATTACH_NOT_STARTED
91670
+ };
91671
+ });
91672
+ case 16:
91673
+ case "end":
91674
+ return _context22.stop();
91675
+ }
91676
+ }, _loop3);
91677
+ });
91678
+ _iterator13.s();
91679
+ case 8:
91680
+ if ((_step13 = _iterator13.n()).done) {
91681
+ _context23.next = 12;
91682
+ break;
91683
+ }
91684
+ return _context23.delegateYield(_loop3(), "t0", 10);
91685
+ case 10:
91686
+ _context23.next = 8;
91687
+ break;
91688
+ case 12:
91689
+ _context23.next = 17;
91690
+ break;
91691
+ case 14:
91692
+ _context23.prev = 14;
91693
+ _context23.t1 = _context23["catch"](5);
91694
+ _iterator13.e(_context23.t1);
91695
+ case 17:
91696
+ _context23.prev = 17;
91697
+ _iterator13.f();
91698
+ return _context23.finish(17);
91699
+ case 20:
91700
+ return _context23.abrupt("return", outcomes);
91701
+ case 21:
91702
+ case "end":
91703
+ return _context23.stop();
91704
+ }
91705
+ }, _callee20, null, [[5, 14, 17, 20]]);
91706
+ }));
91707
+ return _attachGeneratedImages.apply(this, arguments);
91708
+ }
91179
91709
  var BATCH_MAX_ARTICLES = 60;
91180
91710
  /** Keys that configure the RUN rather than one article — inherited by every batch entry. */
91181
91711
  var BATCH_SHARED_KEYS = ['style', 'styleUrl', 'format', 'canvasCm', 'jpgSizePx', 'returnSvg', 'grid', 'column'];
@@ -91184,7 +91714,7 @@ var BATCH_SHARED_KEYS = ['style', 'styleUrl', 'format', 'canvasCm', 'jpgSizePx',
91184
91714
  * Generates and uploads a whole serie in ONE call. Deliberately does NOT attach: one setAssetCell
91185
91715
  * `cells:[…]` costs the user one approval bar instead of one per article. Markup stays out of the result.
91186
91716
  */
91187
- function generateArticleSvgBatch(_x43, _x44, _x45, _x46, _x47) {
91717
+ function generateArticleSvgBatch(_x50, _x51, _x52, _x53, _x54) {
91188
91718
  return _generateArticleSvgBatch.apply(this, arguments);
91189
91719
  }
91190
91720
  /**
@@ -91192,64 +91722,64 @@ function generateArticleSvgBatch(_x43, _x44, _x45, _x46, _x47) {
91192
91722
  * because asset cells store `{mediaitemId, url, name}` objects that only exist after an upload.
91193
91723
  */
91194
91724
  function _generateArticleSvgBatch() {
91195
- _generateArticleSvgBatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee18(root, shared, entries, storedStyle, signal) {
91725
+ _generateArticleSvgBatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee21(root, shared, entries, storedStyle, signal) {
91196
91726
  var _shared$format;
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;
91198
- return _regeneratorRuntime.wrap(function _callee18$(_context18) {
91199
- while (1) switch (_context18.prev = _context18.next) {
91727
+ var inherited, _iterator14, _step14, key, results, failed, startedAt, remaining, _iterator15, _step15, _step15$value, index, entry, merged, typeNo, _merged$format, _merged$fileName, _generated$warnings, spec, inline, generated, format, extension, rawName, requestedFileName, fileName, file, uploaded, column;
91728
+ return _regeneratorRuntime.wrap(function _callee21$(_context24) {
91729
+ while (1) switch (_context24.prev = _context24.next) {
91200
91730
  case 0:
91201
91731
  if (!(entries.length === 0)) {
91202
- _context18.next = 2;
91732
+ _context24.next = 2;
91203
91733
  break;
91204
91734
  }
91205
- return _context18.abrupt("return", {
91735
+ return _context24.abrupt("return", {
91206
91736
  error: 'batch is empty — pass one article spec per entry.'
91207
91737
  });
91208
91738
  case 2:
91209
91739
  if (!(entries.length > BATCH_MAX_ARTICLES)) {
91210
- _context18.next = 4;
91740
+ _context24.next = 4;
91211
91741
  break;
91212
91742
  }
91213
- return _context18.abrupt("return", {
91743
+ return _context24.abrupt("return", {
91214
91744
  error: "batch supports at most ".concat(BATCH_MAX_ARTICLES, " articles per call \u2014 got ").concat(entries.length, ". Split the serie.")
91215
91745
  });
91216
91746
  case 4:
91217
91747
  inherited = {};
91218
- _iterator9 = _createForOfIteratorHelper$g(BATCH_SHARED_KEYS);
91748
+ _iterator14 = _createForOfIteratorHelper$g(BATCH_SHARED_KEYS);
91219
91749
  try {
91220
- for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
91221
- key = _step9.value;
91750
+ for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
91751
+ key = _step14.value;
91222
91752
  if (shared[key] !== undefined) inherited[key] = shared[key];
91223
91753
  }
91224
91754
  } catch (err) {
91225
- _iterator9.e(err);
91755
+ _iterator14.e(err);
91226
91756
  } finally {
91227
- _iterator9.f();
91757
+ _iterator14.f();
91228
91758
  }
91229
91759
  results = [];
91230
91760
  failed = []; // Stop before the bridge's hard timeout (or once the turn is aborted) and hand the untouched rest back, or the
91231
91761
  // receipt is lost while the assets landed.
91232
91762
  startedAt = Date.now();
91233
91763
  remaining = [];
91234
- _iterator10 = _createForOfIteratorHelper$g(entries.entries());
91235
- _context18.prev = 12;
91236
- _iterator10.s();
91764
+ _iterator15 = _createForOfIteratorHelper$g(entries.entries());
91765
+ _context24.prev = 12;
91766
+ _iterator15.s();
91237
91767
  case 14:
91238
- if ((_step10 = _iterator10.n()).done) {
91239
- _context18.next = 55;
91768
+ if ((_step15 = _iterator15.n()).done) {
91769
+ _context24.next = 56;
91240
91770
  break;
91241
91771
  }
91242
- _step10$value = _slicedToArray(_step10.value, 2), index = _step10$value[0], entry = _step10$value[1];
91772
+ _step15$value = _slicedToArray(_step15.value, 2), index = _step15$value[0], entry = _step15$value[1];
91243
91773
  merged = _objectSpread$y(_objectSpread$y({}, inherited), entry);
91244
91774
  typeNo = merged.typeNo === undefined ? undefined : String(merged.typeNo);
91245
91775
  if (!stopBatch(startedAt, TIME_BUDGET_MS, signal)) {
91246
- _context18.next = 21;
91776
+ _context24.next = 21;
91247
91777
  break;
91248
91778
  }
91249
91779
  remaining.push(typeNo !== null && typeNo !== void 0 ? typeNo : "#".concat(index + 1));
91250
- return _context18.abrupt("continue", 53);
91780
+ return _context24.abrupt("continue", 54);
91251
91781
  case 21:
91252
- _context18.prev = 21;
91782
+ _context24.prev = 21;
91253
91783
  spec = _objectSpread$y({}, merged);
91254
91784
  if (storedStyle) {
91255
91785
  inline = _typeof(merged.style) === 'object' && merged.style ? merged.style : undefined;
@@ -91258,45 +91788,49 @@ function _generateArticleSvgBatch() {
91258
91788
  generated = buildArticleTopViewSvg(spec);
91259
91789
  format = String((_merged$format = merged.format) !== null && _merged$format !== void 0 ? _merged$format : 'svg').trim().toLowerCase();
91260
91790
  if (['svg', 'jpg'].includes(format)) {
91261
- _context18.next = 28;
91791
+ _context24.next = 28;
91262
91792
  break;
91263
91793
  }
91264
91794
  throw new Error("format must be 'svg' or 'jpg' \u2014 got '".concat(merged.format, "'."));
91265
91795
  case 28:
91266
91796
  extension = format === 'jpg' ? '.jpg' : '.svg';
91267
91797
  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));
91268
- fileName = rawName.toLowerCase().endsWith(extension) ? rawName : "".concat(rawName.replace(/\.(svg|jpe?g)$/i, '')).concat(extension);
91798
+ requestedFileName = rawName.toLowerCase().endsWith(extension) ? rawName : "".concat(rawName.replace(/\.(svg|jpe?g)$/i, '')).concat(extension); // Fitted before the upload: an IDM asset cell takes the media item's own name (at most 40 characters).
91799
+ fileName = fitMediaName(requestedFileName);
91269
91800
  if (!(format === 'jpg')) {
91270
- _context18.next = 42;
91801
+ _context24.next = 43;
91271
91802
  break;
91272
91803
  }
91273
- _context18.t1 = File;
91274
- _context18.next = 35;
91804
+ _context24.t1 = File;
91805
+ _context24.next = 36;
91275
91806
  return svgToJpegBlob(generated.svg, Math.max(64, Math.min(4096, Number(merged.jpgSizePx) || 1024)));
91276
- case 35:
91277
- _context18.t2 = _context18.sent;
91278
- _context18.t3 = [_context18.t2];
91279
- _context18.t4 = fileName;
91280
- _context18.t5 = {
91807
+ case 36:
91808
+ _context24.t2 = _context24.sent;
91809
+ _context24.t3 = [_context24.t2];
91810
+ _context24.t4 = fileName;
91811
+ _context24.t5 = {
91281
91812
  type: 'image/jpeg'
91282
91813
  };
91283
- _context18.t0 = new _context18.t1(_context18.t3, _context18.t4, _context18.t5);
91284
- _context18.next = 43;
91814
+ _context24.t0 = new _context24.t1(_context24.t3, _context24.t4, _context24.t5);
91815
+ _context24.next = 44;
91285
91816
  break;
91286
- case 42:
91287
- _context18.t0 = new File([generated.svg], fileName, {
91817
+ case 43:
91818
+ _context24.t0 = new File([generated.svg], fileName, {
91288
91819
  type: 'image/svg+xml'
91289
91820
  });
91290
- case 43:
91291
- file = _context18.t0;
91292
- _context18.next = 46;
91821
+ case 44:
91822
+ file = _context24.t0;
91823
+ _context24.next = 47;
91293
91824
  return uploadToMediaService(root, file, fileName, undefined, signal);
91294
- case 46:
91295
- uploaded = _context18.sent;
91296
- results.push(_objectSpread$y(_objectSpread$y({}, typeNo ? {
91825
+ case 47:
91826
+ uploaded = _context24.sent;
91827
+ results.push(_objectSpread$y(_objectSpread$y(_objectSpread$y({}, typeNo ? {
91297
91828
  typeNo: typeNo
91298
91829
  } : {}), {}, {
91299
- fileName: uploaded.fileName,
91830
+ fileName: uploaded.fileName
91831
+ }, fileName !== requestedFileName ? {
91832
+ requestedFileName: requestedFileName
91833
+ } : {}), {}, {
91300
91834
  mediaItemId: uploaded.mediaItemId,
91301
91835
  url: uploaded.url,
91302
91836
  canvasCm: generated.canvasCm,
@@ -91304,35 +91838,35 @@ function _generateArticleSvgBatch() {
91304
91838
  }, (_generated$warnings = generated.warnings) !== null && _generated$warnings !== void 0 && _generated$warnings.length ? {
91305
91839
  warnings: generated.warnings
91306
91840
  } : {}));
91307
- _context18.next = 53;
91841
+ _context24.next = 54;
91308
91842
  break;
91309
- case 50:
91310
- _context18.prev = 50;
91311
- _context18.t6 = _context18["catch"](21);
91843
+ case 51:
91844
+ _context24.prev = 51;
91845
+ _context24.t6 = _context24["catch"](21);
91312
91846
  failed.push(_objectSpread$y(_objectSpread$y({
91313
91847
  index: index
91314
91848
  }, typeNo ? {
91315
91849
  typeNo: typeNo
91316
91850
  } : {}), {}, {
91317
- error: _context18.t6 instanceof Error ? _context18.t6.message : String(_context18.t6)
91851
+ error: _context24.t6 instanceof Error ? _context24.t6.message : String(_context24.t6)
91318
91852
  }));
91319
- case 53:
91320
- _context18.next = 14;
91853
+ case 54:
91854
+ _context24.next = 14;
91321
91855
  break;
91322
- case 55:
91323
- _context18.next = 60;
91856
+ case 56:
91857
+ _context24.next = 61;
91324
91858
  break;
91325
- case 57:
91326
- _context18.prev = 57;
91327
- _context18.t7 = _context18["catch"](12);
91328
- _iterator10.e(_context18.t7);
91329
- case 60:
91330
- _context18.prev = 60;
91331
- _iterator10.f();
91332
- return _context18.finish(60);
91333
- case 63:
91859
+ case 58:
91860
+ _context24.prev = 58;
91861
+ _context24.t7 = _context24["catch"](12);
91862
+ _iterator15.e(_context24.t7);
91863
+ case 61:
91864
+ _context24.prev = 61;
91865
+ _iterator15.f();
91866
+ return _context24.finish(61);
91867
+ case 64:
91334
91868
  column = shared.column ? String(shared.column) : String((_shared$format = shared.format) !== null && _shared$format !== void 0 ? _shared$format : 'svg') === 'jpg' ? 'images' : 'svgs';
91335
- return _context18.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
91869
+ return _context24.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
91336
91870
  batch: true,
91337
91871
  uploaded: results.length
91338
91872
  }, failed.length ? {
@@ -91341,13 +91875,15 @@ function _generateArticleSvgBatch() {
91341
91875
  remaining: remaining
91342
91876
  } : {}), {}, {
91343
91877
  results: results,
91344
- note: "".concat(results.length, " asset(s) generated + uploaded, NONE attached. Write them with ONE setAssetCell cells:[{keyValue: <typeNo>, mediaItemId}] on column '").concat(column, "' \u2014 that is a single approval bar for the whole serie.") + (failed.length ? " ".concat(failed.length, " entr(y|ies) FAILED and are listed in 'failed' \u2014 the rest is uploaded and usable.") : '') + (remaining.length ? " ".concat(remaining.length, " entr(y|ies) were NOT processed (").concat(signal !== null && signal !== void 0 && signal.aborted ? 'the turn was aborted' : 'time budget', ") \u2014 repeat the call with ONLY the 'remaining' articles.") : '')
91878
+ note: "".concat(results.length, " asset(s) generated + uploaded, NONE attached. Write them with ONE setAssetCell cells:[{keyValue: <typeNo>, mediaItemId}] on column '").concat(column, "' \u2014 that is a single approval bar for the whole serie.") + (failed.length ? " ".concat(failed.length, " entr(y|ies) FAILED and are listed in 'failed' \u2014 the rest is uploaded and usable.") : '') + (remaining.length ? " ".concat(remaining.length, " entr(y|ies) were NOT processed (").concat(signal !== null && signal !== void 0 && signal.aborted ? 'the turn was aborted' : 'time budget', ") \u2014 repeat the call with ONLY the 'remaining' articles.") : '') + shortenedNameNote(results.flatMap(function (result) {
91879
+ return result.requestedFileName ? [result.fileName] : [];
91880
+ }))
91345
91881
  }));
91346
- case 65:
91882
+ case 66:
91347
91883
  case "end":
91348
- return _context18.stop();
91884
+ return _context24.stop();
91349
91885
  }
91350
- }, _callee18, null, [[12, 57, 60, 63], [21, 50]]);
91886
+ }, _callee21, null, [[12, 58, 61, 64], [21, 51]]);
91351
91887
  }));
91352
91888
  return _generateArticleSvgBatch.apply(this, arguments);
91353
91889
  }
@@ -91364,7 +91900,7 @@ function createMediaToolset(ctx) {
91364
91900
  toolNames: MEDIA_TOOL_NAMES,
91365
91901
  dispatch: function () {
91366
91902
  var _dispatch = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(name, input, signal) {
91367
- var args, notStartedNote, _result$fileName, longNameNote, 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;
91903
+ var args, notStartedNote, _result$fileName, uploadOne, startedAt, results, remaining, _iterator, _step, _request$fileName, entry, request, fileName, failed, result, callStartedAt, batchEntries, imageCount, labelOf, targetOf, parsedTargets, targetProblems, problems, targets, host, approved, attach, toAttach, target, one, _yield$attach, _yield$attach2, outcome, receipt, where, _startedAt, generationBudgetMs, _results, _remaining, usage, _iterator2, _step2, _step2$value, index, _entry, label, _one, attachable, outcomes, _failed, generated, targeted, untargeted, attachedCount, allAttached, _args$mediaItemId, _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, requestedFileName, _fileName, nameNote, uploaded, file, attachColumn, attachResult;
91368
91904
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
91369
91905
  while (1) switch (_context2.prev = _context2.next) {
91370
91906
  case 0:
@@ -91373,16 +91909,9 @@ function createMediaToolset(ctx) {
91373
91909
  return "".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");
91374
91910
  };
91375
91911
  _context2.t0 = name;
91376
- _context2.next = _context2.t0 === 'uploadAsset' ? 5 : _context2.t0 === 'generateImageAsset' ? 49 : _context2.t0 === 'publishCatalogTestManifest' ? 100 : _context2.t0 === 'getAssetUrls' ? 101 : _context2.t0 === 'setAssetCell' ? 102 : _context2.t0 === 'generateArticleSvg' ? 130 : 230;
91912
+ _context2.next = _context2.t0 === 'uploadAsset' ? 5 : _context2.t0 === 'generateImageAsset' ? 48 : _context2.t0 === 'publishCatalogTestManifest' ? 146 : _context2.t0 === 'getAssetUrls' ? 147 : _context2.t0 === 'setAssetCell' ? 148 : _context2.t0 === 'generateArticleSvg' ? 174 : 276;
91377
91913
  break;
91378
91914
  case 5:
91379
- // The upload takes any file name; an IDM asset cell refuses a media name over 40 characters later, in setAssetCell.
91380
- longNameNote = function longNameNote(fileNames) {
91381
- var tooLong = fileNames.filter(function (fileName) {
91382
- return fileName.length > IDM_MEDIA_NAME_MAX;
91383
- });
91384
- return tooLong.length ? " NAME TOO LONG for an IDM asset cell (at most ".concat(IDM_MEDIA_NAME_MAX, " characters): ").concat(tooLong.join(', '), " \u2014 pass a shorter 'name' to setAssetCell.") : '';
91385
- };
91386
91915
  uploadOne = /*#__PURE__*/function () {
91387
91916
  var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(request) {
91388
91917
  var resolved;
@@ -91418,70 +91947,70 @@ function createMediaToolset(ctx) {
91418
91947
  }
91419
91948
  }, _callee, null, [[5, 11]]);
91420
91949
  }));
91421
- return function uploadOne(_x51) {
91950
+ return function uploadOne(_x58) {
91422
91951
  return _ref.apply(this, arguments);
91423
91952
  };
91424
91953
  }(); // BATCH: sequential on purpose — a parallel burst of three-request handshakes fails halfway.
91425
91954
  if (!Array.isArray(args.files)) {
91426
- _context2.next = 43;
91955
+ _context2.next = 42;
91427
91956
  break;
91428
91957
  }
91429
91958
  if (args.files.length) {
91430
- _context2.next = 10;
91959
+ _context2.next = 9;
91431
91960
  break;
91432
91961
  }
91433
91962
  return _context2.abrupt("return", {
91434
91963
  error: "'files' is empty — pass at least one {fileName, url|svg|base64} entry."
91435
91964
  });
91436
- case 10:
91965
+ case 9:
91437
91966
  // Stop before the bridge's hard timeout and hand the untouched rest back, or the receipt is lost while the files landed.
91438
91967
  startedAt = Date.now();
91439
91968
  results = [];
91440
91969
  remaining = [];
91441
91970
  _iterator = _createForOfIteratorHelper$g(args.files);
91442
- _context2.prev = 14;
91971
+ _context2.prev = 13;
91443
91972
  _iterator.s();
91444
- case 16:
91973
+ case 15:
91445
91974
  if ((_step = _iterator.n()).done) {
91446
- _context2.next = 33;
91975
+ _context2.next = 32;
91447
91976
  break;
91448
91977
  }
91449
91978
  entry = _step.value;
91450
91979
  request = entry !== null && entry !== void 0 ? entry : {};
91451
91980
  fileName = String((_request$fileName = request.fileName) !== null && _request$fileName !== void 0 ? _request$fileName : '').trim() || '(missing fileName)';
91452
91981
  if (!stopBatch(startedAt, TIME_BUDGET_MS, signal)) {
91453
- _context2.next = 23;
91982
+ _context2.next = 22;
91454
91983
  break;
91455
91984
  }
91456
91985
  remaining.push(fileName);
91457
- return _context2.abrupt("continue", 31);
91458
- case 23:
91986
+ return _context2.abrupt("continue", 30);
91987
+ case 22:
91459
91988
  _context2.t1 = results;
91460
91989
  _context2.t2 = _objectSpread$y;
91461
91990
  _context2.t3 = {
91462
91991
  fileName: fileName
91463
91992
  };
91464
- _context2.next = 28;
91993
+ _context2.next = 27;
91465
91994
  return uploadOne(request);
91466
- case 28:
91995
+ case 27:
91467
91996
  _context2.t4 = _context2.sent;
91468
91997
  _context2.t5 = (0, _context2.t2)(_context2.t3, _context2.t4);
91469
91998
  _context2.t1.push.call(_context2.t1, _context2.t5);
91470
- case 31:
91471
- _context2.next = 16;
91999
+ case 30:
92000
+ _context2.next = 15;
91472
92001
  break;
91473
- case 33:
91474
- _context2.next = 38;
92002
+ case 32:
92003
+ _context2.next = 37;
91475
92004
  break;
91476
- case 35:
91477
- _context2.prev = 35;
91478
- _context2.t6 = _context2["catch"](14);
92005
+ case 34:
92006
+ _context2.prev = 34;
92007
+ _context2.t6 = _context2["catch"](13);
91479
92008
  _iterator.e(_context2.t6);
91480
- case 38:
91481
- _context2.prev = 38;
92009
+ case 37:
92010
+ _context2.prev = 37;
91482
92011
  _iterator.f();
91483
- return _context2.finish(38);
91484
- case 41:
92012
+ return _context2.finish(37);
92013
+ case 40:
91485
92014
  failed = results.filter(function (r) {
91486
92015
  return r.error;
91487
92016
  });
@@ -91499,53 +92028,99 @@ function createMediaToolset(ctx) {
91499
92028
  return String(r.fileName);
91500
92029
  }))
91501
92030
  }));
91502
- case 43:
91503
- _context2.next = 45;
92031
+ case 42:
92032
+ _context2.next = 44;
91504
92033
  return uploadOne(args);
91505
- case 45:
92034
+ case 44:
91506
92035
  result = _context2.sent;
91507
92036
  if (!('error' in result)) {
91508
- _context2.next = 48;
92037
+ _context2.next = 47;
91509
92038
  break;
91510
92039
  }
91511
92040
  return _context2.abrupt("return", result);
91512
- case 48:
92041
+ case 47:
91513
92042
  return _context2.abrupt("return", _objectSpread$y(_objectSpread$y({}, result), {}, {
91514
92043
  note: 'Asset uploaded — reference it via setAssetCell (asset columns) using this mediaItemId. It is unused until referenced.' + longNameNote([String((_result$fileName = result.fileName) !== null && _result$fileName !== void 0 ? _result$fileName : '')])
91515
92044
  }));
91516
- case 49:
92045
+ case 48:
91517
92046
  if (!(Array.isArray(args.batch) && !args.batch.length)) {
91518
- _context2.next = 51;
92047
+ _context2.next = 50;
91519
92048
  break;
91520
92049
  }
91521
92050
  return _context2.abrupt("return", {
91522
92051
  error: "'batch' is empty — pass at least one {prompt, fileName} entry."
91523
92052
  });
91524
- case 51:
91525
- imageCount = Array.isArray(args.batch) ? args.batch.length : 1; // Unlike uploadAsset this is not free: every image is charged against the ORGANIZATION's AI budget and a
92053
+ case 50:
92054
+ callStartedAt = Date.now();
92055
+ batchEntries = Array.isArray(args.batch) ? args.batch.map(function (raw) {
92056
+ return raw !== null && raw !== void 0 ? raw : {};
92057
+ }) : undefined;
92058
+ imageCount = batchEntries ? batchEntries.length : 1;
92059
+ labelOf = function labelOf(entry) {
92060
+ var _entry$fileName, _entry$prompt;
92061
+ return String((_entry$fileName = entry.fileName) !== null && _entry$fileName !== void 0 ? _entry$fileName : '').trim() || String((_entry$prompt = entry.prompt) !== null && _entry$prompt !== void 0 ? _entry$prompt : '').slice(0, 60) || '(unnamed)';
92062
+ }; // Batch entries inherit the top-level target: grid/keyColumn/column once, keyValue per entry.
92063
+ targetOf = function targetOf(own) {
92064
+ var shared = args.target;
92065
+ if (own === undefined || own === null) return parseImageTarget(shared);
92066
+ var isObject = function isObject(value) {
92067
+ return !!value && _typeof(value) === 'object' && !Array.isArray(value);
92068
+ };
92069
+ return parseImageTarget(isObject(shared) && isObject(own) ? _objectSpread$y(_objectSpread$y({}, shared), own) : own);
92070
+ };
92071
+ parsedTargets = batchEntries ? batchEntries.map(function (entry) {
92072
+ return targetOf(entry.target);
92073
+ }) : [targetOf()]; // A target is checked BEFORE the spend: an image that cannot be attached was paid for nothing. A dryRun spends
92074
+ // nothing and needs no table on screen, so only the shape of its targets is checked.
92075
+ _context2.next = 58;
92076
+ return imageTargetProblems(root, parsedTargets.map(function (parsed, index) {
92077
+ return _objectSpread$y(_objectSpread$y({}, parsed), {}, {
92078
+ label: batchEntries ? labelOf(batchEntries[index]) : ''
92079
+ });
92080
+ }), !args.dryRun);
92081
+ case 58:
92082
+ targetProblems = _context2.sent;
92083
+ if (!targetProblems.size) {
92084
+ _context2.next = 62;
92085
+ break;
92086
+ }
92087
+ problems = _toConsumableArray(targetProblems).map(function (_ref2) {
92088
+ var _ref3 = _slicedToArray(_ref2, 2),
92089
+ problem = _ref3[0],
92090
+ labels = _ref3[1];
92091
+ return batchEntries ? "".concat(labels.join(', '), ": ").concat(problem) : problem;
92092
+ });
92093
+ return _context2.abrupt("return", {
92094
+ error: "".concat(problems.join(' '), " Nothing was generated.")
92095
+ });
92096
+ case 62:
92097
+ targets = parsedTargets.map(function (parsed) {
92098
+ return parsed.target;
92099
+ }); // Unlike uploadAsset this is not free: every image is charged against the ORGANIZATION's AI budget and a
91526
92100
  // batch orders up to 50 in one call, so the only brake would otherwise be the service's 429. The bar is
91527
- // about the SPEND, not about a write — the asset stays inert until setAssetCell references it — which is
91528
- // why it is asked once for the whole call and names the number of images. A dryRun spends nothing (it
91529
- // only returns the resolved prompt), so it asks for nothing and works without a table on screen.
92101
+ // about the SPEND, not about a write — writing an image into a cell (target) asks its own bar on that table,
92102
+ // exactly like setAssetCell — which is why it is asked once for the whole call and names the number of
92103
+ // images. A dryRun spends nothing (it only returns the resolved prompt), so it asks for nothing and works
92104
+ // without a table on screen.
91530
92105
  if (!(!ctx.autoApprove && !args.dryRun)) {
91531
- _context2.next = 61;
92106
+ _context2.next = 72;
91532
92107
  break;
91533
92108
  }
91534
92109
  host = findGrid(root);
91535
92110
  if (host) {
91536
- _context2.next = 56;
92111
+ _context2.next = 67;
91537
92112
  break;
91538
92113
  }
91539
92114
  return _context2.abrupt("return", {
91540
92115
  error: 'Generating images spends the organization’s AI budget and needs the user’s approval, and the approval bar lives on a table — ' + 'none is on screen. Ask the user to open a table view (or to enable auto-approve in the chat settings), then call again. ' + 'Nothing was generated.'
91541
92116
  });
91542
- case 56:
91543
- _context2.next = 58;
92117
+ case 67:
92118
+ _context2.next = 69;
91544
92119
  return host.requestAgentApproval(imageCount, "generateImageAsset: ".concat(imageCount, " image").concat(imageCount === 1 ? '' : 's', " (AI budget)"), signal);
91545
- case 58:
92120
+ case 69:
91546
92121
  approved = _context2.sent;
91547
92122
  if (approved) {
91548
- _context2.next = 61;
92123
+ _context2.next = 72;
91549
92124
  break;
91550
92125
  }
91551
92126
  return _context2.abrupt("return", {
@@ -91553,137 +92128,228 @@ function createMediaToolset(ctx) {
91553
92128
  applied: false,
91554
92129
  note: 'The user DECLINED — nothing was generated and no budget was spent. Do not retry; ask what to do instead.'
91555
92130
  });
91556
- case 61:
91557
- if (!Array.isArray(args.batch)) {
91558
- _context2.next = 99;
92131
+ case 72:
92132
+ attach = function attach(images) {
92133
+ return attachGeneratedImages(root, images, {
92134
+ autoApprove: ctx.autoApprove,
92135
+ callStartedAt: callStartedAt,
92136
+ signal: signal
92137
+ });
92138
+ };
92139
+ toAttach = function toAttach(result, target) {
92140
+ var _result$fileName2;
92141
+ return {
92142
+ mediaItemId: String(result.mediaItemId),
92143
+ url: typeof result.url === 'string' ? result.url : undefined,
92144
+ fileName: String((_result$fileName2 = result.fileName) !== null && _result$fileName2 !== void 0 ? _result$fileName2 : ''),
92145
+ target: target
92146
+ };
92147
+ };
92148
+ if (batchEntries) {
92149
+ _context2.next = 94;
92150
+ break;
92151
+ }
92152
+ target = targets[0]; // Same rule as the batch: an image that is paid for must still have time to be written before the call's deadline.
92153
+ if (!(target && !args.dryRun && Date.now() > callStartedAt + ATTACH_DEADLINE_MS - ATTACH_RESERVE_MS)) {
92154
+ _context2.next = 78;
91559
92155
  break;
91560
92156
  }
91561
- _startedAt = Date.now();
92157
+ return _context2.abrupt("return", {
92158
+ error: "Nothing was generated: the approval took too long to leave time for writing the image into ".concat(target.keyColumn, " = '").concat(target.keyValue, "'. Call generateImageAsset again.")
92159
+ });
92160
+ case 78:
92161
+ _context2.next = 80;
92162
+ return generateImageAsset(root, args, signal);
92163
+ case 80:
92164
+ one = _context2.sent;
92165
+ if (!(one.error || one.dryRun)) {
92166
+ _context2.next = 83;
92167
+ break;
92168
+ }
92169
+ return _context2.abrupt("return", one);
92170
+ case 83:
92171
+ if (target) {
92172
+ _context2.next = 85;
92173
+ break;
92174
+ }
92175
+ return _context2.abrupt("return", one);
92176
+ case 85:
92177
+ _context2.next = 87;
92178
+ return attach([toAttach(one, target)]);
92179
+ case 87:
92180
+ _yield$attach = _context2.sent;
92181
+ _yield$attach2 = _slicedToArray(_yield$attach, 1);
92182
+ outcome = _yield$attach2[0];
92183
+ receipt = _objectSpread$y({}, one);
92184
+ delete receipt.note;
92185
+ where = "".concat(target.keyColumn, " = '").concat(target.keyValue, "' (").concat(target.column, ")");
92186
+ return _context2.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({}, receipt), {}, {
92187
+ target: target
92188
+ }, outcome), {}, {
92189
+ note: (outcome.attached ? "Generated, uploaded and attached to ".concat(where, ". LOOK at it (open the url, or the tile) before reporting it as done.") : "Generated and uploaded, but NOT attached to ".concat(where, ": ").concat(outcome.attachError, ". ").concat(NOT_ATTACHED_NOTE)) + (outcome.attached && outcome.note ? " ".concat(outcome.note) : '') + shortenedNameNote(one.requestedFileName ? [String(one.fileName)] : [])
92190
+ }));
92191
+ case 94:
92192
+ // BULK: a feature's option set is never ONE image — N swatches would cost N round-trips.
92193
+ _startedAt = Date.now(); // With targets the writes need time before the call's deadline too — the spend bar may already have used much of it.
92194
+ generationBudgetMs = targets.some(Boolean) ? Math.min(TIME_BUDGET_MS, callStartedAt + ATTACH_DEADLINE_MS - ATTACH_RESERVE_MS - _startedAt) : TIME_BUDGET_MS;
91562
92195
  _results = [];
91563
92196
  _remaining = [];
91564
- _iterator2 = _createForOfIteratorHelper$g(args.batch);
91565
- _context2.prev = 66;
92197
+ _iterator2 = _createForOfIteratorHelper$g(batchEntries.entries());
92198
+ _context2.prev = 99;
91566
92199
  _iterator2.s();
91567
- case 68:
92200
+ case 101:
91568
92201
  if ((_step2 = _iterator2.n()).done) {
91569
- _context2.next = 89;
92202
+ _context2.next = 121;
91570
92203
  break;
91571
92204
  }
91572
- raw = _step2.value;
91573
- _entry = raw !== null && raw !== void 0 ? raw : {};
91574
- label = String((_entry$fileName = _entry.fileName) !== null && _entry$fileName !== void 0 ? _entry$fileName : '').trim() || String((_entry$prompt = _entry.prompt) !== null && _entry$prompt !== void 0 ? _entry$prompt : '').slice(0, 60) || '(unnamed)';
91575
- if (!stopBatch(_startedAt, TIME_BUDGET_MS, signal)) {
91576
- _context2.next = 75;
92205
+ _step2$value = _slicedToArray(_step2.value, 2), index = _step2$value[0], _entry = _step2$value[1];
92206
+ label = labelOf(_entry);
92207
+ if (!stopBatch(_startedAt, generationBudgetMs, signal)) {
92208
+ _context2.next = 107;
91577
92209
  break;
91578
92210
  }
91579
92211
  _remaining.push(label);
91580
- return _context2.abrupt("continue", 87);
91581
- case 75:
92212
+ return _context2.abrupt("continue", 119);
92213
+ case 107:
91582
92214
  // One throwing entry must not lose the receipts (and paid usage) of the images already generated.
91583
- one = void 0;
91584
- _context2.prev = 76;
91585
- _context2.next = 79;
92215
+ _one = void 0;
92216
+ _context2.prev = 108;
92217
+ _context2.next = 111;
91586
92218
  return generateImageAsset(root, _objectSpread$y(_objectSpread$y({}, args), {}, {
91587
92219
  batch: undefined
91588
92220
  }, _entry), signal);
91589
- case 79:
91590
- one = _context2.sent;
91591
- _context2.next = 85;
92221
+ case 111:
92222
+ _one = _context2.sent;
92223
+ _context2.next = 117;
91592
92224
  break;
91593
- case 82:
91594
- _context2.prev = 82;
91595
- _context2.t7 = _context2["catch"](76);
91596
- one = {
92225
+ case 114:
92226
+ _context2.prev = 114;
92227
+ _context2.t7 = _context2["catch"](108);
92228
+ _one = {
91597
92229
  error: _context2.t7 instanceof Error ? _context2.t7.message : String(_context2.t7)
91598
92230
  };
91599
- case 85:
91600
- if (one.usage) {
91601
- usage = one.usage;
91602
- delete one.usage;
92231
+ case 117:
92232
+ if (_one.usage) {
92233
+ usage = _one.usage;
92234
+ delete _one.usage;
91603
92235
  }
91604
- _results.push(_objectSpread$y({
91605
- fileName: label
91606
- }, one));
91607
- case 87:
91608
- _context2.next = 68;
92236
+ _results.push({
92237
+ result: _objectSpread$y({
92238
+ fileName: label
92239
+ }, _one),
92240
+ target: targets[index]
92241
+ });
92242
+ case 119:
92243
+ _context2.next = 101;
91609
92244
  break;
91610
- case 89:
91611
- _context2.next = 94;
92245
+ case 121:
92246
+ _context2.next = 126;
91612
92247
  break;
91613
- case 91:
91614
- _context2.prev = 91;
91615
- _context2.t8 = _context2["catch"](66);
92248
+ case 123:
92249
+ _context2.prev = 123;
92250
+ _context2.t8 = _context2["catch"](99);
91616
92251
  _iterator2.e(_context2.t8);
91617
- case 94:
91618
- _context2.prev = 94;
92252
+ case 126:
92253
+ _context2.prev = 126;
91619
92254
  _iterator2.f();
91620
- return _context2.finish(94);
91621
- case 97:
91622
- _failed = _results.filter(function (r) {
91623
- return r.error;
92255
+ return _context2.finish(126);
92256
+ case 129:
92257
+ // Generated first, attached after: ONE approval bar and ONE commit per table instead of one per image.
92258
+ attachable = _results.filter(function (_ref4) {
92259
+ var result = _ref4.result,
92260
+ target = _ref4.target;
92261
+ return target && !result.error && !result.dryRun;
92262
+ });
92263
+ if (!attachable.length) {
92264
+ _context2.next = 136;
92265
+ break;
92266
+ }
92267
+ _context2.next = 133;
92268
+ return attach(attachable.map(function (_ref5) {
92269
+ var result = _ref5.result,
92270
+ target = _ref5.target;
92271
+ return toAttach(result, target);
92272
+ }));
92273
+ case 133:
92274
+ _context2.t9 = _context2.sent;
92275
+ _context2.next = 137;
92276
+ break;
92277
+ case 136:
92278
+ _context2.t9 = [];
92279
+ case 137:
92280
+ outcomes = _context2.t9;
92281
+ attachable.forEach(function (_ref6, position) {
92282
+ var result = _ref6.result,
92283
+ target = _ref6.target;
92284
+ // The entry note says NOT ATTACHED — the outcome replaces it.
92285
+ delete result.note;
92286
+ Object.assign(result, {
92287
+ target: target
92288
+ }, outcomes[position]);
92289
+ });
92290
+ _failed = _results.filter(function (_ref7) {
92291
+ var result = _ref7.result;
92292
+ return result.error;
92293
+ }).map(function (_ref8) {
92294
+ var result = _ref8.result;
92295
+ return result;
91624
92296
  });
92297
+ generated = _results.filter(function (_ref9) {
92298
+ var result = _ref9.result;
92299
+ return !result.error;
92300
+ }).map(function (_ref10) {
92301
+ var result = _ref10.result;
92302
+ return result;
92303
+ });
92304
+ targeted = generated.filter(function (result) {
92305
+ return result.target;
92306
+ });
92307
+ untargeted = generated.filter(function (result) {
92308
+ return !result.target;
92309
+ });
92310
+ attachedCount = targeted.filter(function (result) {
92311
+ return result.attached === true;
92312
+ }).length;
92313
+ allAttached = generated.length > 0 && attachedCount === generated.length;
91625
92314
  return _context2.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({
91626
- generated: _results.filter(function (r) {
91627
- return !r.error;
91628
- }),
92315
+ generated: generated,
91629
92316
  failed: _failed
91630
92317
  }, _remaining.length ? {
91631
92318
  remaining: _remaining
91632
92319
  } : {}), usage ? {
91633
92320
  usage: usage
91634
92321
  } : {}), {}, {
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
92322
+ note: "".concat(generated.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; the entries in 'generated' are generated and uploaded, do not generate them again.") : '') + (targeted.length ? " ".concat(attachedCount, "/").concat(targeted.length, " attached to their rows.") : '') + (attachedCount < targeted.length ? ' The entries with attached:false carry the reason in attachError — they are generated (do not generate them again) but NOT on their rows: fix the cause, then write their mediaItemId with setAssetCell cells.' : '') + (untargeted.length ? ' LOOK at the results before wiring (one contact sheet, not one review per file), then write the entries without a target with setAssetCell cells.' : ' LOOK at the results (one contact sheet, not one review per file).') + (allAttached ? '' : " ".concat(targeted.length ? 'For every entry with attached:false: ' : '').concat(NOT_ATTACHED_NOTE)) + shortenedNameNote(generated.flatMap(function (result) {
92323
+ return result.requestedFileName ? [String(result.fileName)] : [];
92324
+ })),
92325
+ attached: allAttached
91637
92326
  }));
91638
- case 99:
91639
- return _context2.abrupt("return", generateImageAsset(root, args, signal));
91640
- case 100:
92327
+ case 146:
91641
92328
  return _context2.abrupt("return", publishCatalogTestManifest(root, args, signal));
91642
- case 101:
92329
+ case 147:
91643
92330
  return _context2.abrupt("return", getAssetUrls(root, args, signal));
91644
- case 102:
91645
- // An unrecognized non-empty mode errors instead of silently APPENDING (the wrong write) — for the batch entries too.
91646
- // Canonical names live in the same map as their synonyms, so the lookup is already typed.
91647
- MODE_SYNONYMS = {
91648
- append: 'append',
91649
- replace: 'replace',
91650
- remove: 'remove',
91651
- add: 'append',
91652
- overwrite: 'replace',
91653
- set: 'replace',
91654
- "delete": 'remove'
91655
- };
91656
- parseAssetMode = function parseAssetMode(raw) {
91657
- var value = String(raw !== null && raw !== void 0 ? raw : '').trim().toLowerCase();
91658
- if (!value) return {};
91659
- var mapped = MODE_SYNONYMS[value];
91660
- return mapped ? {
91661
- mode: mapped
91662
- } : {
91663
- invalid: String(raw)
91664
- };
91665
- }; // BULK: 'cells' turns N writes into ONE round-trip; entries inherit the top-level grid/column/mode.
92331
+ case 148:
91666
92332
  if (!Array.isArray(args.cells)) {
91667
- _context2.next = 120;
92333
+ _context2.next = 164;
91668
92334
  break;
91669
92335
  }
91670
92336
  if (args.cells.length) {
91671
- _context2.next = 107;
92337
+ _context2.next = 151;
91672
92338
  break;
91673
92339
  }
91674
92340
  return _context2.abrupt("return", {
91675
92341
  error: "'cells' is empty — pass at least one {keyValue, mediaItemId} entry."
91676
92342
  });
91677
- case 107:
92343
+ case 151:
91678
92344
  topMode = parseAssetMode(args.mode);
91679
92345
  if (!topMode.invalid) {
91680
- _context2.next = 110;
92346
+ _context2.next = 154;
91681
92347
  break;
91682
92348
  }
91683
92349
  return _context2.abrupt("return", {
91684
92350
  error: "mode must be 'append' (default), 'replace' or 'remove' \u2014 got '".concat(topMode.invalid, "'.")
91685
92351
  });
91686
- case 110:
92352
+ case 154:
91687
92353
  badEntryModes = args.cells.filter(function (cell) {
91688
92354
  return parseAssetMode(cell === null || cell === void 0 ? void 0 : cell.mode).invalid;
91689
92355
  }).map(function (cell) {
@@ -91691,14 +92357,14 @@ function createMediaToolset(ctx) {
91691
92357
  return "".concat((_cell$keyValue = cell === null || cell === void 0 ? void 0 : cell.keyValue) !== null && _cell$keyValue !== void 0 ? _cell$keyValue : '(missing keyValue)', ": '").concat(cell === null || cell === void 0 ? void 0 : cell.mode, "'");
91692
92358
  });
91693
92359
  if (!badEntryModes.length) {
91694
- _context2.next = 113;
92360
+ _context2.next = 157;
91695
92361
  break;
91696
92362
  }
91697
92363
  return _context2.abrupt("return", {
91698
92364
  error: "mode must be 'append' (default), 'replace' or 'remove' \u2014 invalid for: ".concat(badEntryModes.join(', '), ". Nothing was written.")
91699
92365
  });
91700
- case 113:
91701
- batchEntries = args.cells.map(function (raw) {
92366
+ case 157:
92367
+ _batchEntries = args.cells.map(function (raw) {
91702
92368
  var _cell$keyValue2, _cell$mediaItemId;
91703
92369
  var cell = raw !== null && raw !== void 0 ? raw : {};
91704
92370
  return {
@@ -91711,53 +92377,53 @@ function createMediaToolset(ctx) {
91711
92377
  mode: parseAssetMode(cell.mode).mode
91712
92378
  };
91713
92379
  }); // Validate ids BEFORE the approval bar — never ask the user to approve a batch that then fails validation.
91714
- invalidIds = batchEntries.filter(function (e) {
92380
+ invalidIds = _batchEntries.filter(function (e) {
91715
92381
  return !/^[A-Za-z0-9_-]{10,64}$/.test(e.mediaItemId);
91716
92382
  }).map(function (e) {
91717
92383
  return e.keyValue || '(missing keyValue)';
91718
92384
  });
91719
92385
  if (!invalidIds.length) {
91720
- _context2.next = 117;
92386
+ _context2.next = 161;
91721
92387
  break;
91722
92388
  }
91723
92389
  return _context2.abrupt("return", {
91724
92390
  error: "mediaItemId must be a media item _id (uploadAsset returns it) \u2014 invalid for: ".concat(invalidIds.join(', '), ". Nothing was written.")
91725
92391
  });
91726
- case 117:
91727
- _context2.next = 119;
91728
- return writeAssetCellsBatch(root, args.grid, String((_args$keyColumn = args.keyColumn) !== null && _args$keyColumn !== void 0 ? _args$keyColumn : ''), String((_args$column = args.column) !== null && _args$column !== void 0 ? _args$column : ''), (_topMode$mode = topMode.mode) !== null && _topMode$mode !== void 0 ? _topMode$mode : 'append', batchEntries, ctx.autoApprove ? undefined : function (entry, stageable) {
92392
+ case 161:
92393
+ _context2.next = 163;
92394
+ return writeAssetCellsBatch(root, args.grid, String((_args$keyColumn = args.keyColumn) !== null && _args$keyColumn !== void 0 ? _args$keyColumn : ''), String((_args$column = args.column) !== null && _args$column !== void 0 ? _args$column : ''), (_topMode$mode = topMode.mode) !== null && _topMode$mode !== void 0 ? _topMode$mode : 'append', _batchEntries, ctx.autoApprove ? undefined : function (entry, stageable) {
91729
92395
  return entry.requestAgentApproval(stageable, "setAssetCell: ".concat(stageable, " cells"), signal);
91730
92396
  }, signal);
91731
- case 119:
92397
+ case 163:
91732
92398
  return _context2.abrupt("return", _context2.sent);
91733
- case 120:
92399
+ case 164:
91734
92400
  mediaItemId = String((_args$mediaItemId = args.mediaItemId) !== null && _args$mediaItemId !== void 0 ? _args$mediaItemId : '').trim();
91735
92401
  parsedMode = parseAssetMode(args.mode);
91736
92402
  if (!parsedMode.invalid) {
91737
- _context2.next = 124;
92403
+ _context2.next = 168;
91738
92404
  break;
91739
92405
  }
91740
92406
  return _context2.abrupt("return", {
91741
92407
  error: "mode must be 'append' (default), 'replace' or 'remove' \u2014 got '".concat(args.mode, "'.")
91742
92408
  });
91743
- case 124:
92409
+ case 168:
91744
92410
  mode = parsedMode.mode; // Media item _ids are nanoids; legacy items may carry 24-hex ObjectIds — accept both.
91745
92411
  if (/^[A-Za-z0-9_-]{10,64}$/.test(mediaItemId)) {
91746
- _context2.next = 127;
92412
+ _context2.next = 171;
91747
92413
  break;
91748
92414
  }
91749
92415
  return _context2.abrupt("return", {
91750
92416
  error: 'mediaItemId must be a media item _id — uploadAsset returns it.'
91751
92417
  });
91752
- case 127:
92418
+ case 171:
91753
92419
  if (!(!args.keyColumn || args.keyValue === undefined || !args.column)) {
91754
- _context2.next = 129;
92420
+ _context2.next = 173;
91755
92421
  break;
91756
92422
  }
91757
92423
  return _context2.abrupt("return", {
91758
92424
  error: 'keyColumn, keyValue and column are required (the row is addressed by keyColumn=keyValue).'
91759
92425
  });
91760
- case 129:
92426
+ case 173:
91761
92427
  return _context2.abrupt("return", writeAssetCell(root, {
91762
92428
  grid: args.grid,
91763
92429
  keyColumn: String(args.keyColumn),
@@ -91772,122 +92438,122 @@ function createMediaToolset(ctx) {
91772
92438
  mode: mode !== null && mode !== void 0 ? mode : 'append',
91773
92439
  approve: agentApprove("setAssetCell: ".concat(args.column, " ").concat(mode !== null && mode !== void 0 ? mode : 'append', " ").concat(mediaItemId), signal)
91774
92440
  }));
91775
- case 130:
92441
+ case 174:
91776
92442
  if (!args.styleUrl) {
91777
- _context2.next = 148;
92443
+ _context2.next = 192;
91778
92444
  break;
91779
92445
  }
91780
- _context2.prev = 131;
91781
- _context2.next = 134;
92446
+ _context2.prev = 175;
92447
+ _context2.next = 178;
91782
92448
  return fetch(String(args.styleUrl), {
91783
92449
  signal: signal
91784
92450
  });
91785
- case 134:
92451
+ case 178:
91786
92452
  response = _context2.sent;
91787
92453
  if (response.ok) {
91788
- _context2.next = 137;
92454
+ _context2.next = 181;
91789
92455
  break;
91790
92456
  }
91791
92457
  return _context2.abrupt("return", {
91792
92458
  error: "styleUrl fetch failed (".concat(response.status, ") \u2014 is the URL a reachable style-config JSON (media item)?")
91793
92459
  });
91794
- case 137:
91795
- _context2.next = 139;
92460
+ case 181:
92461
+ _context2.next = 183;
91796
92462
  return response.json();
91797
- case 139:
92463
+ case 183:
91798
92464
  fetched = _context2.sent;
91799
92465
  if (!(!fetched || _typeof(fetched) !== 'object' || Array.isArray(fetched))) {
91800
- _context2.next = 142;
92466
+ _context2.next = 186;
91801
92467
  break;
91802
92468
  }
91803
92469
  return _context2.abrupt("return", {
91804
92470
  error: 'styleUrl JSON is not a style config — expected an object like {parts: {...}, cushionMode: "..."}.'
91805
92471
  });
91806
- case 142:
92472
+ case 186:
91807
92473
  storedStyle = fetched;
91808
- _context2.next = 148;
92474
+ _context2.next = 192;
91809
92475
  break;
91810
- case 145:
91811
- _context2.prev = 145;
91812
- _context2.t9 = _context2["catch"](131);
92476
+ case 189:
92477
+ _context2.prev = 189;
92478
+ _context2.t10 = _context2["catch"](175);
91813
92479
  return _context2.abrupt("return", {
91814
- error: "styleUrl fetch failed (".concat(_context2.t9 instanceof Error ? _context2.t9.message : String(_context2.t9), ") \u2014 is the URL reachable from the browser (CORS)?")
92480
+ error: "styleUrl fetch failed (".concat(_context2.t10 instanceof Error ? _context2.t10.message : String(_context2.t10), ") \u2014 is the URL reachable from the browser (CORS)?")
91815
92481
  });
91816
- case 148:
92482
+ case 192:
91817
92483
  if (!args.recipeUrl) {
91818
- _context2.next = 168;
92484
+ _context2.next = 212;
91819
92485
  break;
91820
92486
  }
91821
- _context2.prev = 149;
91822
- _context2.next = 152;
92487
+ _context2.prev = 193;
92488
+ _context2.next = 196;
91823
92489
  return fetch(String(args.recipeUrl), {
91824
92490
  signal: signal
91825
92491
  });
91826
- case 152:
92492
+ case 196:
91827
92493
  _response = _context2.sent;
91828
92494
  if (_response.ok) {
91829
- _context2.next = 155;
92495
+ _context2.next = 199;
91830
92496
  break;
91831
92497
  }
91832
92498
  return _context2.abrupt("return", {
91833
92499
  error: "recipeUrl fetch failed (".concat(_response.status, ") \u2014 is the URL a reachable recipe JSON (media item)?")
91834
92500
  });
91835
- case 155:
91836
- _context2.next = 157;
92501
+ case 199:
92502
+ _context2.next = 201;
91837
92503
  return _response.json();
91838
- case 157:
92504
+ case 201:
91839
92505
  _fetched = _context2.sent;
91840
92506
  if (isArticleSvgRecipe(_fetched)) {
91841
- _context2.next = 160;
92507
+ _context2.next = 204;
91842
92508
  break;
91843
92509
  }
91844
92510
  return _context2.abrupt("return", {
91845
92511
  error: 'recipeUrl JSON is not a recipe — expected {description?, spec: {…}, style?}.'
91846
92512
  });
91847
- case 160:
92513
+ case 204:
91848
92514
  recipe = _fetched;
91849
- _context2.next = 166;
92515
+ _context2.next = 210;
91850
92516
  break;
91851
- case 163:
91852
- _context2.prev = 163;
91853
- _context2.t10 = _context2["catch"](149);
92517
+ case 207:
92518
+ _context2.prev = 207;
92519
+ _context2.t11 = _context2["catch"](193);
91854
92520
  return _context2.abrupt("return", {
91855
- error: "recipeUrl fetch failed (".concat(_context2.t10 instanceof Error ? _context2.t10.message : String(_context2.t10), ") \u2014 is the URL reachable from the browser (CORS)?")
92521
+ error: "recipeUrl fetch failed (".concat(_context2.t11 instanceof Error ? _context2.t11.message : String(_context2.t11), ") \u2014 is the URL reachable from the browser (CORS)?")
91856
92522
  });
91857
- case 166:
91858
- _context2.next = 178;
92523
+ case 210:
92524
+ _context2.next = 222;
91859
92525
  break;
91860
- case 168:
92526
+ case 212:
91861
92527
  if (!(typeof args.recipe === 'string')) {
91862
- _context2.next = 174;
92528
+ _context2.next = 218;
91863
92529
  break;
91864
92530
  }
91865
92531
  recipe = BUILT_IN_RECIPES[args.recipe];
91866
92532
  if (recipe) {
91867
- _context2.next = 172;
92533
+ _context2.next = 216;
91868
92534
  break;
91869
92535
  }
91870
92536
  return _context2.abrupt("return", {
91871
92537
  error: "Unknown built-in recipe '".concat(args.recipe, "' \u2014 available: ").concat(Object.keys(BUILT_IN_RECIPES).join(', '), ".")
91872
92538
  });
91873
- case 172:
91874
- _context2.next = 178;
92539
+ case 216:
92540
+ _context2.next = 222;
91875
92541
  break;
91876
- case 174:
92542
+ case 218:
91877
92543
  if (!(args.recipe !== undefined)) {
91878
- _context2.next = 178;
92544
+ _context2.next = 222;
91879
92545
  break;
91880
92546
  }
91881
92547
  if (isArticleSvgRecipe(args.recipe)) {
91882
- _context2.next = 177;
92548
+ _context2.next = 221;
91883
92549
  break;
91884
92550
  }
91885
92551
  return _context2.abrupt("return", {
91886
92552
  error: 'recipe must be a built-in name or {description?, spec: {…}, style?}.'
91887
92553
  });
91888
- case 177:
92554
+ case 221:
91889
92555
  recipe = args.recipe;
91890
- case 178:
92556
+ case 222:
91891
92557
  if (recipe) {
91892
92558
  active = recipe;
91893
92559
  if (active.style && args.style === undefined && !storedStyle) args.style = active.style;
@@ -91903,97 +92569,99 @@ function createMediaToolset(ctx) {
91903
92569
  }
91904
92570
  }
91905
92571
  if (!Array.isArray(args.batch)) {
91906
- _context2.next = 183;
92572
+ _context2.next = 227;
91907
92573
  break;
91908
92574
  }
91909
- _context2.next = 182;
92575
+ _context2.next = 226;
91910
92576
  return generateArticleSvgBatch(root, args, args.batch, storedStyle, signal);
91911
- case 182:
92577
+ case 226:
91912
92578
  return _context2.abrupt("return", _context2.sent);
91913
- case 183:
91914
- _context2.prev = 183;
92579
+ case 227:
92580
+ _context2.prev = 227;
91915
92581
  spec = _objectSpread$y({}, args);
91916
92582
  if (storedStyle) {
91917
92583
  inline = _typeof(args.style) === 'object' && args.style ? args.style : undefined;
91918
92584
  spec.style = mergeArticleSvgStyles(storedStyle, inline);
91919
92585
  }
91920
- generated = buildArticleTopViewSvg(spec);
91921
- _context2.next = 192;
92586
+ _generated = buildArticleTopViewSvg(spec);
92587
+ _context2.next = 236;
91922
92588
  break;
91923
- case 189:
91924
- _context2.prev = 189;
91925
- _context2.t11 = _context2["catch"](183);
92589
+ case 233:
92590
+ _context2.prev = 233;
92591
+ _context2.t12 = _context2["catch"](227);
91926
92592
  return _context2.abrupt("return", {
91927
- error: _context2.t11 instanceof Error ? _context2.t11.message : String(_context2.t11)
92593
+ error: _context2.t12 instanceof Error ? _context2.t12.message : String(_context2.t12)
91928
92594
  });
91929
- case 192:
92595
+ case 236:
91930
92596
  typeNo = args.typeNo === undefined ? undefined : String(args.typeNo); // 'jpg' = rasterized article-list picture (white background); 'svg' = planner top view.
91931
92597
  format = String((_args$format = args.format) !== null && _args$format !== void 0 ? _args$format : 'svg').trim().toLowerCase();
91932
92598
  if (['svg', 'jpg'].includes(format)) {
91933
- _context2.next = 196;
92599
+ _context2.next = 240;
91934
92600
  break;
91935
92601
  }
91936
92602
  return _context2.abrupt("return", {
91937
92603
  error: "format must be 'svg' (planner top view) or 'jpg' (article-list picture) \u2014 got '".concat(args.format, "'.")
91938
92604
  });
91939
- case 196:
92605
+ case 240:
91940
92606
  extension = format === 'jpg' ? '.jpg' : '.svg';
91941
92607
  rawName = String((_args$fileName = args.fileName) !== null && _args$fileName !== void 0 ? _args$fileName : typeNo ? "top-".concat(typeNo).concat(extension) : "top-view".concat(extension));
91942
- _fileName = rawName.toLowerCase().endsWith(extension) ? rawName : "".concat(rawName.replace(/\.(svg|jpe?g)$/i, '')).concat(extension);
91943
- _context2.prev = 199;
92608
+ requestedFileName = rawName.toLowerCase().endsWith(extension) ? rawName : "".concat(rawName.replace(/\.(svg|jpe?g)$/i, '')).concat(extension); // Fitted before the upload: an IDM asset cell takes the media item's own name (at most 40 characters).
92609
+ _fileName = fitMediaName(requestedFileName);
92610
+ nameNote = shortenedNameNote(_fileName !== requestedFileName ? [_fileName] : []);
92611
+ _context2.prev = 245;
91944
92612
  if (!(format === 'jpg')) {
91945
- _context2.next = 211;
92613
+ _context2.next = 257;
91946
92614
  break;
91947
92615
  }
91948
- _context2.t13 = File;
91949
- _context2.next = 204;
91950
- return svgToJpegBlob(generated.svg, Math.max(64, Math.min(4096, Number(args.jpgSizePx) || 1024)));
91951
- case 204:
91952
- _context2.t14 = _context2.sent;
91953
- _context2.t15 = [_context2.t14];
91954
- _context2.t16 = _fileName;
91955
- _context2.t17 = {
92616
+ _context2.t14 = File;
92617
+ _context2.next = 250;
92618
+ return svgToJpegBlob(_generated.svg, Math.max(64, Math.min(4096, Number(args.jpgSizePx) || 1024)));
92619
+ case 250:
92620
+ _context2.t15 = _context2.sent;
92621
+ _context2.t16 = [_context2.t15];
92622
+ _context2.t17 = _fileName;
92623
+ _context2.t18 = {
91956
92624
  type: 'image/jpeg'
91957
92625
  };
91958
- _context2.t12 = new _context2.t13(_context2.t15, _context2.t16, _context2.t17);
91959
- _context2.next = 212;
92626
+ _context2.t13 = new _context2.t14(_context2.t16, _context2.t17, _context2.t18);
92627
+ _context2.next = 258;
91960
92628
  break;
91961
- case 211:
91962
- _context2.t12 = new File([generated.svg], _fileName, {
92629
+ case 257:
92630
+ _context2.t13 = new File([_generated.svg], _fileName, {
91963
92631
  type: 'image/svg+xml'
91964
92632
  });
91965
- case 212:
91966
- file = _context2.t12;
91967
- _context2.next = 215;
92633
+ case 258:
92634
+ file = _context2.t13;
92635
+ _context2.next = 261;
91968
92636
  return uploadToMediaService(root, file, _fileName, undefined, signal);
91969
- case 215:
92637
+ case 261:
91970
92638
  uploaded = _context2.sent;
91971
- _context2.next = 221;
92639
+ _context2.next = 267;
91972
92640
  break;
91973
- case 218:
91974
- _context2.prev = 218;
91975
- _context2.t18 = _context2["catch"](199);
92641
+ case 264:
92642
+ _context2.prev = 264;
92643
+ _context2.t19 = _context2["catch"](245);
91976
92644
  return _context2.abrupt("return", {
91977
- error: _context2.t18 instanceof Error ? _context2.t18.message : String(_context2.t18)
92645
+ error: _context2.t19 instanceof Error ? _context2.t19.message : String(_context2.t19)
91978
92646
  });
91979
- case 221:
92647
+ case 267:
91980
92648
  // Canvas/list pictures belong in 'images'; the planner top view in 'svgs'.
91981
92649
  attachColumn = args.column ? String(args.column) : format === 'jpg' ? 'images' : 'svgs';
91982
92650
  if (!(!typeNo || args.attach === false)) {
91983
- _context2.next = 224;
92651
+ _context2.next = 270;
91984
92652
  break;
91985
92653
  }
91986
92654
  return _context2.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({}, uploaded), format === 'svg' && args.returnSvg !== false ? {
91987
- svg: generated.svg
92655
+ svg: _generated.svg
91988
92656
  } : {}), {}, {
91989
- canvasCm: generated.canvasCm,
91990
- connectors: generated.connectors,
91991
- warnings: generated.warnings,
92657
+ canvasCm: _generated.canvasCm,
92658
+ connectors: _generated.connectors,
92659
+ warnings: _generated.warnings,
91992
92660
  attached: false,
91993
- note: "".concat(format.toUpperCase(), " generated + uploaded but NOT attached \u2014 setAssetCell it onto an item's ").concat(attachColumn, " column, or pass typeNo to attach directly.")
92661
+ note: "".concat(format.toUpperCase(), " generated + uploaded but NOT attached \u2014 setAssetCell it onto an item's ").concat(attachColumn, " column, or pass typeNo to attach directly.").concat(nameNote)
91994
92662
  }));
91995
- case 224:
91996
- _context2.next = 226;
92663
+ case 270:
92664
+ _context2.next = 272;
91997
92665
  return writeAssetCell(root, {
91998
92666
  grid: (_args$grid = args.grid) !== null && _args$grid !== void 0 ? _args$grid : 'items',
91999
92667
  keyColumn: 'typeNo',
@@ -92008,36 +92676,36 @@ function createMediaToolset(ctx) {
92008
92676
  mode: args.mode === 'replace' || args.mode === 'remove' ? args.mode : 'append',
92009
92677
  approve: agentApprove("generateArticleSvg \u2192 ".concat(typeNo, " (").concat(attachColumn, ")"), signal)
92010
92678
  });
92011
- case 226:
92679
+ case 272:
92012
92680
  attachResult = _context2.sent;
92013
92681
  if (!(attachResult.error || attachResult.applied === false)) {
92014
- _context2.next = 229;
92682
+ _context2.next = 275;
92015
92683
  break;
92016
92684
  }
92017
92685
  return _context2.abrupt("return", _objectSpread$y(_objectSpread$y(_objectSpread$y({}, uploaded), {}, {
92018
92686
  attached: false
92019
92687
  }, attachResult), {}, {
92020
- note: "".concat(format.toUpperCase(), " uploaded, but attaching to the item failed \u2014 the asset exists; fix the attach and setAssetCell it.")
92688
+ note: "".concat(format.toUpperCase(), " uploaded, but attaching to the item failed \u2014 the asset exists; fix the attach and setAssetCell it.").concat(nameNote)
92021
92689
  }));
92022
- case 229:
92690
+ case 275:
92023
92691
  return _context2.abrupt("return", {
92024
92692
  mediaItemId: uploaded.mediaItemId,
92025
92693
  url: uploaded.url,
92026
- canvasCm: generated.canvasCm,
92027
- connectors: generated.connectors,
92028
- warnings: generated.warnings,
92694
+ canvasCm: _generated.canvasCm,
92695
+ connectors: _generated.connectors,
92696
+ warnings: _generated.warnings,
92029
92697
  attached: true,
92030
- note: format === 'svg' ? "SVG attached to the item's svgs list. svgs[0] is the planner's TOP VIEW — check order if the item had SVGs before. Verify: select the article, then getMediaInfo/getDockingInfo." : "JPG attached to the item's ".concat(attachColumn, " list (article-list picture). For a serie-uniform scale, reuse canvasCm=").concat((_generated$canvasCm = generated.canvasCm) !== null && _generated$canvasCm !== void 0 ? _generated$canvasCm : '—', " on every article of the serie.")
92698
+ note: (format === 'svg' ? "SVG attached to the item's svgs list. svgs[0] is the planner's TOP VIEW — check order if the item had SVGs before. Verify: select the article, then getMediaInfo/getDockingInfo." : "JPG attached to the item's ".concat(attachColumn, " list (article-list picture). For a serie-uniform scale, reuse canvasCm=").concat((_generated$canvasCm = _generated.canvasCm) !== null && _generated$canvasCm !== void 0 ? _generated$canvasCm : '—', " on every article of the serie.")) + nameNote
92031
92699
  });
92032
- case 230:
92700
+ case 276:
92033
92701
  throw new Error("Unknown media tool: ".concat(name));
92034
- case 231:
92702
+ case 277:
92035
92703
  case "end":
92036
92704
  return _context2.stop();
92037
92705
  }
92038
- }, _callee2, null, [[14, 35, 38, 41], [66, 91, 94, 97], [76, 82], [131, 145], [149, 163], [183, 189], [199, 218]]);
92706
+ }, _callee2, null, [[13, 34, 37, 40], [99, 123, 126, 129], [108, 114], [175, 189], [193, 207], [227, 233], [245, 264]]);
92039
92707
  }));
92040
- function dispatch(_x48, _x49, _x50) {
92708
+ function dispatch(_x55, _x56, _x57) {
92041
92709
  return _dispatch.apply(this, arguments);
92042
92710
  }
92043
92711
  return dispatch;
@@ -95996,14 +96664,32 @@ function isPackageSelectableAsCollectionMember(packageData, organizationId, pare
95996
96664
  return publishedOrInherited && !(packageData !== null && packageData !== void 0 && packageData.isApi);
95997
96665
  }
95998
96666
 
96667
+ /** The setting of a collection member that decides whether the publish adds new series to it. */
96668
+
96669
+ /**
96670
+ * Whether the publish adds every new serie of the live catalog to a member of a supplier collection. A member
96671
+ * without the setting does, as every member did before the setting existed.
96672
+ */
96673
+ function addsNewSeriesAutomatically(member) {
96674
+ return (member === null || member === void 0 ? void 0 : member.autoIncludeNewSeries) !== false;
96675
+ }
96676
+
96677
+ /**
96678
+ * Whether the user chooses the series of a member: always in a regular collection, in a supplier collection only
96679
+ * for a member the publish does not add new series to - otherwise the publish lists every serie of the live catalog.
96680
+ */
96681
+ function isSerieSelectionByHand(isSupplierCollection, member) {
96682
+ return !isSupplierCollection || !addsNewSeriesAutomatically(member);
96683
+ }
96684
+
95999
96685
  function CollectionMembers(_ref) {
96000
96686
  var collection = _ref.collection,
96001
96687
  organizationId = _ref.organizationId,
96002
96688
  apiConfig = _ref.apiConfig,
96003
96689
  agentBoundParent = _ref.agentBoundParent;
96004
- var _useTranslation = useTranslation();
96005
- _useTranslation.t;
96006
- var i18n = _useTranslation.i18n;
96690
+ var _useTranslation = useTranslation(),
96691
+ t = _useTranslation.t,
96692
+ i18n = _useTranslation.i18n;
96007
96693
  var root = useStore();
96008
96694
  var applicationData = useMemo(function () {
96009
96695
  return {
@@ -96057,15 +96743,30 @@ function CollectionMembers(_ref) {
96057
96743
  },
96058
96744
  additionalFields: ['enricherPackageName'],
96059
96745
  isDictionary: false
96060
- }, {
96746
+ }].concat(_toConsumableArray(collection.isSupplierCollection ? [{
96747
+ headerName: 'backoffice.idmCatalogEditor.collectionmembers.label.autoIncludeNewSeries',
96748
+ headerTooltip: t('backoffice.idmCatalogEditor.collectionmembers.tooltip.autoIncludeNewSeries'),
96749
+ field: 'autoIncludeNewSeries',
96750
+ cellDataType: 'boolean',
96751
+ editable: true,
96752
+ defaultValue: true,
96753
+ // a member without the setting adds new series, so the filter has to match it like the display
96754
+ customParams: {
96755
+ missingValue: true
96756
+ },
96757
+ valueGetter: function valueGetter(_ref2) {
96758
+ var data = _ref2.data;
96759
+ return addsNewSeriesAutomatically(data);
96760
+ }
96761
+ }] : []), [{
96061
96762
  field: 'serieNos',
96062
96763
  headerName: 'backoffice.idmCatalogEditor.collectionmembers.label.serieNos',
96063
96764
  cellDataType: 'lookup',
96064
- // the series of a supplier collection are maintained by the publish
96065
- editable: function editable(_ref2) {
96066
- var data = _ref2.data,
96067
- context = _ref2.context;
96068
- return !collection.isSupplierCollection && ((context === null || context === void 0 ? void 0 : context.isPasting) || !!data.enricherPackageId);
96765
+ // the publish maintains the series of a supplier collection member that takes in new series
96766
+ editable: function editable(_ref3) {
96767
+ var data = _ref3.data,
96768
+ context = _ref3.context;
96769
+ return isSerieSelectionByHand(collection.isSupplierCollection, data) && ((context === null || context === void 0 ? void 0 : context.isPasting) || !!data.enricherPackageId);
96069
96770
  },
96070
96771
  customParams: {
96071
96772
  nameField: 'serieNosDisplayTexts',
@@ -96096,7 +96797,7 @@ function CollectionMembers(_ref) {
96096
96797
  field: '_id',
96097
96798
  editable: false,
96098
96799
  cellDataType: 'objectId'
96099
- }]
96800
+ }])
96100
96801
  };
96101
96802
  }, [apiInterface, i18n.language, organizationId, collection.isSupplierCollection]);
96102
96803
  return /*#__PURE__*/jsx(Spreadsheet, {