@atlaskit/editor-synced-block-provider 2.15.2 → 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 (34) hide show
  1. package/CHANGELOG.md +8 -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/utils/errorHandling.js +4 -1
  8. package/dist/es2019/clients/block-service/blockService.js +19 -0
  9. package/dist/es2019/providers/block-service/blockServiceAPI.js +34 -1
  10. package/dist/es2019/providers/confluence/confluenceContentAPI.js +5 -0
  11. package/dist/es2019/providers/syncBlockProvider.js +3 -0
  12. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +59 -1
  13. package/dist/es2019/utils/errorHandling.js +1 -0
  14. package/dist/esm/clients/block-service/blockService.js +41 -0
  15. package/dist/esm/providers/block-service/blockServiceAPI.js +63 -4
  16. package/dist/esm/providers/confluence/confluenceContentAPI.js +7 -0
  17. package/dist/esm/providers/syncBlockProvider.js +5 -0
  18. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +93 -1
  19. package/dist/esm/utils/errorHandling.js +3 -0
  20. package/dist/types/clients/block-service/blockService.d.ts +16 -4
  21. package/dist/types/providers/block-service/blockServiceAPI.d.ts +3 -2
  22. package/dist/types/providers/confluence/confluenceContentAPI.d.ts +3 -2
  23. package/dist/types/providers/syncBlockProvider.d.ts +3 -2
  24. package/dist/types/providers/types.d.ts +13 -1
  25. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +7 -0
  26. package/dist/types/utils/errorHandling.d.ts +1 -0
  27. package/dist/types-ts4.5/clients/block-service/blockService.d.ts +16 -4
  28. package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +3 -2
  29. package/dist/types-ts4.5/providers/confluence/confluenceContentAPI.d.ts +3 -2
  30. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +3 -2
  31. package/dist/types-ts4.5/providers/types.d.ts +13 -1
  32. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +7 -0
  33. package/dist/types-ts4.5/utils/errorHandling.d.ts +1 -0
  34. package/package.json +2 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 2.15.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`f14e76661c943`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f14e76661c943) -
8
+ [EDITOR-2844] Save reference synced block on document to BE when a page is saved
9
+ - Updated dependencies
10
+
3
11
  ## 2.15.2
4
12
 
5
13
  ### Patch Changes
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.updateSyncedBlock = exports.isBlockContentResponse = exports.getSyncedBlockContent = exports.getReferenceSyncedBlocks = exports.deleteSyncedBlock = exports.createSyncedBlock = exports.BlockError = void 0;
7
+ exports.updateSyncedBlock = exports.updateReferenceSyncedBlockOnDocument = exports.isBlockContentResponse = exports.getSyncedBlockContent = exports.getReferenceSyncedBlocks = exports.deleteSyncedBlock = exports.createSyncedBlock = exports.BlockError = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
9
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
10
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
@@ -247,4 +247,45 @@ var createSyncedBlock = exports.createSyncedBlock = /*#__PURE__*/function () {
247
247
  return function createSyncedBlock(_x5) {
248
248
  return _ref9.apply(this, arguments);
249
249
  };
250
+ }();
251
+ var updateReferenceSyncedBlockOnDocument = exports.updateReferenceSyncedBlockOnDocument = /*#__PURE__*/function () {
252
+ var _ref1 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(_ref0) {
253
+ var documentAri, blocks, _ref0$noContent, noContent, response;
254
+ return _regenerator.default.wrap(function _callee6$(_context6) {
255
+ while (1) switch (_context6.prev = _context6.next) {
256
+ case 0:
257
+ documentAri = _ref0.documentAri, blocks = _ref0.blocks, _ref0$noContent = _ref0.noContent, noContent = _ref0$noContent === void 0 ? true : _ref0$noContent;
258
+ _context6.next = 3;
259
+ return (0, _retry.fetchWithRetry)("".concat(BLOCK_SERVICE_API_URL, "/block/document/").concat(encodeURIComponent(documentAri), "/references?noContent=").concat(noContent), {
260
+ method: 'PUT',
261
+ headers: COMMON_HEADERS,
262
+ body: JSON.stringify({
263
+ blocks: blocks
264
+ })
265
+ });
266
+ case 3:
267
+ response = _context6.sent;
268
+ if (response.ok) {
269
+ _context6.next = 6;
270
+ break;
271
+ }
272
+ throw new BlockError(response.status);
273
+ case 6:
274
+ if (noContent) {
275
+ _context6.next = 10;
276
+ break;
277
+ }
278
+ _context6.next = 9;
279
+ return response.json();
280
+ case 9:
281
+ return _context6.abrupt("return", _context6.sent);
282
+ case 10:
283
+ case "end":
284
+ return _context6.stop();
285
+ }
286
+ }, _callee6);
287
+ }));
288
+ return function updateReferenceSyncedBlockOnDocument(_x6) {
289
+ return _ref1.apply(this, arguments);
290
+ };
250
291
  }();
