@atlaskit/editor-synced-block-provider 6.3.2 → 6.4.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 6.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 6.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`c5fc2c5fb9fd1`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c5fc2c5fb9fd1) -
14
+ Add discardUnpublishedSyncBlocks action to clean up orphaned synced blocks when user cancels
15
+ editing. Fetches block statuses from the backend on editor init and deletes all blocks with
16
+ 'unpublished' status on cancel.
17
+
3
18
  ## 6.3.2
4
19
 
5
20
  ### Patch Changes
@@ -54,7 +54,7 @@ var mapErrorResponseCode = function mapErrorResponseCode(errorCode) {
54
54
  case 'NOT_FOUND':
55
55
  return _types.SyncBlockError.NotFound;
56
56
  case 'EntityNotFound':
57
- return (0, _platformFeatureFlags.fg)('platform_synced_block_patch_9') ? _types.SyncBlockError.EntityNotFound : _types.SyncBlockError.Errored;
57
+ return (0, _platformFeatureFlags.fg)('platform_synced_block_patch_10') ? _types.SyncBlockError.EntityNotFound : _types.SyncBlockError.Errored;
58
58
  case 'INVALID_REQUEST':
59
59
  return _types.SyncBlockError.InvalidRequest;
60
60
  case 'CONFLICT':
@@ -1271,7 +1271,7 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
1271
1271
  value: function () {
1272
1272
  var _writeDataBatch = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee10(data) {
1273
1273
  var _this3 = this;
1274
- var stepVersion, blockAriToResourceIdMap, blocks, response, results, successResourceIds, _iterator6, _step6, block, errorResourceIds, _iterator7, _step7, _loop2;
1274
+ var stepVersion, blockAriToResourceIdMap, blocks, response, results, successBlocks, _iterator6, _step6, block, successBlock, errorResourceIds, _iterator7, _step7, _loop2;
1275
1275
  return _regenerator.default.wrap(function _callee10$(_context12) {
1276
1276
  while (1) switch (_context12.prev = _context12.next) {
1277
1277
  case 0:
@@ -1321,17 +1321,20 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
1321
1321
  response = _context12.sent;
1322
1322
  results = []; // Process successful updates
1323
1323
  if (response.success) {
1324
- successResourceIds = new Set(response.success.map(function (block) {
1325
- return blockAriToResourceIdMap.get(block.blockAri);
1324
+ successBlocks = new Map(response.success.map(function (block) {
1325
+ return [blockAriToResourceIdMap.get(block.blockAri), block];
1326
1326
  }));
1327
1327
  _iterator6 = _createForOfIteratorHelper(data);
1328
1328
  try {
1329
1329
  for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1330
1330
  block = _step6.value;
1331
- if (successResourceIds.has(block.resourceId)) {
1332
- results.push({
1331
+ successBlock = successBlocks.get(block.resourceId);
1332
+ if (successBlock) {
1333
+ results.push(_objectSpread({
1333
1334
  resourceId: block.resourceId
1334
- });
1335
+ }, (0, _platformFeatureFlags.fg)('platform_synced_block_patch_10') && {
1336
+ status: successBlock.status
1337
+ }));
1335
1338
  }
1336
1339
  }
1337
1340
  } catch (err) {
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.SourceSyncBlockStoreManager = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
10
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
11
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
12
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
@@ -18,6 +19,9 @@ var _types = require("../common/types");
18
19
  var _errorHandling = require("../utils/errorHandling");
19
20
  var _experienceTracking = require("../utils/experienceTracking");
20
21
  var _utils = require("../utils/utils");
22
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
23
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
24
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
21
25
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
22
26
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
23
27
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
@@ -108,6 +112,8 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
108
112
  isDirty: isDirty,
109
113
  // if the change is from remote, it's not dirty
110
114
  contentFragment: syncBlockNode.content
115
+ }, (0, _platformFeatureFlags.fg)('platform_synced_block_patch_10') && {
116
+ status: cachedBlock === null || cachedBlock === void 0 ? void 0 : cachedBlock.status
111
117
  }));
112
118
  } else {
113
119
  var _syncBlockData = (0, _utils.convertSyncBlockPMNodeToSyncBlockData)(syncBlockNode);
@@ -116,6 +122,8 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
116
122
  }
117
123
  this.syncBlockCache.set(resourceId, _objectSpread(_objectSpread({}, _syncBlockData), {}, {
118
124
  isDirty: true
125
+ }, (0, _platformFeatureFlags.fg)('platform_synced_block_patch_10') && {
126
+ status: cachedBlock === null || cachedBlock === void 0 ? void 0 : cachedBlock.status
119
127
  }));
120
128
  }
121
129
  return true;
@@ -214,6 +222,13 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
214
222
  writeResults.forEach(function (result) {
215
223
  if (result.resourceId && !result.error) {
216
224
  var _this2$fireAnalyticsE;
225
+ // Update cache with the status returned from the backend
226
+ if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_10')) {
227
+ var cachedData = _this2.syncBlockCache.get(result.resourceId);
228
+ if (cachedData && result.status) {
229
+ cachedData.status = result.status;
230
+ }
231
+ }
217
232
  (_this2$fireAnalyticsE = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE === void 0 || _this2$fireAnalyticsE.call(_this2, (0, _errorHandling.updateSuccessPayload)(result.resourceId, false));
218
233
  }
219
234
  });
@@ -367,6 +382,14 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
367
382
  if ((0, _platformFeatureFlags.fg)('platform_synced_block_update_refactor')) {
368
383
  // add the node to the cache
369
384
  this.updateSyncBlockData(node, false);
385
+
386
+ // Mark the block as unpublished in the cache so it can be cleaned up on cancel
387
+ if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_10')) {
388
+ var cached = this.syncBlockCache.get(resourceId);
389
+ if (cached) {
390
+ cached.status = 'unpublished';
391
+ }
392
+ }
370
393
  }
371
394
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
372
395
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
@@ -550,6 +573,123 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
550
573
  }
551
574
 
552
575
  /**
576
+ * Fetches the current status of all source sync blocks in the cache from the backend
577
+ * and updates the cache entries with the fetched status.
578
+ * This is called on editor init so we know which blocks are 'unpublished' vs 'active'.
579
+ */
580
+ }, {
581
+ key: "fetchAndCacheStatuses",
582
+ value: (function () {
583
+ var _fetchAndCacheStatuses = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
584
+ var _this6 = this;
585
+ var sourceToReferenceMap, syncBlockNodes, results, _iterator, _step, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
586
+ return _regenerator.default.wrap(function _callee4$(_context4) {
587
+ while (1) switch (_context4.prev = _context4.next) {
588
+ case 0:
589
+ if (!(!(0, _platformFeatureFlags.fg)('platform_synced_block_patch_10') || !this.dataProvider || this.syncBlockCache.size === 0)) {
590
+ _context4.next = 2;
591
+ break;
592
+ }
593
+ return _context4.abrupt("return");
594
+ case 2:
595
+ // Source blocks have plain UUID resourceIds, but fetchNodesData internally uses
596
+ // generateBlockAriFromReference which expects reference-format resourceIds
597
+ // (e.g. "confluence-page/pageId/uuid"). We convert source resourceIds to reference
598
+ // format before fetching, and maintain a mapping back to original resourceIds
599
+ // so we can update the correct cache entries.
600
+ sourceToReferenceMap = new Map();
601
+ syncBlockNodes = Array.from(this.syncBlockCache.entries()).map(function (_ref) {
602
+ var _this6$dataProvider$g, _this6$dataProvider;
603
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
604
+ resourceId = _ref2[0],
605
+ data = _ref2[1];
606
+ var referenceResourceId = (_this6$dataProvider$g = (_this6$dataProvider = _this6.dataProvider) === null || _this6$dataProvider === void 0 ? void 0 : _this6$dataProvider.generateResourceIdForReference(resourceId)) !== null && _this6$dataProvider$g !== void 0 ? _this6$dataProvider$g : resourceId;
607
+ sourceToReferenceMap.set(referenceResourceId, resourceId);
608
+ return {
609
+ type: 'bodiedSyncBlock',
610
+ attrs: {
611
+ localId: data.blockInstanceId,
612
+ resourceId: referenceResourceId
613
+ }
614
+ };
615
+ });
616
+ _context4.prev = 4;
617
+ _context4.next = 7;
618
+ return this.dataProvider.fetchNodesData(syncBlockNodes);
619
+ case 7:
620
+ results = _context4.sent;
621
+ _iterator = _createForOfIteratorHelper(results);
622
+ try {
623
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
624
+ result = _step.value;
625
+ // Map the reference resourceId back to the source resourceId
626
+ sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
627
+ cached = this.syncBlockCache.get(sourceResourceId);
628
+ if (cached && (_result$data = result.data) !== null && _result$data !== void 0 && _result$data.status) {
629
+ cached.status = result.data.status;
630
+ }
631
+ }
632
+ } catch (err) {
633
+ _iterator.e(err);
634
+ } finally {
635
+ _iterator.f();
636
+ }
637
+ _context4.next = 14;
638
+ break;
639
+ case 12:
640
+ _context4.prev = 12;
641
+ _context4.t0 = _context4["catch"](4);
642
+ case 14:
643
+ case "end":
644
+ return _context4.stop();
645
+ }
646
+ }, _callee4, this, [[4, 12]]);
647
+ }));
648
+ function fetchAndCacheStatuses() {
649
+ return _fetchAndCacheStatuses.apply(this, arguments);
650
+ }
651
+ return fetchAndCacheStatuses;
652
+ }()
653
+ /**
654
+ * Deletes all source sync blocks that have 'unpublished' status.
655
+ * Used to clean up orphaned blocks when a user cancels editing without saving.
656
+ * Blocks that were already saved (status 'active') are not affected.
657
+ *
658
+ * @returns true if all deletions succeeded, false otherwise
659
+ */
660
+ )
661
+ }, {
662
+ key: "discardUnpublishedBlocks",
663
+ value: function discardUnpublishedBlocks() {
664
+ if (!(0, _platformFeatureFlags.fg)('platform_synced_block_patch_10')) {
665
+ return Promise.resolve(true);
666
+ }
667
+ var unpublishedBlockIds = Array.from(this.syncBlockCache.entries()).filter(function (_ref3) {
668
+ var _ref4 = (0, _slicedToArray2.default)(_ref3, 2),
669
+ _ = _ref4[0],
670
+ data = _ref4[1];
671
+ return data.status === 'unpublished' && !data.pendingDeletion;
672
+ }).map(function (_ref5) {
673
+ var _ref6 = (0, _slicedToArray2.default)(_ref5, 2),
674
+ resourceId = _ref6[0],
675
+ data = _ref6[1];
676
+ return {
677
+ resourceId: resourceId,
678
+ localId: data.blockInstanceId
679
+ };
680
+ });
681
+ if (unpublishedBlockIds.length === 0) {
682
+ return Promise.resolve(true);
683
+ }
684
+ return this.delete(unpublishedBlockIds, function () {},
685
+ // onDelete: no-op, document is being discarded
686
+ function () {},
687
+ // onDeleteCompleted: no-op
688
+ 'source-block-unpublished');
689
+ }
690
+
691
+ /**
692
+ * Deletes sync blocks with confirmation from the backend
553
693
  *
554
694
  * @param syncBlockIds - The sync block ids to delete
555
695
  * @param onDelete - The callback to delete sync block node from document
@@ -559,33 +699,33 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
559
699
  }, {
560
700
  key: "deleteSyncBlocksWithConfirmation",
561
701
  value: (function () {
562
- var _deleteSyncBlocksWithConfirmation = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(syncBlockIds, deletionReason, onDelete, onDeleteCompleted, destroyCallback) {
702
+ var _deleteSyncBlocksWithConfirmation = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(syncBlockIds, deletionReason, onDelete, onDeleteCompleted, destroyCallback) {
563
703
  var confirmed, isDeleteSuccessful;
564
- return _regenerator.default.wrap(function _callee4$(_context4) {
565
- while (1) switch (_context4.prev = _context4.next) {
704
+ return _regenerator.default.wrap(function _callee5$(_context5) {
705
+ while (1) switch (_context5.prev = _context5.next) {
566
706
  case 0:
567
707
  if (!(this.viewMode === 'view' && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_8'))) {
568
- _context4.next = 2;
708
+ _context5.next = 2;
569
709
  break;
570
710
  }
571
- return _context4.abrupt("return", Promise.resolve());
711
+ return _context5.abrupt("return", Promise.resolve());
572
712
  case 2:
573
713
  if (!this.confirmationCallback) {
574
- _context4.next = 14;
714
+ _context5.next = 14;
575
715
  break;
576
716
  }
577
- _context4.next = 5;
717
+ _context5.next = 5;
578
718
  return this.confirmationCallback(syncBlockIds, deletionReason);
579
719
  case 5:
580
- confirmed = _context4.sent;
720
+ confirmed = _context5.sent;
581
721
  if (!confirmed) {
582
- _context4.next = 13;
722
+ _context5.next = 13;
583
723
  break;
584
724
  }
585
- _context4.next = 9;
725
+ _context5.next = 9;
586
726
  return this.delete(syncBlockIds, onDelete, onDeleteCompleted, deletionReason);
587
727
  case 9:
588
- isDeleteSuccessful = _context4.sent;
728
+ isDeleteSuccessful = _context5.sent;
589
729
  if (!isDeleteSuccessful) {
590
730
  // If deletion failed, save deletion info for potential retry
591
731
  this.deletionRetryInfo = {
@@ -598,15 +738,15 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
598
738
  } else {
599
739
  destroyCallback();
600
740
  }
601
- _context4.next = 14;
741
+ _context5.next = 14;
602
742
  break;
603
743
  case 13:
604
744
  destroyCallback();
605
745
  case 14:
606
746
  case "end":
607
- return _context4.stop();
747
+ return _context5.stop();
608
748
  }
609
- }, _callee4, this);
749
+ }, _callee5, this);
610
750
  }));
611
751
  function deleteSyncBlocksWithConfirmation(_x5, _x6, _x7, _x8, _x9) {
612
752
  return _deleteSyncBlocksWithConfirmation.apply(this, arguments);
@@ -616,7 +756,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
616
756
  }, {
617
757
  key: "getSyncBlockSourceInfo",
618
758
  value: function getSyncBlockSourceInfo(localId) {
619
- var _this6 = this;
759
+ var _this7 = this;
620
760
  try {
621
761
  var _this$fetchSourceInfo;
622
762
  if (!this.dataProvider) {
@@ -625,13 +765,13 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
625
765
  (_this$fetchSourceInfo = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo === void 0 || _this$fetchSourceInfo.start();
626
766
  return this.dataProvider.fetchSyncBlockSourceInfo(localId, undefined, undefined).then(function (sourceInfo) {
627
767
  if (!sourceInfo) {
628
- var _this6$fetchSourceInf;
629
- (_this6$fetchSourceInf = _this6.fetchSourceInfoExperience) === null || _this6$fetchSourceInf === void 0 || _this6$fetchSourceInf.failure({
768
+ var _this7$fetchSourceInf;
769
+ (_this7$fetchSourceInf = _this7.fetchSourceInfoExperience) === null || _this7$fetchSourceInf === void 0 || _this7$fetchSourceInf.failure({
630
770
  reason: 'No source info returned'
631
771
  });
632
772
  } else {
633
- var _this6$fetchSourceInf2;
634
- (_this6$fetchSourceInf2 = _this6.fetchSourceInfoExperience) === null || _this6$fetchSourceInf2 === void 0 || _this6$fetchSourceInf2.success();
773
+ var _this7$fetchSourceInf2;
774
+ (_this7$fetchSourceInf2 = _this7.fetchSourceInfoExperience) === null || _this7$fetchSourceInf2 === void 0 || _this7$fetchSourceInf2.success();
635
775
  }
636
776
  return sourceInfo;
637
777
  });
@@ -37,7 +37,7 @@ const mapErrorResponseCode = errorCode => {
37
37
  case 'NOT_FOUND':
38
38
  return SyncBlockError.NotFound;
39
39
  case 'EntityNotFound':
40
- return fg('platform_synced_block_patch_9') ? SyncBlockError.EntityNotFound : SyncBlockError.Errored;
40
+ return fg('platform_synced_block_patch_10') ? SyncBlockError.EntityNotFound : SyncBlockError.Errored;
41
41
  case 'INVALID_REQUEST':
42
42
  return SyncBlockError.InvalidRequest;
43
43
  case 'CONFLICT':
@@ -861,11 +861,15 @@ class BlockServiceADFWriteProvider {
861
861
 
862
862
  // Process successful updates
863
863
  if (response.success) {
864
- const successResourceIds = new Set(response.success.map(block => blockAriToResourceIdMap.get(block.blockAri)));
864
+ const successBlocks = new Map(response.success.map(block => [blockAriToResourceIdMap.get(block.blockAri), block]));
865
865
  for (const block of data) {
866
- if (successResourceIds.has(block.resourceId)) {
866
+ const successBlock = successBlocks.get(block.resourceId);
867
+ if (successBlock) {
867
868
  results.push({
868
- resourceId: block.resourceId
869
+ resourceId: block.resourceId,
870
+ ...(fg('platform_synced_block_patch_10') && {
871
+ status: successBlock.status
872
+ })
869
873
  });
870
874
  }
871
875
  }
@@ -86,7 +86,10 @@ export class SourceSyncBlockStoreManager {
86
86
  ...syncBlockData,
87
87
  isDirty: isDirty,
88
88
  // if the change is from remote, it's not dirty
89
- contentFragment: syncBlockNode.content
89
+ contentFragment: syncBlockNode.content,
90
+ ...(fg('platform_synced_block_patch_10') && {
91
+ status: cachedBlock === null || cachedBlock === void 0 ? void 0 : cachedBlock.status
92
+ })
90
93
  });
91
94
  } else {
92
95
  const syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
@@ -95,7 +98,10 @@ export class SourceSyncBlockStoreManager {
95
98
  }
96
99
  this.syncBlockCache.set(resourceId, {
97
100
  ...syncBlockData,
98
- isDirty: true
101
+ isDirty: true,
102
+ ...(fg('platform_synced_block_patch_10') && {
103
+ status: cachedBlock === null || cachedBlock === void 0 ? void 0 : cachedBlock.status
104
+ })
99
105
  });
100
106
  }
101
107
  return true;
@@ -172,6 +178,13 @@ export class SourceSyncBlockStoreManager {
172
178
  writeResults.forEach(result => {
173
179
  if (result.resourceId && !result.error) {
174
180
  var _this$fireAnalyticsEv2;
181
+ // Update cache with the status returned from the backend
182
+ if (fg('platform_synced_block_patch_10')) {
183
+ const cachedData = this.syncBlockCache.get(result.resourceId);
184
+ if (cachedData && result.status) {
185
+ cachedData.status = result.status;
186
+ }
187
+ }
175
188
  (_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 ? void 0 : _this$fireAnalyticsEv2.call(this, updateSuccessPayload(result.resourceId, false));
176
189
  }
177
190
  });
@@ -296,6 +309,14 @@ export class SourceSyncBlockStoreManager {
296
309
  if (fg('platform_synced_block_update_refactor')) {
297
310
  // add the node to the cache
298
311
  this.updateSyncBlockData(node, false);
312
+
313
+ // Mark the block as unpublished in the cache so it can be cleaned up on cancel
314
+ if (fg('platform_synced_block_patch_10')) {
315
+ const cached = this.syncBlockCache.get(resourceId);
316
+ if (cached) {
317
+ cached.status = 'unpublished';
318
+ }
319
+ }
299
320
  }
300
321
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
301
322
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 ? void 0 : _this$createExperienc.start({});
@@ -424,6 +445,78 @@ export class SourceSyncBlockStoreManager {
424
445
  }
425
446
 
426
447
  /**
448
+ * Fetches the current status of all source sync blocks in the cache from the backend
449
+ * and updates the cache entries with the fetched status.
450
+ * This is called on editor init so we know which blocks are 'unpublished' vs 'active'.
451
+ */
452
+ async fetchAndCacheStatuses() {
453
+ if (!fg('platform_synced_block_patch_10') || !this.dataProvider || this.syncBlockCache.size === 0) {
454
+ return;
455
+ }
456
+
457
+ // Source blocks have plain UUID resourceIds, but fetchNodesData internally uses
458
+ // generateBlockAriFromReference which expects reference-format resourceIds
459
+ // (e.g. "confluence-page/pageId/uuid"). We convert source resourceIds to reference
460
+ // format before fetching, and maintain a mapping back to original resourceIds
461
+ // so we can update the correct cache entries.
462
+ const sourceToReferenceMap = new Map();
463
+ const syncBlockNodes = Array.from(this.syncBlockCache.entries()).map(([resourceId, data]) => {
464
+ var _this$dataProvider$ge, _this$dataProvider;
465
+ const referenceResourceId = (_this$dataProvider$ge = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.generateResourceIdForReference(resourceId)) !== null && _this$dataProvider$ge !== void 0 ? _this$dataProvider$ge : resourceId;
466
+ sourceToReferenceMap.set(referenceResourceId, resourceId);
467
+ return {
468
+ type: 'bodiedSyncBlock',
469
+ attrs: {
470
+ localId: data.blockInstanceId,
471
+ resourceId: referenceResourceId
472
+ }
473
+ };
474
+ });
475
+ try {
476
+ const results = await this.dataProvider.fetchNodesData(syncBlockNodes);
477
+ for (const result of results) {
478
+ var _sourceToReferenceMap, _result$data;
479
+ // Map the reference resourceId back to the source resourceId
480
+ const sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
481
+ const cached = this.syncBlockCache.get(sourceResourceId);
482
+ if (cached && (_result$data = result.data) !== null && _result$data !== void 0 && _result$data.status) {
483
+ cached.status = result.data.status;
484
+ }
485
+ }
486
+ } catch {
487
+ // If the fetch fails, statuses remain undefined.
488
+ // This is acceptable — on cancel, blocks without a known status
489
+ // will not be deleted (safe default).
490
+ }
491
+ }
492
+
493
+ /**
494
+ * Deletes all source sync blocks that have 'unpublished' status.
495
+ * Used to clean up orphaned blocks when a user cancels editing without saving.
496
+ * Blocks that were already saved (status 'active') are not affected.
497
+ *
498
+ * @returns true if all deletions succeeded, false otherwise
499
+ */
500
+ discardUnpublishedBlocks() {
501
+ if (!fg('platform_synced_block_patch_10')) {
502
+ return Promise.resolve(true);
503
+ }
504
+ const unpublishedBlockIds = Array.from(this.syncBlockCache.entries()).filter(([_, data]) => data.status === 'unpublished' && !data.pendingDeletion).map(([resourceId, data]) => ({
505
+ resourceId,
506
+ localId: data.blockInstanceId
507
+ }));
508
+ if (unpublishedBlockIds.length === 0) {
509
+ return Promise.resolve(true);
510
+ }
511
+ return this.delete(unpublishedBlockIds, () => {},
512
+ // onDelete: no-op, document is being discarded
513
+ () => {},
514
+ // onDeleteCompleted: no-op
515
+ 'source-block-unpublished');
516
+ }
517
+
518
+ /**
519
+ * Deletes sync blocks with confirmation from the backend
427
520
  *
428
521
  * @param syncBlockIds - The sync block ids to delete
429
522
  * @param onDelete - The callback to delete sync block node from document
@@ -48,7 +48,7 @@ var mapErrorResponseCode = function mapErrorResponseCode(errorCode) {
48
48
  case 'NOT_FOUND':
49
49
  return SyncBlockError.NotFound;
50
50
  case 'EntityNotFound':
51
- return fg('platform_synced_block_patch_9') ? SyncBlockError.EntityNotFound : SyncBlockError.Errored;
51
+ return fg('platform_synced_block_patch_10') ? SyncBlockError.EntityNotFound : SyncBlockError.Errored;
52
52
  case 'INVALID_REQUEST':
53
53
  return SyncBlockError.InvalidRequest;
54
54
  case 'CONFLICT':
@@ -1266,7 +1266,7 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
1266
1266
  value: function () {
1267
1267
  var _writeDataBatch = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee10(data) {
1268
1268
  var _this3 = this;
1269
- var stepVersion, blockAriToResourceIdMap, blocks, response, results, successResourceIds, _iterator6, _step6, block, errorResourceIds, _iterator7, _step7, _loop2;
1269
+ var stepVersion, blockAriToResourceIdMap, blocks, response, results, successBlocks, _iterator6, _step6, block, successBlock, errorResourceIds, _iterator7, _step7, _loop2;
1270
1270
  return _regeneratorRuntime.wrap(function _callee10$(_context12) {
1271
1271
  while (1) switch (_context12.prev = _context12.next) {
1272
1272
  case 0:
@@ -1316,17 +1316,20 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
1316
1316
  response = _context12.sent;
1317
1317
  results = []; // Process successful updates
1318
1318
  if (response.success) {
1319
- successResourceIds = new Set(response.success.map(function (block) {
1320
- return blockAriToResourceIdMap.get(block.blockAri);
1319
+ successBlocks = new Map(response.success.map(function (block) {
1320
+ return [blockAriToResourceIdMap.get(block.blockAri), block];
1321
1321
  }));
1322
1322
  _iterator6 = _createForOfIteratorHelper(data);
1323
1323
  try {
1324
1324
  for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1325
1325
  block = _step6.value;
1326
- if (successResourceIds.has(block.resourceId)) {
1327
- results.push({
1326
+ successBlock = successBlocks.get(block.resourceId);
1327
+ if (successBlock) {
1328
+ results.push(_objectSpread({
1328
1329
  resourceId: block.resourceId
1329
- });
1330
+ }, fg('platform_synced_block_patch_10') && {
1331
+ status: successBlock.status
1332
+ }));
1330
1333
  }
1331
1334
  }
1332
1335
  } catch (err) {
@@ -1,7 +1,11 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
1
2
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
3
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
4
  import _createClass from "@babel/runtime/helpers/createClass";
4
5
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
6
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
7
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
8
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
9
  import _regeneratorRuntime from "@babel/runtime/regenerator";
6
10
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
7
11
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -101,6 +105,8 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
101
105
  isDirty: isDirty,
102
106
  // if the change is from remote, it's not dirty
103
107
  contentFragment: syncBlockNode.content
108
+ }, fg('platform_synced_block_patch_10') && {
109
+ status: cachedBlock === null || cachedBlock === void 0 ? void 0 : cachedBlock.status
104
110
  }));
105
111
  } else {
106
112
  var _syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
@@ -109,6 +115,8 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
109
115
  }
110
116
  this.syncBlockCache.set(resourceId, _objectSpread(_objectSpread({}, _syncBlockData), {}, {
111
117
  isDirty: true
118
+ }, fg('platform_synced_block_patch_10') && {
119
+ status: cachedBlock === null || cachedBlock === void 0 ? void 0 : cachedBlock.status
112
120
  }));
113
121
  }
114
122
  return true;
@@ -207,6 +215,13 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
207
215
  writeResults.forEach(function (result) {
208
216
  if (result.resourceId && !result.error) {
209
217
  var _this2$fireAnalyticsE;
218
+ // Update cache with the status returned from the backend
219
+ if (fg('platform_synced_block_patch_10')) {
220
+ var cachedData = _this2.syncBlockCache.get(result.resourceId);
221
+ if (cachedData && result.status) {
222
+ cachedData.status = result.status;
223
+ }
224
+ }
210
225
  (_this2$fireAnalyticsE = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE === void 0 || _this2$fireAnalyticsE.call(_this2, updateSuccessPayload(result.resourceId, false));
211
226
  }
212
227
  });
@@ -360,6 +375,14 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
360
375
  if (fg('platform_synced_block_update_refactor')) {
361
376
  // add the node to the cache
362
377
  this.updateSyncBlockData(node, false);
378
+
379
+ // Mark the block as unpublished in the cache so it can be cleaned up on cancel
380
+ if (fg('platform_synced_block_patch_10')) {
381
+ var cached = this.syncBlockCache.get(resourceId);
382
+ if (cached) {
383
+ cached.status = 'unpublished';
384
+ }
385
+ }
363
386
  }
364
387
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
365
388
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
@@ -543,6 +566,123 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
543
566
  }
544
567
 
545
568
  /**
569
+ * Fetches the current status of all source sync blocks in the cache from the backend
570
+ * and updates the cache entries with the fetched status.
571
+ * This is called on editor init so we know which blocks are 'unpublished' vs 'active'.
572
+ */
573
+ }, {
574
+ key: "fetchAndCacheStatuses",
575
+ value: (function () {
576
+ var _fetchAndCacheStatuses = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
577
+ var _this6 = this;
578
+ var sourceToReferenceMap, syncBlockNodes, results, _iterator, _step, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
579
+ return _regeneratorRuntime.wrap(function _callee4$(_context4) {
580
+ while (1) switch (_context4.prev = _context4.next) {
581
+ case 0:
582
+ if (!(!fg('platform_synced_block_patch_10') || !this.dataProvider || this.syncBlockCache.size === 0)) {
583
+ _context4.next = 2;
584
+ break;
585
+ }
586
+ return _context4.abrupt("return");
587
+ case 2:
588
+ // Source blocks have plain UUID resourceIds, but fetchNodesData internally uses
589
+ // generateBlockAriFromReference which expects reference-format resourceIds
590
+ // (e.g. "confluence-page/pageId/uuid"). We convert source resourceIds to reference
591
+ // format before fetching, and maintain a mapping back to original resourceIds
592
+ // so we can update the correct cache entries.
593
+ sourceToReferenceMap = new Map();
594
+ syncBlockNodes = Array.from(this.syncBlockCache.entries()).map(function (_ref) {
595
+ var _this6$dataProvider$g, _this6$dataProvider;
596
+ var _ref2 = _slicedToArray(_ref, 2),
597
+ resourceId = _ref2[0],
598
+ data = _ref2[1];
599
+ var referenceResourceId = (_this6$dataProvider$g = (_this6$dataProvider = _this6.dataProvider) === null || _this6$dataProvider === void 0 ? void 0 : _this6$dataProvider.generateResourceIdForReference(resourceId)) !== null && _this6$dataProvider$g !== void 0 ? _this6$dataProvider$g : resourceId;
600
+ sourceToReferenceMap.set(referenceResourceId, resourceId);
601
+ return {
602
+ type: 'bodiedSyncBlock',
603
+ attrs: {
604
+ localId: data.blockInstanceId,
605
+ resourceId: referenceResourceId
606
+ }
607
+ };
608
+ });
609
+ _context4.prev = 4;
610
+ _context4.next = 7;
611
+ return this.dataProvider.fetchNodesData(syncBlockNodes);
612
+ case 7:
613
+ results = _context4.sent;
614
+ _iterator = _createForOfIteratorHelper(results);
615
+ try {
616
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
617
+ result = _step.value;
618
+ // Map the reference resourceId back to the source resourceId
619
+ sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
620
+ cached = this.syncBlockCache.get(sourceResourceId);
621
+ if (cached && (_result$data = result.data) !== null && _result$data !== void 0 && _result$data.status) {
622
+ cached.status = result.data.status;
623
+ }
624
+ }
625
+ } catch (err) {
626
+ _iterator.e(err);
627
+ } finally {
628
+ _iterator.f();
629
+ }
630
+ _context4.next = 14;
631
+ break;
632
+ case 12:
633
+ _context4.prev = 12;
634
+ _context4.t0 = _context4["catch"](4);
635
+ case 14:
636
+ case "end":
637
+ return _context4.stop();
638
+ }
639
+ }, _callee4, this, [[4, 12]]);
640
+ }));
641
+ function fetchAndCacheStatuses() {
642
+ return _fetchAndCacheStatuses.apply(this, arguments);
643
+ }
644
+ return fetchAndCacheStatuses;
645
+ }()
646
+ /**
647
+ * Deletes all source sync blocks that have 'unpublished' status.
648
+ * Used to clean up orphaned blocks when a user cancels editing without saving.
649
+ * Blocks that were already saved (status 'active') are not affected.
650
+ *
651
+ * @returns true if all deletions succeeded, false otherwise
652
+ */
653
+ )
654
+ }, {
655
+ key: "discardUnpublishedBlocks",
656
+ value: function discardUnpublishedBlocks() {
657
+ if (!fg('platform_synced_block_patch_10')) {
658
+ return Promise.resolve(true);
659
+ }
660
+ var unpublishedBlockIds = Array.from(this.syncBlockCache.entries()).filter(function (_ref3) {
661
+ var _ref4 = _slicedToArray(_ref3, 2),
662
+ _ = _ref4[0],
663
+ data = _ref4[1];
664
+ return data.status === 'unpublished' && !data.pendingDeletion;
665
+ }).map(function (_ref5) {
666
+ var _ref6 = _slicedToArray(_ref5, 2),
667
+ resourceId = _ref6[0],
668
+ data = _ref6[1];
669
+ return {
670
+ resourceId: resourceId,
671
+ localId: data.blockInstanceId
672
+ };
673
+ });
674
+ if (unpublishedBlockIds.length === 0) {
675
+ return Promise.resolve(true);
676
+ }
677
+ return this.delete(unpublishedBlockIds, function () {},
678
+ // onDelete: no-op, document is being discarded
679
+ function () {},
680
+ // onDeleteCompleted: no-op
681
+ 'source-block-unpublished');
682
+ }
683
+
684
+ /**
685
+ * Deletes sync blocks with confirmation from the backend
546
686
  *
547
687
  * @param syncBlockIds - The sync block ids to delete
548
688
  * @param onDelete - The callback to delete sync block node from document
@@ -552,33 +692,33 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
552
692
  }, {
553
693
  key: "deleteSyncBlocksWithConfirmation",
554
694
  value: (function () {
555
- var _deleteSyncBlocksWithConfirmation = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(syncBlockIds, deletionReason, onDelete, onDeleteCompleted, destroyCallback) {
695
+ var _deleteSyncBlocksWithConfirmation = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(syncBlockIds, deletionReason, onDelete, onDeleteCompleted, destroyCallback) {
556
696
  var confirmed, isDeleteSuccessful;
557
- return _regeneratorRuntime.wrap(function _callee4$(_context4) {
558
- while (1) switch (_context4.prev = _context4.next) {
697
+ return _regeneratorRuntime.wrap(function _callee5$(_context5) {
698
+ while (1) switch (_context5.prev = _context5.next) {
559
699
  case 0:
560
700
  if (!(this.viewMode === 'view' && fg('platform_synced_block_patch_8'))) {
561
- _context4.next = 2;
701
+ _context5.next = 2;
562
702
  break;
563
703
  }
564
- return _context4.abrupt("return", Promise.resolve());
704
+ return _context5.abrupt("return", Promise.resolve());
565
705
  case 2:
566
706
  if (!this.confirmationCallback) {
567
- _context4.next = 14;
707
+ _context5.next = 14;
568
708
  break;
569
709
  }
570
- _context4.next = 5;
710
+ _context5.next = 5;
571
711
  return this.confirmationCallback(syncBlockIds, deletionReason);
572
712
  case 5:
573
- confirmed = _context4.sent;
713
+ confirmed = _context5.sent;
574
714
  if (!confirmed) {
575
- _context4.next = 13;
715
+ _context5.next = 13;
576
716
  break;
577
717
  }
578
- _context4.next = 9;
718
+ _context5.next = 9;
579
719
  return this.delete(syncBlockIds, onDelete, onDeleteCompleted, deletionReason);
580
720
  case 9:
581
- isDeleteSuccessful = _context4.sent;
721
+ isDeleteSuccessful = _context5.sent;
582
722
  if (!isDeleteSuccessful) {
583
723
  // If deletion failed, save deletion info for potential retry
584
724
  this.deletionRetryInfo = {
@@ -591,15 +731,15 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
591
731
  } else {
592
732
  destroyCallback();
593
733
  }
594
- _context4.next = 14;
734
+ _context5.next = 14;
595
735
  break;
596
736
  case 13:
597
737
  destroyCallback();
598
738
  case 14:
599
739
  case "end":
600
- return _context4.stop();
740
+ return _context5.stop();
601
741
  }
602
- }, _callee4, this);
742
+ }, _callee5, this);
603
743
  }));
604
744
  function deleteSyncBlocksWithConfirmation(_x5, _x6, _x7, _x8, _x9) {
605
745
  return _deleteSyncBlocksWithConfirmation.apply(this, arguments);
@@ -609,7 +749,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
609
749
  }, {
610
750
  key: "getSyncBlockSourceInfo",
611
751
  value: function getSyncBlockSourceInfo(localId) {
612
- var _this6 = this;
752
+ var _this7 = this;
613
753
  try {
614
754
  var _this$fetchSourceInfo;
615
755
  if (!this.dataProvider) {
@@ -618,13 +758,13 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
618
758
  (_this$fetchSourceInfo = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo === void 0 || _this$fetchSourceInfo.start();
619
759
  return this.dataProvider.fetchSyncBlockSourceInfo(localId, undefined, undefined).then(function (sourceInfo) {
620
760
  if (!sourceInfo) {
621
- var _this6$fetchSourceInf;
622
- (_this6$fetchSourceInf = _this6.fetchSourceInfoExperience) === null || _this6$fetchSourceInf === void 0 || _this6$fetchSourceInf.failure({
761
+ var _this7$fetchSourceInf;
762
+ (_this7$fetchSourceInf = _this7.fetchSourceInfoExperience) === null || _this7$fetchSourceInf === void 0 || _this7$fetchSourceInf.failure({
623
763
  reason: 'No source info returned'
624
764
  });
625
765
  } else {
626
- var _this6$fetchSourceInf2;
627
- (_this6$fetchSourceInf2 = _this6.fetchSourceInfoExperience) === null || _this6$fetchSourceInf2 === void 0 || _this6$fetchSourceInf2.success();
766
+ var _this7$fetchSourceInf2;
767
+ (_this7$fetchSourceInf2 = _this7.fetchSourceInfoExperience) === null || _this7$fetchSourceInf2 === void 0 || _this7$fetchSourceInf2.success();
628
768
  }
629
769
  return sourceInfo;
630
770
  });
@@ -3,7 +3,7 @@ import type { EmojiProvider } from '@atlaskit/emoji';
3
3
  import type { MentionProvider } from '@atlaskit/mention/types';
4
4
  import { NodeDataProvider } from '@atlaskit/node-data-provider';
5
5
  import type { TaskDecisionProvider } from '@atlaskit/task-decision/types';
6
- import type { SyncBlockData, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, DeletionReason } from '../common/types';
6
+ import type { SyncBlockData, SyncBlockStatus, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, DeletionReason } from '../common/types';
7
7
  type SyncBlockErrorInfo = {
8
8
  reason?: string;
9
9
  sourceAri?: string;
@@ -48,6 +48,7 @@ export type SyncBlockParentInfo = {
48
48
  export type WriteSyncBlockResult = {
49
49
  error?: string;
50
50
  resourceId?: ResourceId;
51
+ status?: SyncBlockStatus;
51
52
  };
52
53
  export type SourceInfoFetchData = {
53
54
  pageARI: string;
@@ -68,6 +68,21 @@ export declare class SourceSyncBlockStoreManager {
68
68
  retryDeletion(): Promise<void>;
69
69
  clearPendingDeletion(): void;
70
70
  /**
71
+ * Fetches the current status of all source sync blocks in the cache from the backend
72
+ * and updates the cache entries with the fetched status.
73
+ * This is called on editor init so we know which blocks are 'unpublished' vs 'active'.
74
+ */
75
+ fetchAndCacheStatuses(): Promise<void>;
76
+ /**
77
+ * Deletes all source sync blocks that have 'unpublished' status.
78
+ * Used to clean up orphaned blocks when a user cancels editing without saving.
79
+ * Blocks that were already saved (status 'active') are not affected.
80
+ *
81
+ * @returns true if all deletions succeeded, false otherwise
82
+ */
83
+ discardUnpublishedBlocks(): Promise<boolean>;
84
+ /**
85
+ * Deletes sync blocks with confirmation from the backend
71
86
  *
72
87
  * @param syncBlockIds - The sync block ids to delete
73
88
  * @param onDelete - The callback to delete sync block node from document
@@ -3,7 +3,7 @@ import type { EmojiProvider } from '@atlaskit/emoji';
3
3
  import type { MentionProvider } from '@atlaskit/mention/types';
4
4
  import { NodeDataProvider } from '@atlaskit/node-data-provider';
5
5
  import type { TaskDecisionProvider } from '@atlaskit/task-decision/types';
6
- import type { SyncBlockData, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, DeletionReason } from '../common/types';
6
+ import type { SyncBlockData, SyncBlockStatus, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs, ReferenceSyncBlockData, DeletionReason } from '../common/types';
7
7
  type SyncBlockErrorInfo = {
8
8
  reason?: string;
9
9
  sourceAri?: string;
@@ -48,6 +48,7 @@ export type SyncBlockParentInfo = {
48
48
  export type WriteSyncBlockResult = {
49
49
  error?: string;
50
50
  resourceId?: ResourceId;
51
+ status?: SyncBlockStatus;
51
52
  };
52
53
  export type SourceInfoFetchData = {
53
54
  pageARI: string;
@@ -68,6 +68,21 @@ export declare class SourceSyncBlockStoreManager {
68
68
  retryDeletion(): Promise<void>;
69
69
  clearPendingDeletion(): void;
70
70
  /**
71
+ * Fetches the current status of all source sync blocks in the cache from the backend
72
+ * and updates the cache entries with the fetched status.
73
+ * This is called on editor init so we know which blocks are 'unpublished' vs 'active'.
74
+ */
75
+ fetchAndCacheStatuses(): Promise<void>;
76
+ /**
77
+ * Deletes all source sync blocks that have 'unpublished' status.
78
+ * Used to clean up orphaned blocks when a user cancels editing without saving.
79
+ * Blocks that were already saved (status 'active') are not affected.
80
+ *
81
+ * @returns true if all deletions succeeded, false otherwise
82
+ */
83
+ discardUnpublishedBlocks(): Promise<boolean>;
84
+ /**
85
+ * Deletes sync blocks with confirmation from the backend
71
86
  *
72
87
  * @param syncBlockIds - The sync block ids to delete
73
88
  * @param onDelete - The callback to delete sync block node from document
package/package.json CHANGED
@@ -24,12 +24,12 @@
24
24
  ],
25
25
  "atlaskit:src": "src/index.ts",
26
26
  "dependencies": {
27
- "@atlaskit/adf-utils": "^19.28.0",
27
+ "@atlaskit/adf-utils": "^19.29.0",
28
28
  "@atlaskit/editor-json-transformer": "^8.31.0",
29
29
  "@atlaskit/editor-prosemirror": "^7.3.0",
30
30
  "@atlaskit/node-data-provider": "^11.0.0",
31
31
  "@atlaskit/platform-feature-flags": "^1.1.0",
32
- "@atlaskit/tmp-editor-statsig": "^74.0.0",
32
+ "@atlaskit/tmp-editor-statsig": "^75.0.0",
33
33
  "@babel/runtime": "^7.0.0",
34
34
  "@compiled/react": "^0.20.0",
35
35
  "graphql-ws": "^5.14.2",
@@ -38,7 +38,7 @@
38
38
  "uuid": "^3.1.0"
39
39
  },
40
40
  "peerDependencies": {
41
- "@atlaskit/editor-common": "^114.15.0",
41
+ "@atlaskit/editor-common": "^114.19.0",
42
42
  "react": "^18.2.0"
43
43
  },
44
44
  "devDependencies": {
@@ -81,7 +81,7 @@
81
81
  }
82
82
  },
83
83
  "name": "@atlaskit/editor-synced-block-provider",
84
- "version": "6.3.2",
84
+ "version": "6.4.1",
85
85
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
86
86
  "author": "Atlassian Pty Ltd",
87
87
  "license": "Apache-2.0",
@@ -98,6 +98,9 @@
98
98
  "platform_synced_block_patch_9": {
99
99
  "type": "boolean"
100
100
  },
101
+ "platform_synced_block_patch_10": {
102
+ "type": "boolean"
103
+ },
101
104
  "platform_synced_block_add_info_web_socket_error": {
102
105
  "type": "boolean"
103
106
  }