@atlaskit/editor-synced-block-provider 2.15.1 → 2.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/clients/block-service/blockService.js +42 -1
  3. package/dist/cjs/providers/block-service/blockServiceAPI.js +62 -3
  4. package/dist/cjs/providers/confluence/confluenceContentAPI.js +7 -0
  5. package/dist/cjs/providers/syncBlockProvider.js +5 -0
  6. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +92 -0
  7. package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +27 -13
  8. package/dist/cjs/utils/errorHandling.js +4 -1
  9. package/dist/es2019/clients/block-service/blockService.js +19 -0
  10. package/dist/es2019/providers/block-service/blockServiceAPI.js +34 -1
  11. package/dist/es2019/providers/confluence/confluenceContentAPI.js +5 -0
  12. package/dist/es2019/providers/syncBlockProvider.js +3 -0
  13. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +59 -1
  14. package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +18 -4
  15. package/dist/es2019/utils/errorHandling.js +1 -0
  16. package/dist/esm/clients/block-service/blockService.js +41 -0
  17. package/dist/esm/providers/block-service/blockServiceAPI.js +63 -4
  18. package/dist/esm/providers/confluence/confluenceContentAPI.js +7 -0
  19. package/dist/esm/providers/syncBlockProvider.js +5 -0
  20. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +93 -1
  21. package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +27 -12
  22. package/dist/esm/utils/errorHandling.js +3 -0
  23. package/dist/types/clients/block-service/blockService.d.ts +16 -4
  24. package/dist/types/providers/block-service/blockServiceAPI.d.ts +3 -2
  25. package/dist/types/providers/confluence/confluenceContentAPI.d.ts +3 -2
  26. package/dist/types/providers/syncBlockProvider.d.ts +3 -2
  27. package/dist/types/providers/types.d.ts +13 -1
  28. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +7 -0
  29. package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +1 -1
  30. package/dist/types/utils/errorHandling.d.ts +1 -0
  31. package/dist/types-ts4.5/clients/block-service/blockService.d.ts +16 -4
  32. package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +3 -2
  33. package/dist/types-ts4.5/providers/confluence/confluenceContentAPI.d.ts +3 -2
  34. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +3 -2
  35. package/dist/types-ts4.5/providers/types.d.ts +13 -1
  36. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +7 -0
  37. package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +1 -1
  38. package/dist/types-ts4.5/utils/errorHandling.d.ts +1 -0
  39. package/package.json +2 -3
@@ -2,6 +2,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
3
3
  import uuid from 'uuid';
4
4
  import { logException } from '@atlaskit/editor-common/monitoring';
5
+ import { SyncBlockError } from '../common/types';
5
6
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload } from '../utils/errorHandling';
6
7
  import { convertSyncBlockPMNodeToSyncBlockData } from '../utils/utils';
7
8
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
@@ -42,7 +43,10 @@ export class SourceSyncBlockStoreManager {
42
43
  throw new Error('Local ID or resource ID is not set');
43
44
  }
44
45
  const syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
45
- this.syncBlockCache.set(resourceId, syncBlockData);
46
+ this.syncBlockCache.set(resourceId, {
47
+ ...syncBlockData,
48
+ isDirty: true
49
+ });
46
50
  return true;