@@ -325,21 +325,30 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
325
325
  _context5.prev = 7;
326
326
  _context5.t0 = _context5["catch"](1);
327
327
  if (!(_context5.t0 instanceof _blockService.BlockError)) {
328
- _context5.next = 11;
328
+ _context5.next = 13;
329
+ break;
330
+ }
331
+ if (!(_context5.t0.status === 404)) {
332
+ _context5.next = 12;
329
333
  break;
330
334
  }
335
+ return _context5.abrupt("return", {
336
+ resourceId: resourceId,
337
+ success: true
338
+ });
339
+ case 12:
331
340
  return _context5.abrupt("return", {
332
341
  resourceId: resourceId,
333
342
  success: false,
334
343
  error: mapBlockError(_context5.t0)
335
344
  });
336
- case 11:
345
+ case 13:
337
346
  return _context5.abrupt("return", {
338
347
  resourceId: resourceId,
339
348
  success: false,
340
349
  error: (0, _errorHandling.stringifyError)(_context5.t0)
341
350
  });
342
- case 12:
351
+ case 14:
343
352
  case "end":
344
353
  return _context5.stop();
345
354
  }
@@ -360,6 +369,56 @@ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
360
369
  value: function generateResourceId() {
361
370
  return crypto.randomUUID();
362
371
  }
372
+ }, {
373
+ key: "updateReferenceData",
374
+ value: function () {
375
+ var _updateReferenceData = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(blocks, noContent) {
376
+ var _this = this;
377
+ return _regenerator.default.wrap(function _callee6$(_context6) {
378
+ while (1) switch (_context6.prev = _context6.next) {
379
+ case 0:
380
+ _context6.prev = 0;
381
+ _context6.next = 3;
382
+ return (0, _blockService.updateReferenceSyncedBlockOnDocument)({
383
+ documentAri: this.sourceAri,
384
+ blocks: blocks.map(function (block) {
385
+ return {
386
+ blockAri: (0, _ari.generateBlockAriFromReference)(_this.sourceAri, block.resourceId),
387
+ blockInstanceId: block.localId
388
+ };
389
+ }, noContent)
390
+ });
391
+ case 3:
392
+ return _context6.abrupt("return", {
393
+ success: true
394
+ });
395
+ case 6:
396
+ _context6.prev = 6;
397
+ _context6.t0 = _context6["catch"](0);
398
+ if (!(_context6.t0 instanceof _blockService.BlockError)) {
399
+ _context6.next = 10;
400
+ break;
401
+ }
402
+ return _context6.abrupt("return", {
403
+ success: false,
404
+ error: mapBlockError(_context6.t0)
405
+ });
406
+ case 10:
407
+ return _context6.abrupt("return", {
408
+ success: false,
409
+ error: (0, _errorHandling.stringifyError)(_context6.t0)
410
+ });
411
+ case 11:
412
+ case "end":
413
+ return _context6.stop();
414
+ }
415
+ }, _callee6, this, [[0, 6]]);
416
+ }));
417
+ function updateReferenceData(_x6, _x7) {
418
+ return _updateReferenceData.apply(this, arguments);
419
+ }
420
+ return updateReferenceData;
421
+ }()
363
422
  }]);
364
423
  }();
365
424
  /**
@@ -409,6 +409,13 @@ var ConfluenceADFWriteProvider = /*#__PURE__*/function () {
409
409
  value: function generateResourceIdForReference(sourceId) {
410
410
  return sourceId;
411
411
  }
412
+ }, {
413
+ key: "updateReferenceData",
414
+ value: function updateReferenceData(_blocks, _noContent) {
415
+ return Promise.resolve({
416
+ success: true
417
+ });
418
+ }
412
419
  }]);