47
51
  } catch (error) {
48
52
  var _this$fireAnalyticsEv;
@@ -68,7 +72,8 @@ export class SourceSyncBlockStoreManager {
68
72
  const bodiedSyncBlockData = [];
69
73
  Array.from(this.syncBlockCache.values()).forEach(syncBlockData => {
70
74
  // Don't flush nodes that are waiting to be deleted to avoid nodes being re-created
71
- if (!syncBlockData.pendingDeletion) {
75
+ // Don't flush nodes that haven't been updated since we last flushed
76
+ if (!syncBlockData.pendingDeletion && syncBlockData.isDirty) {
72
77
  bodiedSyncBlockNodes.push({
73
78
  type: 'bodiedSyncBlock',
74
79
  attrs: {
@@ -83,10 +88,19 @@ export class SourceSyncBlockStoreManager {
83
88
  return Promise.resolve(true);
84
89
  }
85
90
  const writeResults = await this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
86
- if (writeResults.every(result => result.resourceId !== undefined)) {
91
+ writeResults.forEach(result => {
92
+ // set isDirty to false on write success and unrecoverable errors like not found
93
+ if (result.resourceId && (result.error === SyncBlockError.NotFound || !result.error)) {
94
+ const cachedData = this.syncBlockCache.get(result.resourceId);
95
+ if (cachedData) {
96
+ cachedData.isDirty = false;
97
+ }
98
+ }
99
+ });
100
+ if (writeResults.every(result => result.resourceId && !result.error)) {
87
101
  return true;
88
102
  } else {
89
- writeResults.filter(result => result.resourceId === undefined).forEach(result => {
103
+ writeResults.filter(result => !result.resourceId || result.error).forEach(result => {
90
104
  var _this$fireAnalyticsEv2;
91
105
  (_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 ? void 0 : _this$fireAnalyticsEv2.call(this, updateErrorPayload(result.error || 'Failed to write data'));
92
106
  });
@@ -18,6 +18,7 @@ export const getErrorPayload = (actionSubjectId, error) => ({
18
18
  export const fetchErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error);
19
19
  export const getSourceInfoErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error);
20
20
  export const updateErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error);
21
+ export const updateReferenceErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE, error);
21
22
  export const createErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error);
22
23
  export const deleteErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE, error);
23
24
  export const updateCacheErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE_CACHE, error);
@@ -240,4 +240,45 @@ export var createSyncedBlock = /*#__PURE__*/function () {
240
240
  return function createSyncedBlock(_x5) {
241
241
  return _ref9.apply(this, arguments);
242
242
  };
243
+ }();
244
+ export var updateReferenceSyncedBlockOnDocument = /*#__PURE__*/function () {
245
+ var _ref1 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(_ref0) {
246
+ var documentAri, blocks, _ref0$noContent, noContent, response;
247
+ return _regeneratorRuntime.wrap(function _callee6$(_context6) {
248
+ while (1) switch (_context6.prev = _context6.next) {
249
+ case 0:
250
+ documentAri = _ref0.documentAri, blocks = _ref0.blocks, _ref0$noContent = _ref0.noContent, noContent = _ref0$noContent === void 0 ? true : _ref0$noContent;
251
+ _context6.next = 3;
252
+ return fetchWithRetry("".concat(BLOCK_SERVICE_API_URL, "/block/document/").concat(encodeURIComponent(documentAri), "/references?noContent=").concat(noContent), {
253
+ method: 'PUT',
254
+ headers: COMMON_HEADERS,
255
+ body: JSON.stringify({
256
+ blocks: blocks
257
+ })
258
+ });
259
+ case 3:
260
+ response = _context6.sent;
261
+ if (response.ok) {
262
+ _context6.next = 6;
263
+ break;
264
+ }
265
+ throw new BlockError(response.status);
266
+ case 6:
267
+ if (noContent) {
268
+ _context6.next = 10;
269
+ break;
270
+ }
271
+ _context6.next = 9;
272
+ return response.json();
273
+ case 9:
274
+ return _context6.abrupt("return", _context6.sent);
275
+ case 10:
276
+ case "end":
277
+ return _context6.stop();
278
+ }
279
+ }, _callee6);
280
+ }));
281
+ return function updateReferenceSyncedBlockOnDocument(_x6) {
282
+ return _ref1.apply(this, arguments);
283
+ };
243
284
  }();
@@ -6,7 +6,7 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
6
6
  /* eslint-disable require-unicode-regexp */
7
7
  import { useMemo } from 'react';
8
8
  import { generateBlockAri, generateBlockAriFromReference } from '../../clients/block-service/ari';
9
- import { BlockError, createSyncedBlock, deleteSyncedBlock, getReferenceSyncedBlocks, getSyncedBlockContent, updateSyncedBlock } from '../../clients/block-service/blockService';
9
+ import { BlockError, createSyncedBlock, deleteSyncedBlock, getReferenceSyncedBlocks, getSyncedBlockContent, updateReferenceSyncedBlockOnDocument, updateSyncedBlock } from '../../clients/block-service/blockService';
10
10
  import { SyncBlockError } from '../../common/types';
11
11
  import { stringifyError } from '../../utils/errorHandling';
12
12
  var mapBlockError = function mapBlockError(error) {
@@ -317,21 +317,30 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
317
317
  _context5.prev = 7;
318
318
  _context5.t0 = _context5["catch"](1);
319
319
  if (!(_context5.t0 instanceof BlockError)) {
320
- _context5.next = 11;
320
+ _context5.next = 13;
321
+ break;
322
+ }
323
+ if (!(_context5.t0.status === 404)) {
324
+ _context5.next = 12;
321
325
  break;
322
326
  }
327
+ return _context5.abrupt("return", {
328
+ resourceId: resourceId,
329
+ success: true
330
+ });
331
+ case 12:
323
332
  return _context5.abrupt("return", {
324
333
  resourceId: resourceId,
325
334
  success: false,
326
335
  error: mapBlockError(_context5.t0)
327
336
  });
328
- case 11:
337
+ case 13:
329
338
  return _context5.abrupt("return", {
330
339
  resourceId: resourceId,
331
340
  success: false,
332
341
  error: stringifyError(_context5.t0)
333
342
  });
334
- case 12:
343
+ case 14:
335
344
  case "end":
336
345
  return _context5.stop();
337
346
  }
@@ -352,6 +361,56 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
352
361
  value: function generateResourceId() {
353
362
  return crypto.randomUUID();
354
363
  }
364
+ }, {
365
+ key: "updateReferenceData",
366
+ value: function () {
367
+ var _updateReferenceData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6(blocks, noContent) {
368
+ var _this = this;
369
+ return _regeneratorRuntime.wrap(function _callee6$(_context6) {
370
+ while (1) switch (_context6.prev = _context6.next) {
371
+ case 0:
372
+ _context6.prev = 0;
373
+ _context6.next = 3;
374
+ return updateReferenceSyncedBlockOnDocument({
375
+ documentAri: this.sourceAri,
376
+ blocks: blocks.map(function (block) {
377
+ return {
378
+ blockAri: generateBlockAriFromReference(_this.sourceAri, block.resourceId),
379
+ blockInstanceId: block.localId
380
+ };
381
+ }, noContent)
382
+ });
383
+ case 3:
384
+ return _context6.abrupt("return", {
385
+ success: true
386
+ });
387
+ case 6:
388
+ _context6.prev = 6;
389
+ _context6.t0 = _context6["catch"](0);
390
+ if (!(_context6.t0 instanceof BlockError)) {
391
+ _context6.next = 10;
392
+ break;
393
+ }
394
+ return _context6.abrupt("return", {
395
+ success: false,
396
+ error: mapBlockError(_context6.t0)
397
+ });
398
+ case 10:
399
+ return _context6.abrupt("return", {
400
+ success: false,
401
+ error: stringifyError(_context6.t0)
402
+ });
403
+ case 11:
404
+ case "end":
405
+ return _context6.stop();
406
+ }
407
+ }, _callee6, this, [[0, 6]]);
408
+ }));
409
+ function updateReferenceData(_x6, _x7) {
410
+ return _updateReferenceData.apply(this, arguments);
411
+ }
412
+ return updateReferenceData;
413
+ }()
355
414
  }]);
356
415
  }();
357
416
  /**
@@ -403,6 +403,13 @@ var ConfluenceADFWriteProvider = /*#__PURE__*/function () {
403
403
  value: function generateResourceIdForReference(sourceId) {
404
404
  return sourceId;
405
405
  }
406
+ }, {
407
+ key: "updateReferenceData",
408
+ value: function updateReferenceData(_blocks, _noContent) {
409
+ return Promise.resolve({
410
+ success: true
411
+ });
412
+ }
406
413
  }]);
407
414
  }();
408
415
  /**
@@ -289,6 +289,11 @@ export var SyncBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
289
289
  throw new Error("".concat(sourceProduct, " source product not supported"));
290
290
  }
291
291
  }
292
+ }, {
293
+ key: "updateReferenceData",
294
+ value: function updateReferenceData(blocks, noContent) {
295
+ return this.writeProvider.updateReferenceData(blocks, noContent);
296
+ }
292
297
  }]);
293
298
  }(SyncBlockDataProvider);
294
299
  export var useMemoizedSyncedBlockProvider = function useMemoizedSyncedBlockProvider(fetchProvider, writeProvider, sourceId, providerOptions, getSSRData) {
@@ -12,7 +12,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
12
12
  import { logException } from '@atlaskit/editor-common/monitoring';
13
13
  import { ProviderFactory } from '@atlaskit/editor-common/provider-factory';
14
14
  import { SyncBlockError } from '../common/types';
15
- import { fetchErrorPayload, getSourceInfoErrorPayload } from '../utils/errorHandling';
15
+ import { fetchErrorPayload, getSourceInfoErrorPayload, updateReferenceErrorPayload } from '../utils/errorHandling';
16
16
  import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
17
17
  import { createSyncBlockNode } from '../utils/utils';
18
18
 
@@ -24,6 +24,10 @@ import { createSyncBlockNode } from '../utils/utils';
24
24
  export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
25
25
  function ReferenceSyncBlockStoreManager(dataProvider, fireAnalyticsEvent) {
26
26
  _classCallCheck(this, ReferenceSyncBlockStoreManager);
27
+ // Keeps track of addition and deletion of reference synced blocks on the document
28
+ // This starts as true to always flush the cache when document is saved for the first time
29
+ // to cater the case when a editor seesion is closed without document being updated right after reference block is deleted
30
+ _defineProperty(this, "isCacheDirty", true);
27
31
  _defineProperty(this, "isRefreshingSubscriptions", false);
28
32
  this.syncBlockCache = new Map();
29
33
  this.subscriptions = new Map();
@@ -321,6 +325,9 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
321
325
  // add to subscriptions map
322
326
  var resourceSubscriptions = this.subscriptions.get(resourceId) || {};
323
327
  this.subscriptions.set(resourceId, _objectSpread(_objectSpread({}, resourceSubscriptions), {}, _defineProperty({}, localId, callback)));
328
+
329
+ // New subscription means new reference synced block is added to the document
330
+ this.isCacheDirty = true;
324
331
  var syncBlockNode = createSyncBlockNode(localId, resourceId);
325
332
 
326
333
  // call the callback immediately if we have cached data
@@ -340,6 +347,8 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
340
347
  return function () {
341
348
  var resourceSubscriptions = _this3.subscriptions.get(resourceId);
342
349
  if (resourceSubscriptions) {
350
+ // Unsubscription means a reference synced block is removed from the document
351
+ _this3.isCacheDirty = true;
343
352
  delete resourceSubscriptions[localId];
344
353
  if (Object.keys(resourceSubscriptions).length === 0) {
345
354
  _this3.subscriptions.delete(resourceId);
@@ -509,6 +518,89 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
509
518
  }
510
519
  }
511
520
  }
521
+
522
+ /**
523
+ * Update reference synced blocks on the document with the BE
524
+ *
525
+ * @returns true if the reference synced blocks are updated successfully, false otherwise
526
+ */
527
+ }, {
528
+ key: "flush",
529
+ value: (function () {
530
+ var _flush = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
531
+ var success, blocks, updateResult, _this$fireAnalyticsEv9, _this$fireAnalyticsEv0;
532
+ return _regeneratorRuntime.wrap(function _callee3$(_context4) {
533
+ while (1) switch (_context4.prev = _context4.next) {
534
+ case 0:
535
+ if (this.isCacheDirty) {
536
+ _context4.next = 2;
537
+ break;
538
+ }
539
+ return _context4.abrupt("return", true);
540
+ case 2:
541
+ success = true;
542
+ _context4.prev = 3;
543
+ if (this.dataProvider) {
544
+ _context4.next = 6;
545
+ break;
546
+ }
547
+ throw new Error('Data provider not set');
548
+ case 6:
549
+ blocks = []; // Collect all reference synced blocks on the current document
550
+ Array.from(this.subscriptions.entries()).forEach(function (_ref2) {
551
+ var _ref3 = _slicedToArray(_ref2, 2),
552
+ resourceId = _ref3[0],
553
+ callbacks = _ref3[1];
554
+ Object.keys(callbacks).forEach(function (localId) {
555
+ blocks.push({
556
+ resourceId: resourceId,
557
+ localId: localId
558
+ });
559
+ });
560
+ });
561
+ if (!(blocks.length === 0)) {
562
+ _context4.next = 10;
563
+ break;
564
+ }
565
+ return _context4.abrupt("return", true);
566
+ case 10:
567
+ _context4.next = 12;
568
+ return this.dataProvider.updateReferenceData(blocks);
569
+ case 12:
570
+ updateResult = _context4.sent;
571
+ if (!updateResult.success) {
572
+ success = false;
573
+ (_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 || _this$fireAnalyticsEv9.call(this, updateReferenceErrorPayload(updateResult.error || 'Failed to update reference synced blocks on the document'));
574
+ }
575
+ _context4.next = 21;
576
+ break;
577
+ case 16:
578
+ _context4.prev = 16;
579
+ _context4.t0 = _context4["catch"](3);
580
+ success = false;
581
+ logException(_context4.t0, {
582
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
583
+ });
584
+ (_this$fireAnalyticsEv0 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv0 === void 0 || _this$fireAnalyticsEv0.call(this, updateReferenceErrorPayload(_context4.t0.message));
585
+ case 21:
586
+ _context4.prev = 21;
587
+ if (success) {
588
+ this.isCacheDirty = false;
589
+ }
590
+ return _context4.finish(21);
591
+ case 24:
592
+ return _context4.abrupt("return", success);
593
+ case 25:
594
+ case "end":
595
+ return _context4.stop();
596
+ }
597
+ }, _callee3, this, [[3, 16, 21, 24]]);
598
+ }));
599
+ function flush() {
600
+ return _flush.apply(this, arguments);
601
+ }
602
+ return flush;
603
+ }())
512
604
  }, {
513
605
  key: "destroy",
514
606
  value: function destroy() {
@@ -3,9 +3,12 @@ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
3
  import _createClass from "@babel/runtime/helpers/createClass";
4
4
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
5
5
  import _regeneratorRuntime from "@babel/runtime/regenerator";
6
+ 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
+ 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; }
6
8
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
7
9
  import uuid from 'uuid';
8
10
  import { logException } from '@atlaskit/editor-common/monitoring';
11
+ import { SyncBlockError } from '../common/types';
9
12
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload } from '../utils/errorHandling';
10
13
  import { convertSyncBlockPMNodeToSyncBlockData } from '../utils/utils';