413
420
  }();
414
421
  /**
@@ -296,6 +296,11 @@ var SyncBlockProvider = exports.SyncBlockProvider = /*#__PURE__*/function (_Sync
296
296
  throw new Error("".concat(sourceProduct, " source product not supported"));
297
297
  }
298
298
  }
299
+ }, {
300
+ key: "updateReferenceData",
301
+ value: function updateReferenceData(blocks, noContent) {
302
+ return this.writeProvider.updateReferenceData(blocks, noContent);
303
+ }
299
304
  }]);
300
305
  }(_types2.SyncBlockDataProvider);
301
306
  var useMemoizedSyncedBlockProvider = exports.useMemoizedSyncedBlockProvider = function useMemoizedSyncedBlockProvider(fetchProvider, writeProvider, sourceId, providerOptions, getSSRData) {
@@ -30,6 +30,10 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
30
30
  var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
31
31
  function ReferenceSyncBlockStoreManager(dataProvider, fireAnalyticsEvent) {
32
32
  (0, _classCallCheck2.default)(this, ReferenceSyncBlockStoreManager);
33
+ // Keeps track of addition and deletion of reference synced blocks on the document
34
+ // This starts as true to always flush the cache when document is saved for the first time
35
+ // to cater the case when a editor seesion is closed without document being updated right after reference block is deleted
36
+ (0, _defineProperty2.default)(this, "isCacheDirty", true);
33
37
  (0, _defineProperty2.default)(this, "isRefreshingSubscriptions", false);
34
38
  this.syncBlockCache = new Map();
35
39
  this.subscriptions = new Map();
@@ -327,6 +331,9 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
327
331
  // add to subscriptions map
328
332
  var resourceSubscriptions = this.subscriptions.get(resourceId) || {};
329
333
  this.subscriptions.set(resourceId, _objectSpread(_objectSpread({}, resourceSubscriptions), {}, (0, _defineProperty2.default)({}, localId, callback)));
334
+
335
+ // New subscription means new reference synced block is added to the document
336
+ this.isCacheDirty = true;
330
337
  var syncBlockNode = (0, _utils.createSyncBlockNode)(localId, resourceId);
331
338
 
332
339
  // call the callback immediately if we have cached data
@@ -346,6 +353,8 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
346
353
  return function () {
347
354
  var resourceSubscriptions = _this3.subscriptions.get(resourceId);
348
355
  if (resourceSubscriptions) {
356
+ // Unsubscription means a reference synced block is removed from the document
357
+ _this3.isCacheDirty = true;
349
358
  delete resourceSubscriptions[localId];
350
359
  if (Object.keys(resourceSubscriptions).length === 0) {
351
360
  _this3.subscriptions.delete(resourceId);
@@ -515,6 +524,89 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
515
524
  }
516
525
  }
517
526
  }
527
+
528
+ /**
529
+ * Update reference synced blocks on the document with the BE
530
+ *
531
+ * @returns true if the reference synced blocks are updated successfully, false otherwise
532
+ */
533
+ }, {
534
+ key: "flush",
535
+ value: (function () {
536
+ var _flush = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
537
+ var success, blocks, updateResult, _this$fireAnalyticsEv9, _this$fireAnalyticsEv0;
538
+ return _regenerator.default.wrap(function _callee3$(_context4) {
539
+ while (1) switch (_context4.prev = _context4.next) {
540
+ case 0:
541
+ if (this.isCacheDirty) {
542
+ _context4.next = 2;
543
+ break;
544
+ }
545
+ return _context4.abrupt("return", true);
546
+ case 2:
547
+ success = true;
548
+ _context4.prev = 3;
549
+ if (this.dataProvider) {
550
+ _context4.next = 6;
551
+ break;
552
+ }
553
+ throw new Error('Data provider not set');
554
+ case 6:
555
+ blocks = []; // Collect all reference synced blocks on the current document
556
+ Array.from(this.subscriptions.entries()).forEach(function (_ref2) {
557
+ var _ref3 = (0, _slicedToArray2.default)(_ref2, 2),
558
+ resourceId = _ref3[0],
559
+ callbacks = _ref3[1];
560
+ Object.keys(callbacks).forEach(function (localId) {
561
+ blocks.push({
562
+ resourceId: resourceId,
563
+ localId: localId
564
+ });
565
+ });
566
+ });
567
+ if (!(blocks.length === 0)) {
568
+ _context4.next = 10;
569
+ break;
570
+ }
571
+ return _context4.abrupt("return", true);
572
+ case 10:
573
+ _context4.next = 12;
574
+ return this.dataProvider.updateReferenceData(blocks);
575
+ case 12:
576
+ updateResult = _context4.sent;
577
+ if (!updateResult.success) {
578
+ success = false;
579
+ (_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 || _this$fireAnalyticsEv9.call(this, (0, _errorHandling.updateReferenceErrorPayload)(updateResult.error || 'Failed to update reference synced blocks on the document'));
580
+ }
581
+ _context4.next = 21;
582
+ break;
583
+ case 16:
584
+ _context4.prev = 16;
585
+ _context4.t0 = _context4["catch"](3);
586
+ success = false;
587
+ (0, _monitoring.logException)(_context4.t0, {
588
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
589
+ });
590
+ (_this$fireAnalyticsEv0 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv0 === void 0 || _this$fireAnalyticsEv0.call(this, (0, _errorHandling.updateReferenceErrorPayload)(_context4.t0.message));
591
+ case 21:
592
+ _context4.prev = 21;
593
+ if (success) {
594
+ this.isCacheDirty = false;
595
+ }
596
+ return _context4.finish(21);
597
+ case 24:
598
+ return _context4.abrupt("return", success);
599
+ case 25:
600
+ case "end":
601
+ return _context4.stop();
602
+ }
603
+ }, _callee3, this, [[3, 16, 21, 24]]);
604
+ }));
605
+ function flush() {
606
+ return _flush.apply(this, arguments);
607
+ }
608
+ return flush;
609
+ }())
518
610
  }, {
519
611
  key: "destroy",
520
612
  value: function destroy() {
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.updateErrorPayload = exports.updateCacheErrorPayload = exports.stringifyError = exports.getSourceInfoErrorPayload = exports.getErrorPayload = exports.fetchErrorPayload = exports.deleteErrorPayload = exports.createErrorPayload = void 0;
6
+ exports.updateReferenceErrorPayload = exports.updateErrorPayload = exports.updateCacheErrorPayload = exports.stringifyError = exports.getSourceInfoErrorPayload = exports.getErrorPayload = exports.fetchErrorPayload = exports.deleteErrorPayload = exports.createErrorPayload = void 0;
7
7
  var _analytics = require("@atlaskit/editor-common/analytics");
8
8
  var stringifyError = exports.stringifyError = function stringifyError(error) {
9
9
  try {
@@ -32,6 +32,9 @@ var getSourceInfoErrorPayload = exports.getSourceInfoErrorPayload = function get
32
32
  var updateErrorPayload = exports.updateErrorPayload = function updateErrorPayload(error) {
33
33
  return getErrorPayload(_analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error);
34
34
  };
35
+ var updateReferenceErrorPayload = exports.updateReferenceErrorPayload = function updateReferenceErrorPayload(error) {
36
+ return getErrorPayload(_analytics.ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE, error);
37
+ };
35
38
  var createErrorPayload = exports.createErrorPayload = function createErrorPayload(error) {
36
39
  return getErrorPayload(_analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error);
37
40
  };
@@ -127,4 +127,23 @@ export const createSyncedBlock = async ({
127
127
  throw new BlockError(response.status);
128
128
  }
129
129
  return await response.json();
130
+ };
131
+ export const updateReferenceSyncedBlockOnDocument = async ({
132
+ documentAri,
133
+ blocks,
134
+ noContent = true
135
+ }) => {
136
+ const response = await fetchWithRetry(`${BLOCK_SERVICE_API_URL}/block/document/${encodeURIComponent(documentAri)}/references?noContent=${noContent}`, {
137
+ method: 'PUT',
138
+ headers: COMMON_HEADERS,
139
+ body: JSON.stringify({
140
+ blocks
141
+ })
142
+ });
143
+ if (!response.ok) {
144
+ throw new BlockError(response.status);
145
+ }
146
+ if (!noContent) {
147
+ return await response.json();
148
+ }
130
149
  };
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable require-unicode-regexp */
2
2
  import { useMemo } from 'react';
3
3
  import { generateBlockAri, generateBlockAriFromReference } from '../../clients/block-service/ari';
4
- import { BlockError, createSyncedBlock, deleteSyncedBlock, getReferenceSyncedBlocks, getSyncedBlockContent, updateSyncedBlock } from '../../clients/block-service/blockService';
4
+ import { BlockError, createSyncedBlock, deleteSyncedBlock, getReferenceSyncedBlocks, getSyncedBlockContent, updateReferenceSyncedBlockOnDocument, updateSyncedBlock } from '../../clients/block-service/blockService';
5
5
  import { SyncBlockError } from '../../common/types';
6
6
  import { stringifyError } from '../../utils/errorHandling';
7
7
  const mapBlockError = error => {
@@ -212,6 +212,14 @@ class BlockServiceADFWriteProvider {
212
212
  };
213
213
  } catch (error) {
214
214
  if (error instanceof BlockError) {
215
+ if (error.status === 404) {
216
+ // User should not be blocked by not_found error when deleting,
217
+ // hence returns successful result for 404 error
218
+ return {
219
+ resourceId,
220
+ success: true
221
+ };
222
+ }
215
223
  return {
216
224
  resourceId,
217
225
  success: false,
@@ -233,6 +241,31 @@ class BlockServiceADFWriteProvider {
233
241
  generateResourceId() {
234
242
  return crypto.randomUUID();
235
243
  }
244
+ async updateReferenceData(blocks, noContent) {
245
+ try {
246
+ await updateReferenceSyncedBlockOnDocument({
247
+ documentAri: this.sourceAri,
248
+ blocks: blocks.map(block => ({
249
+ blockAri: generateBlockAriFromReference(this.sourceAri, block.resourceId),
250
+ blockInstanceId: block.localId
251
+ }), noContent)
252
+ });
253
+ return {
254
+ success: true
255
+ };
256
+ } catch (error) {
257
+ if (error instanceof BlockError) {
258
+ return {
259
+ success: false,
260
+ error: mapBlockError(error)
261
+ };
262
+ }
263
+ return {
264
+ success: false,
265
+ error: stringifyError(error)
266
+ };
267
+ }
268
+ }
236
269
  }
237
270
 
238
271
  /**
@@ -275,6 +275,11 @@ class ConfluenceADFWriteProvider {
275
275
  generateResourceIdForReference(sourceId) {
276
276
  return sourceId;
277
277
  }
278
+ updateReferenceData(_blocks, _noContent) {
279
+ return Promise.resolve({
280
+ success: true
281
+ });
282
+ }
278
283
  }
279
284
 
280
285
  /**
@@ -200,6 +200,9 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
200
200
  throw new Error(`${sourceProduct} source product not supported`);
201
201
  }
202
202
  }
203
+ updateReferenceData(blocks, noContent) {
204
+ return this.writeProvider.updateReferenceData(blocks, noContent);
205
+ }
203
206
  }
204
207
  export const useMemoizedSyncedBlockProvider = (fetchProvider, writeProvider, sourceId, providerOptions, getSSRData) => {
205
208
  return useMemo(() => {
@@ -2,7 +2,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import { logException } from '@atlaskit/editor-common/monitoring';
3
3
  import { ProviderFactory } from '@atlaskit/editor-common/provider-factory';
4
4
  import { SyncBlockError } from '../common/types';
5
- import { fetchErrorPayload, getSourceInfoErrorPayload } from '../utils/errorHandling';
5
+ import { fetchErrorPayload, getSourceInfoErrorPayload, updateReferenceErrorPayload } from '../utils/errorHandling';
6
6
  import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
7
7
  import { createSyncBlockNode } from '../utils/utils';
8
8
 
@@ -13,6 +13,10 @@ import { createSyncBlockNode } from '../utils/utils';
13
13
  // Can be used in both editor and renderer contexts.
14
14
  export class ReferenceSyncBlockStoreManager {
15
15
  constructor(dataProvider, fireAnalyticsEvent) {
16
+ // Keeps track of addition and deletion of reference synced blocks on the document
17
+ // This starts as true to always flush the cache when document is saved for the first time
18
+ // to cater the case when a editor seesion is closed without document being updated right after reference block is deleted
19
+ _defineProperty(this, "isCacheDirty", true);
16
20
  _defineProperty(this, "isRefreshingSubscriptions", false);
17
21
  this.syncBlockCache = new Map();
18
22
  this.subscriptions = new Map();
@@ -212,6 +216,9 @@ export class ReferenceSyncBlockStoreManager {
212
216
  ...resourceSubscriptions,
213
217
  [localId]: callback
214
218
  });
219
+
220
+ // New subscription means new reference synced block is added to the document
221
+ this.isCacheDirty = true;
215
222
  const syncBlockNode = createSyncBlockNode(localId, resourceId);
216
223
 
217
224
  // call the callback immediately if we have cached data
@@ -231,6 +238,8 @@ export class ReferenceSyncBlockStoreManager {
231
238
  return () => {
232
239
  const resourceSubscriptions = this.subscriptions.get(resourceId);
233
240
  if (resourceSubscriptions) {
241
+ // Unsubscription means a reference synced block is removed from the document
242
+ this.isCacheDirty = true;
234
243
  delete resourceSubscriptions[localId];
235
244
  if (Object.keys(resourceSubscriptions).length === 0) {
236
245
  this.subscriptions.delete(resourceId);
@@ -397,6 +406,55 @@ export class ReferenceSyncBlockStoreManager {
397
406
  }
398
407
  }
399
408
  }
409
+
410
+ /**
411
+ * Update reference synced blocks on the document with the BE
412
+ *
413
+ * @returns true if the reference synced blocks are updated successfully, false otherwise
414
+ */
415
+ async flush() {
416
+ if (!this.isCacheDirty) {
417
+ return true;
418
+ }
419
+ let success = true;
420
+ try {
421
+ if (!this.dataProvider) {
422
+ throw new Error('Data provider not set');
423
+ }
424
+ const blocks = [];
425
+
426
+ // Collect all reference synced blocks on the current document
427
+ Array.from(this.subscriptions.entries()).forEach(([resourceId, callbacks]) => {
428
+ Object.keys(callbacks).forEach(localId => {
429
+ blocks.push({
430
+ resourceId,
431
+ localId
432
+ });
433
+ });
434
+ });
435
+ if (blocks.length === 0) {
436
+ return true;
437
+ }
438
+ const updateResult = await this.dataProvider.updateReferenceData(blocks);
439
+ if (!updateResult.success) {
440
+ var _this$fireAnalyticsEv10;
441
+ success = false;
442
+ (_this$fireAnalyticsEv10 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv10 === void 0 ? void 0 : _this$fireAnalyticsEv10.call(this, updateReferenceErrorPayload(updateResult.error || 'Failed to update reference synced blocks on the document'));
443
+ }
444
+ } catch (error) {
445
+ var _this$fireAnalyticsEv11;
446
+ success = false;
447
+ logException(error, {
448
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
449
+ });
450
+ (_this$fireAnalyticsEv11 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv11 === void 0 ? void 0 : _this$fireAnalyticsEv11.call(this, updateReferenceErrorPayload(error.message));
451
+ } finally {
452
+ if (success) {
453
+ this.isCacheDirty = false;
454
+ }
455
+ }
456
+ return success;
457
+ }
400
458
  destroy() {
401
459
  this.dataProvider = undefined;
402
460
  this.syncBlockCache.clear();
@@ -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() {
@@ -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
  }
@@ -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;
@@ -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
  }
@@ -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;
package/package.json CHANGED
@@ -24,10 +24,9 @@
24
24
  ],
25
25
  "atlaskit:src": "src/index.ts",
26
26
  "dependencies": {
27
- "@atlaskit/adf-schema": "^51.5.1",
28
27
  "@atlaskit/adf-utils": "^19.26.0",
29
28
  "@atlaskit/editor-json-transformer": "^8.31.0",
30
- "@atlaskit/editor-prosemirror": "7.0.0",
29
+ "@atlaskit/editor-prosemirror": "^7.2.0",
31
30
  "@atlaskit/node-data-provider": "^7.5.0",
32
31
  "@babel/runtime": "^7.0.0",
33
32
  "@compiled/react": "^0.18.6",
@@ -77,7 +76,7 @@
77
76
  }
78
77
  },
79
78
  "name": "@atlaskit/editor-synced-block-provider",
80
- "version": "2.15.2",
79
+ "version": "2.15.3",
81
80
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
82
81
  "author": "Atlassian Pty Ltd",
83
82
  "license": "Apache-2.0",