11
14
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
@@ -51,7 +54,9 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
51
54
  throw new Error('Local ID or resource ID is not set');
52
55
  }
53
56
  var syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
54
- this.syncBlockCache.set(resourceId, syncBlockData);
57
+ this.syncBlockCache.set(resourceId, _objectSpread(_objectSpread({}, syncBlockData), {}, {
58
+ isDirty: true
59
+ }));
55
60
  return true;
56
61
  } catch (error) {
57
62
  var _this$fireAnalyticsEv;
@@ -88,7 +93,8 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
88
93
  bodiedSyncBlockData = [];
89
94
  Array.from(this.syncBlockCache.values()).forEach(function (syncBlockData) {
90
95
  // Don't flush nodes that are waiting to be deleted to avoid nodes being re-created
91
- if (!syncBlockData.pendingDeletion) {
96
+ // Don't flush nodes that haven't been updated since we last flushed
97
+ if (!syncBlockData.pendingDeletion && syncBlockData.isDirty) {
92
98
  bodiedSyncBlockNodes.push({
93
99
  type: 'bodiedSyncBlock',
94
100
  attrs: {
@@ -109,37 +115,46 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
109
115
  return this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
110
116
  case 10:
111
117
  writeResults = _context.sent;
118
+ writeResults.forEach(function (result) {
119
+ // set isDirty to false on write success and unrecoverable errors like not found
120
+ if (result.resourceId && (result.error === SyncBlockError.NotFound || !result.error)) {
121
+ var cachedData = _this2.syncBlockCache.get(result.resourceId);
122
+ if (cachedData) {
123
+ cachedData.isDirty = false;
124
+ }
125
+ }
126
+ });
112
127
  if (!writeResults.every(function (result) {
113
- return result.resourceId !== undefined;
128
+ return result.resourceId && !result.error;
114
129
  })) {
115
- _context.next = 15;
130
+ _context.next = 16;
116
131
  break;
117
132
  }
118
133
  return _context.abrupt("return", true);
119
- case 15:
134
+ case 16:
120
135
  writeResults.filter(function (result) {
121
- return result.resourceId === undefined;
136
+ return !result.resourceId || result.error;
122
137
  }).forEach(function (result) {
123
138
  var _this2$fireAnalyticsE;
124
139
  (_this2$fireAnalyticsE = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE === void 0 || _this2$fireAnalyticsE.call(_this2, updateErrorPayload(result.error || 'Failed to write data'));
125
140
  });
126
141
  return _context.abrupt("return", false);
127
- case 17:
128
- _context.next = 24;
142
+ case 18:
143
+ _context.next = 25;
129
144
  break;
130
- case 19:
131
- _context.prev = 19;
145
+ case 20:
146
+ _context.prev = 20;
132
147
  _context.t0 = _context["catch"](0);
133
148
  logException(_context.t0, {
134
149
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
135
150
  });
136
151
  (_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 || _this$fireAnalyticsEv2.call(this, updateErrorPayload(_context.t0.message));
137
152
  return _context.abrupt("return", false);
138
- case 24:
153
+ case 25:
139
154
  case "end":
140
155
  return _context.stop();
141
156
  }
142
- }, _callee, this, [[0, 19]]);
157
+ }, _callee, this, [[0, 20]]);
143
158
  }));
144
159
  function flush() {
145
160
  return _flush.apply(this, arguments);
@@ -26,6 +26,9 @@ export var getSourceInfoErrorPayload = function getSourceInfoErrorPayload(error)
26
26
  export var updateErrorPayload = function updateErrorPayload(error) {
27
27
  return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error);
28
28
  };
29
+ export var updateReferenceErrorPayload = function updateReferenceErrorPayload(error) {
30
+ return getErrorPayload(ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE, error);
31
+ };
29
32
  export var createErrorPayload = function createErrorPayload(error) {
30
33
  return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error);
31
34
  };
@@ -15,6 +15,10 @@ export type BlockContentErrorResponse = {
15
15
  code: string;
16
16
  reason: string;
17
17
  };
18
+ type ReferenceSyncedBlockResponse = {
19
+ blocks?: Array<BlockContentResponse>;
20
+ errors?: Array<BlockContentErrorResponse>;
21
+ };
18
22
  export declare const isBlockContentResponse: (response: BlockContentResponse | BlockContentErrorResponse) => response is BlockContentResponse;
19
23
  /**
20
24
  * Retrieves all synced blocks referenced in a document.
@@ -58,10 +62,7 @@ export declare const isBlockContentResponse: (response: BlockContentResponse | B
58
62
  * ```
59
63
  * Check https://block-service.dev.atl-paas.net/ for latest API documentation.
60
64
  */
61
- export declare const getReferenceSyncedBlocks: (documentAri: string) => Promise<{
62
- blocks?: Array<BlockContentResponse>;
63
- errors?: Array<BlockContentErrorResponse>;
64
- }>;
65
+ export declare const getReferenceSyncedBlocks: (documentAri: string) => Promise<ReferenceSyncedBlockResponse>;
65
66
  export type GetSyncedBlockContentRequest = {
66
67
  blockAri: string;
67
68
  };
@@ -79,6 +80,15 @@ export type CreateSyncedBlockRequest = {
79
80
  product: SyncBlockProduct;
80
81
  sourceAri: string;
81
82
  };
83
+ type ReferenceSyncedBlockIDs = {
84
+ blockAri: string;
85
+ blockInstanceId: string;
86
+ };
87
+ type UpdateReferenceSyncedBlockOnDocumentRequest = {
88
+ blocks: ReferenceSyncedBlockIDs[];
89
+ documentAri: string;
90
+ noContent?: boolean;
91
+ };
82
92
  export declare class BlockError extends Error {
83
93
  readonly status: number;
84
94
  constructor(status: number);
@@ -87,3 +97,5 @@ export declare const getSyncedBlockContent: ({ blockAri, }: GetSyncedBlockConten
87
97
  export declare const deleteSyncedBlock: ({ blockAri }: DeleteSyncedBlockRequest) => Promise<void>;
88
98
  export declare const updateSyncedBlock: ({ blockAri, content, }: UpdateSyncedBlockRequest) => Promise<void>;
89
99
  export declare const createSyncedBlock: ({ blockAri, blockInstanceId, sourceAri, product, content, }: CreateSyncedBlockRequest) => Promise<BlockContentResponse>;
100
+ export declare const updateReferenceSyncedBlockOnDocument: ({ documentAri, blocks, noContent, }: UpdateReferenceSyncedBlockOnDocumentRequest) => Promise<ReferenceSyncedBlockResponse | void>;
101
+ export {};
@@ -1,5 +1,5 @@
1
- import { SyncBlockError, type ResourceId, type SyncBlockData, type SyncBlockProduct } from '../../common/types';
2
- import type { ADFFetchProvider, ADFWriteProvider, DeleteSyncBlockResult, SyncBlockInstance, WriteSyncBlockResult } from '../types';
1
+ import { SyncBlockError, type ResourceId, type SyncBlockAttrs, type SyncBlockData, type SyncBlockProduct } from '../../common/types';
2
+ import type { ADFFetchProvider, ADFWriteProvider, DeleteSyncBlockResult, SyncBlockInstance, UpdateReferenceSyncBlockResult, WriteSyncBlockResult } from '../types';
3
3
  export declare const fetchReferences: (documentAri: string) => Promise<SyncBlockInstance[] | SyncBlockError>;
4
4
  /**
5
5
  * ADFFetchProvider implementation that fetches synced block data from Block Service API
@@ -22,6 +22,7 @@ declare class BlockServiceADFWriteProvider implements ADFWriteProvider {
22
22
  deleteData(resourceId: string): Promise<DeleteSyncBlockResult>;
23
23
  generateResourceIdForReference(sourceId: ResourceId): ResourceId;
24
24
  generateResourceId(): ResourceId;
25
+ updateReferenceData(blocks: SyncBlockAttrs[], noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
25
26
  }
26
27
  export declare const useMemoizedBlockServiceAPIProviders: (sourceAri: string, product: SyncBlockProduct, sourceDocumentId: string) => {
27
28
  fetchProvider: BlockServiceADFFetchProvider;
@@ -1,5 +1,5 @@
1
- import { type ResourceId, type SyncBlockData, type SyncBlockProduct } from '../../common/types';
2
- import type { ADFFetchProvider, ADFWriteProvider, DeleteSyncBlockResult, SyncBlockInstance, WriteSyncBlockResult } from '../types';
1
+ import { type ResourceId, type SyncBlockAttrs, type SyncBlockData, type SyncBlockProduct } from '../../common/types';
2
+ import type { ADFFetchProvider, ADFWriteProvider, DeleteSyncBlockResult, SyncBlockInstance, UpdateReferenceSyncBlockResult, WriteSyncBlockResult } from '../types';
3
3
  /**
4
4
  * Configuration for Content API providers
5
5
  */
@@ -28,6 +28,7 @@ declare class ConfluenceADFWriteProvider implements ADFWriteProvider {
28
28
  deleteData(resourceId: string): Promise<DeleteSyncBlockResult>;
29
29
  generateResourceId(sourceId: string, localId: string): string;
30
30
  generateResourceIdForReference(sourceId: ResourceId): ResourceId;
31
+ updateReferenceData(_blocks: SyncBlockAttrs[], _noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
31
32
  }
32
33
  /**
33
34
  * Convenience function to create providers with default content property key
@@ -1,7 +1,7 @@
1
1
  import type { RendererSyncBlockEventPayload } from '@atlaskit/editor-common/analytics';
2
2
  import type { JSONNode } from '@atlaskit/editor-json-transformer/types';
3
- import { type BlockInstanceId, type ResourceId, type SyncBlockData, type SyncBlockNode, type SyncBlockProduct } from '../common/types';
4
- import { SyncBlockDataProvider, type ADFFetchProvider, type ADFWriteProvider, type DeleteSyncBlockResult, type SyncBlockInstance, type SyncBlockParentInfo, type SyncBlockSourceInfo, type SyncedBlockRendererProviderOptions, type WriteSyncBlockResult } from '../providers/types';
3
+ import { type BlockInstanceId, type ResourceId, type SyncBlockAttrs, type SyncBlockData, type SyncBlockNode, type SyncBlockProduct } from '../common/types';
4
+ import { SyncBlockDataProvider, type ADFFetchProvider, type ADFWriteProvider, type DeleteSyncBlockResult, type SyncBlockInstance, type SyncBlockParentInfo, type SyncBlockSourceInfo, type SyncedBlockRendererProviderOptions, type UpdateReferenceSyncBlockResult, type WriteSyncBlockResult } from '../providers/types';
5
5
  export declare class SyncBlockProvider extends SyncBlockDataProvider {
6
6
  name: string;
7
7
  private fetchProvider;
@@ -94,5 +94,6 @@ export declare class SyncBlockProvider extends SyncBlockDataProvider {
94
94
  * @returns The parent info for the sync block
95
95
  */
96
96
  retrieveSyncBlockParentInfo(sourceAri: string, sourceProduct: SyncBlockProduct): SyncBlockParentInfo | undefined;
97
+ updateReferenceData(blocks: SyncBlockAttrs[], noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
97
98
  }
98
99
  export declare const useMemoizedSyncedBlockProvider: (fetchProvider: ADFFetchProvider, writeProvider: ADFWriteProvider, sourceId: string, providerOptions: SyncedBlockRendererProviderOptions, getSSRData?: () => Record<string, SyncBlockInstance> | undefined) => SyncBlockProvider;
@@ -4,7 +4,7 @@ import type { EmojiProvider } from '@atlaskit/emoji';
4
4
  import type { MentionProvider } from '@atlaskit/mention/types';
5
5
  import { NodeDataProvider } from '@atlaskit/node-data-provider';
6
6
  import type { TaskDecisionProvider } from '@atlaskit/task-decision/types';
7
- import type { SyncBlockData, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId } from '../common/types';
7
+ import type { SyncBlockData, ResourceId, SyncBlockError, SyncBlockNode, SyncBlockProduct, BlockInstanceId, SyncBlockAttrs } from '../common/types';
8
8
  /**
9
9
  * The instance of a sync block, containing its data and metadata.
10
10
  * Mainly used for representing the state of a sync block after fetching from a data provider.
@@ -39,15 +39,26 @@ export type SourceInfoFetchData = {
39
39
  pageARI: string;
40
40
  sourceLocalId?: string;
41
41
  };
42
+ export type UpdateReferenceSyncBlockResult = {
43
+ error?: string;
44
+ success: boolean;
45
+ };
42
46
  export interface ADFFetchProvider {
43
47
  fetchData: (resourceId: ResourceId) => Promise<SyncBlockInstance>;
44
48
  }
45
49
  export interface ADFWriteProvider {
46
50
  createData: (data: SyncBlockData) => Promise<WriteSyncBlockResult>;
51
+ /**
52
+ * Delete source block.
53
+ * @param resourceId the resourceId of the block to be deleted
54
+ * @returns Object representing the result of the deletion. {resourceId: string, success: boolean, error?: string}.
55
+ * User should not be blocked by not_found error when deleting, so successful result should be returned for 404 error
56
+ */
47
57
  deleteData: (resourceId: ResourceId) => Promise<DeleteSyncBlockResult>;
48
58
  generateResourceId: (sourceId: string, localId: string) => ResourceId;
49
59
  generateResourceIdForReference: (sourceId: ResourceId) => ResourceId;
50
60
  product: SyncBlockProduct;
61
+ updateReferenceData: (blocks: SyncBlockAttrs[], noContent?: boolean) => Promise<UpdateReferenceSyncBlockResult>;
51
62
  writeData: (data: SyncBlockData) => Promise<WriteSyncBlockResult>;
52
63
  }
53
64
  export type MediaEmojiProviderOptions = {
@@ -84,6 +95,7 @@ export declare abstract class SyncBlockDataProvider extends NodeDataProvider<Syn
84
95
  */
85
96
  abstract generateResourceId(sourceId: ResourceId, localId: BlockInstanceId): ResourceId;
86
97
  abstract generateResourceIdForReference(sourceId: ResourceId): ResourceId;
98
+ abstract updateReferenceData(blocks: SyncBlockAttrs[], noContent?: boolean): Promise<UpdateReferenceSyncBlockResult>;
87
99
  }
88
100
  export type SubscriptionCallback = (data: SyncBlockInstance) => void;
89
101
  export type TitleSubscriptionCallback = (title: string) => void;
@@ -6,6 +6,7 @@ import type { SyncBlockInstance, SubscriptionCallback, SyncBlockDataProvider, Ti
6
6
  export declare class ReferenceSyncBlockStoreManager {
7
7
  private dataProvider?;
8
8
  private syncBlockCache;
9
+ private isCacheDirty;
9
10
  private subscriptions;
10
11
  private titleSubscriptions;
11
12
  private providerFactories;
@@ -44,5 +45,11 @@ export declare class ReferenceSyncBlockStoreManager {
44
45
  getSyncBlockURL(resourceId: ResourceId): string | undefined;
45
46
  getProviderFactory(resourceId: ResourceId): ProviderFactory | undefined;
46
47
  private retrieveDynamicProviders;
48
+ /**
49
+ * Update reference synced blocks on the document with the BE
50
+ *
51
+ * @returns true if the reference synced blocks are updated successfully, false otherwise
52
+ */
53
+ flush(): Promise<boolean>;
47
54
  destroy(): void;
48
55
  }
@@ -1,6 +1,6 @@
1
1
  import { type SyncBlockEventPayload } from '@atlaskit/editor-common/analytics';
2
2
  import { type Node as PMNode } from '@atlaskit/editor-prosemirror/model';
3
- import type { ResourceId, SyncBlockAttrs } from '../common/types';
3
+ import { type ResourceId, type SyncBlockAttrs } from '../common/types';
4
4
  import type { SyncBlockDataProvider } from '../providers/types';
5
5
  export type ConfirmationCallback = (syncBlockCount: number) => Promise<boolean>;
6
6
  type OnDelete = () => void;
@@ -6,6 +6,7 @@ export declare const getErrorPayload: <T extends ACTION_SUBJECT_ID>(actionSubjec
6
6
  export declare const fetchErrorPayload: (error: string) => RendererSyncBlockEventPayload;
7
7
  export declare const getSourceInfoErrorPayload: (error: string) => RendererSyncBlockEventPayload;
8
8
  export declare const updateErrorPayload: (error: string) => SyncBlockEventPayload;
9
+ export declare const updateReferenceErrorPayload: (error: string) => RendererSyncBlockEventPayload;
9
10
  export declare const createErrorPayload: (error: string) => SyncBlockEventPayload;
10
11
  export declare const deleteErrorPayload: (error: string) => SyncBlockEventPayload;
11
12
  export declare const updateCacheErrorPayload: (error: string) => SyncBlockEventPayload;