@atlaskit/editor-synced-block-provider 2.5.2 → 2.7.0

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 (56) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/hooks/useFetchSyncBlockData.js +60 -6
  3. package/dist/cjs/index.js +24 -5
  4. package/dist/cjs/providers/confluence/confluenceContentAPI.js +86 -73
  5. package/dist/cjs/providers/syncBlockProvider.js +60 -36
  6. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +24 -20
  7. package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +78 -17
  8. package/dist/cjs/store-manager/syncBlockStoreManager.js +46 -8
  9. package/dist/cjs/utils/errorHandling.js +13 -0
  10. package/dist/cjs/utils/utils.js +32 -1
  11. package/dist/es2019/hooks/useFetchSyncBlockData.js +35 -6
  12. package/dist/es2019/index.js +7 -6
  13. package/dist/es2019/providers/confluence/confluenceContentAPI.js +62 -40
  14. package/dist/es2019/providers/syncBlockProvider.js +15 -9
  15. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +16 -14
  16. package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +64 -12
  17. package/dist/es2019/store-manager/syncBlockStoreManager.js +34 -8
  18. package/dist/es2019/utils/errorHandling.js +7 -0
  19. package/dist/es2019/utils/utils.js +31 -0
  20. package/dist/esm/hooks/useFetchSyncBlockData.js +60 -6
  21. package/dist/esm/index.js +7 -6
  22. package/dist/esm/providers/confluence/confluenceContentAPI.js +79 -66
  23. package/dist/esm/providers/syncBlockProvider.js +60 -36
  24. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +21 -17
  25. package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +79 -18
  26. package/dist/esm/store-manager/syncBlockStoreManager.js +46 -8
  27. package/dist/esm/utils/errorHandling.js +7 -0
  28. package/dist/esm/utils/utils.js +31 -0
  29. package/dist/types/common/schema.d.ts +1 -1
  30. package/dist/types/hooks/useFetchSyncBlockData.d.ts +6 -3
  31. package/dist/types/index.d.ts +10 -9
  32. package/dist/types/providers/confluence/confluenceContentAPI.d.ts +2 -2
  33. package/dist/types/providers/syncBlockProvider.d.ts +4 -3
  34. package/dist/types/providers/types.d.ts +6 -2
  35. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +2 -1
  36. package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +15 -3
  37. package/dist/types/store-manager/syncBlockStoreManager.d.ts +22 -3
  38. package/dist/types/utils/errorHandling.d.ts +1 -0
  39. package/dist/types/utils/utils.d.ts +6 -1
  40. package/dist/types-ts4.5/common/schema.d.ts +1 -1
  41. package/dist/types-ts4.5/hooks/useFetchSyncBlockData.d.ts +6 -3
  42. package/dist/types-ts4.5/index.d.ts +10 -9
  43. package/dist/types-ts4.5/providers/confluence/confluenceContentAPI.d.ts +2 -2
  44. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +4 -3
  45. package/dist/types-ts4.5/providers/types.d.ts +6 -2
  46. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +2 -1
  47. package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +15 -3
  48. package/dist/types-ts4.5/store-manager/syncBlockStoreManager.d.ts +22 -3
  49. package/dist/types-ts4.5/utils/errorHandling.d.ts +1 -0
  50. package/dist/types-ts4.5/utils/utils.d.ts +6 -1
  51. package/package.json +2 -2
  52. package/dist/cjs/utils/createSyncBlock.js +0 -15
  53. package/dist/es2019/utils/createSyncBlock.js +0 -9
  54. package/dist/esm/utils/createSyncBlock.js +0 -9
  55. package/dist/types/utils/createSyncBlock.d.ts +0 -2
  56. package/dist/types-ts4.5/utils/createSyncBlock.d.ts +0 -2
@@ -11,8 +11,8 @@ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/
11
11
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
12
12
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
13
13
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
14
- var _createSyncBlock = require("../utils/createSyncBlock");
15
14
  var _resolveSyncBlockInstance = require("../utils/resolveSyncBlockInstance");
15
+ var _utils = require("../utils/utils");
16
16
  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; }
17
17
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
18
18
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
@@ -58,7 +58,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
58
58
  case 0:
59
59
  _step$value = (0, _slicedToArray2.default)(_step.value, 2), resourceId = _step$value[0], callbacks = _step$value[1];
60
60
  Object.keys(callbacks).forEach(function (localId) {
61
- syncBlocks.push((0, _createSyncBlock.createSyncBlockNode)(localId, resourceId));
61
+ syncBlocks.push((0, _utils.createSyncBlockNode)(localId, resourceId));
62
62
  });
63
63
  case 2:
64
64
  case "end":
@@ -124,7 +124,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
124
124
  // we could optimise this further by checking if the sync block is on the same page as the source
125
125
  if (!this.syncBlockURLRequests.get(resourceId)) {
126
126
  this.syncBlockURLRequests.set(resourceId, true);
127
- this.dataProvider.retrieveSyncBlockSourceUrlAndTitle((0, _createSyncBlock.createSyncBlockNode)('', resourceId)).then(function (sourceInfo) {
127
+ this.dataProvider.retrieveSyncBlockSourceUrlAndTitle((0, _utils.createSyncBlockNode)('', resourceId)).then(function (sourceInfo) {
128
128
  var existingSyncBlock = _this.getFromCache(resourceId);
129
129
  if (existingSyncBlock && existingSyncBlock.data) {
130
130
  existingSyncBlock.data = _objectSpread(_objectSpread({}, existingSyncBlock.data), {}, {
@@ -229,20 +229,9 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
229
229
  this.syncBlockCache.delete(resourceId);
230
230
  }
231
231
  }, {
232
- key: "subscribe",
233
- value: function subscribe(node, callback) {
232
+ key: "subscribeToSyncBlock",
233
+ value: function subscribeToSyncBlock(resourceId, localId, callback) {
234
234
  var _this3 = this;
235
- // check node is a sync block, as we only support sync block subscriptions
236
- if (node.type.name !== 'syncBlock') {
237
- return function () {};
238
- }
239
- var _node$attrs = node.attrs,
240
- resourceId = _node$attrs.resourceId,
241
- localId = _node$attrs.localId;
242
- if (!localId || !resourceId) {
243
- return function () {};
244
- }
245
-
246
235
  // add to subscriptions map
247
236
  var resourceSubscriptions = this.subscriptions.get(resourceId) || {};
248
237
  this.subscriptions.set(resourceId, _objectSpread(_objectSpread({}, resourceSubscriptions), {}, (0, _defineProperty2.default)({}, localId, callback)));
@@ -252,7 +241,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
252
241
  if (cachedData) {
253
242
  callback(cachedData);
254
243
  } else {
255
- this.fetchSyncBlocksData([(0, _createSyncBlock.createSyncBlockNode)(localId, resourceId)]).catch(function () {});
244
+ this.fetchSyncBlocksData([(0, _utils.createSyncBlockNode)(localId, resourceId)]).catch(function () {});
256
245
  }
257
246
  return function () {
258
247
  var resourceSubscriptions = _this3.subscriptions.get(resourceId);
@@ -276,9 +265,9 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
276
265
  if (node.type.name !== 'syncBlock') {
277
266
  return function () {};
278
267
  }
279
- var _node$attrs2 = node.attrs,
280
- resourceId = _node$attrs2.resourceId,
281
- localId = _node$attrs2.localId;
268
+ var _node$attrs = node.attrs,
269
+ resourceId = _node$attrs.resourceId,
270
+ localId = _node$attrs.localId;
282
271
  if (!localId || !resourceId) {
283
272
  return function () {};
284
273
  }
@@ -302,6 +291,21 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
302
291
  }
303
292
  };
304
293
  }
294
+ }, {
295
+ key: "subscribe",
296
+ value: function subscribe(node, callback) {
297
+ // check node is a sync block, as we only support sync block subscriptions
298
+ if (node.type.name !== 'syncBlock') {
299
+ return function () {};
300
+ }
301
+ var _node$attrs2 = node.attrs,
302
+ resourceId = _node$attrs2.resourceId,
303
+ localId = _node$attrs2.localId;
304
+ if (!localId || !resourceId) {
305
+ return function () {};
306
+ }
307
+ return this.subscribeToSyncBlock(resourceId, localId, callback);
308
+ }
305
309
 
306
310
  /**
307
311
  * Get the URL for a sync block.
@@ -47,7 +47,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
47
47
  key: "flushBodiedSyncBlocks",
48
48
  value: (function () {
49
49
  var _flushBodiedSyncBlocks = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
50
- var bodiedSyncBlockNodes, bodiedSyncBlockData, resourceIds;
50
+ var bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults;
51
51
  return _regenerator.default.wrap(function _callee$(_context) {
52
52
  while (1) switch (_context.prev = _context.next) {
53
53
  case 0:
@@ -79,9 +79,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
79
79
  _context.next = 10;
80
80
  return this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
81
81
  case 10:
82
- resourceIds = _context.sent;
83
- return _context.abrupt("return", resourceIds.every(function (resourceId) {
84
- return resourceId !== undefined;
82
+ writeResults = _context.sent;
83
+ return _context.abrupt("return", writeResults.every(function (result) {
84
+ return result.resourceId !== undefined;
85
85
  }));
86
86
  case 14:
87
87
  _context.prev = 14;
@@ -103,6 +103,35 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
103
103
  value: function setEditorView(editorView) {
104
104
  this.editorView = editorView;
105
105
  }
106
+ }, {
107
+ key: "registerPendingCreation",
108
+ value: function registerPendingCreation(resourceId) {
109
+ this.pendingResourceId = resourceId;
110
+ }
111
+ }, {
112
+ key: "registerCreationCallback",
113
+ value: function registerCreationCallback(callback) {
114
+ this.creationCallback = callback;
115
+ }
116
+
117
+ /**
118
+ * Fires callback to insert node (if creation is successful) and clears pending creation data
119
+ * @param success
120
+ */
121
+ }, {
122
+ key: "commitPendingCreation",
123
+ value: function commitPendingCreation(success) {
124
+ if (success && this.creationCallback) {
125
+ this.creationCallback();
126
+ }
127
+ this.pendingResourceId = undefined;
128
+ this.creationCallback = undefined;
129
+ }
130
+ }, {
131
+ key: "hasPendingCreation",
132
+ value: function hasPendingCreation() {
133
+ return !!this.pendingResourceId;
134
+ }
106
135
  }, {
107
136
  key: "registerConfirmationCallback",
108
137
  value: function registerConfirmationCallback(callback) {
@@ -118,31 +147,63 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
118
147
  return !!this.confirmationCallback;
119
148
  }
120
149
  }, {
121
- key: "createSyncBlockNode",
122
- value: function createSyncBlockNode() {
150
+ key: "generateBodiedSyncBlockAttrs",
151
+ value: function generateBodiedSyncBlockAttrs() {
123
152
  var _this$dataProvider;
124
- var blockInstanceId = (0, _uuid.default)();
153
+ var localId = (0, _uuid.default)();
125
154
  var sourceId = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getSourceId();
126
155
  if (!sourceId) {
127
156
  throw new Error('Provider of sync block plugin is not set');
128
157
  }
129
158
 
130
159
  // This should be generated by the data provider implementation as it differs between data providers
131
- var resourceId = (0, _ari.resourceIdFromSourceAndLocalId)(sourceId, blockInstanceId);
132
- var syncBlockNode = {
133
- attrs: {
134
- resourceId: resourceId,
135
- localId: blockInstanceId
136
- },
137
- type: 'bodiedSyncBlock'
160
+ var resourceId = (0, _ari.resourceIdFromSourceAndLocalId)(sourceId, localId);
161
+ return {
162
+ resourceId: resourceId,
163
+ localId: localId
138
164
  };
139
- return syncBlockNode;
165
+ }
166
+ }, {
167
+ key: "createBodiedSyncBlockNode",
168
+ value: function createBodiedSyncBlockNode(attrs) {
169
+ var _this2 = this;
170
+ try {
171
+ if (!this.dataProvider) {
172
+ throw new Error('Data provider not set');
173
+ }
174
+ var resourceId = attrs.resourceId,
175
+ blockInstanceId = attrs.localId;
176
+ this.dataProvider.writeNodesData([(0, _utils.createBodiedSyncBlockNode)(blockInstanceId, resourceId)], [{
177
+ content: [],
178
+ blockInstanceId: blockInstanceId,
179
+ resourceId: resourceId
180
+ }]).then(function (results) {
181
+ results.forEach(function (result) {
182
+ var resourceId = result.resourceId;
183
+ if (resourceId) {
184
+ _this2.commitPendingCreation(true);
185
+ } else {
186
+ _this2.commitPendingCreation(false);
187
+ // TODO: EDITOR-1921 - add error analytics
188
+ }
189
+ });
190
+ }).catch(function (_reason) {
191
+ _this2.commitPendingCreation(false);
192
+ // TODO: EDITOR-1921 - add error analytics
193
+ });
194
+ this.registerPendingCreation(resourceId);
195
+ } catch (error) {
196
+ if (this.hasPendingCreation()) {
197
+ this.commitPendingCreation(false);
198
+ }
199
+ // TODO: EDITOR-1921 - add error analytics
200
+ }
140
201
  }
141
202
  }, {
142
203
  key: "deleteSyncBlocksWithConfirmation",
143
204
  value: function () {
144
205
  var _deleteSyncBlocksWithConfirmation = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(tr, syncBlockIds) {
145
- var _this2 = this;
206
+ var _this3 = this;
146
207
  var confirmed, _this$editorView, results;
147
208
  return _regenerator.default.wrap(function _callee2$(_context2) {
148
209
  while (1) switch (_context2.prev = _context2.next) {
@@ -177,7 +238,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
177
238
  results.forEach(function (result) {
178
239
  if (result.success) {
179
240
  // Only delete when it's deleted successfully in backend
180
- _this2.syncBlockCache.delete(result.resourceId);
241
+ _this3.syncBlockCache.delete(result.resourceId);
181
242
  } else {
182
243
  // TODO: EDITOR-1921 - add error analytics with result.error
183
244
  }
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.SyncBlockStoreManager = void 0;
8
8
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
9
9
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
- var _createSyncBlock = require("../utils/createSyncBlock");
10
+ var _utils = require("../utils/utils");
11
11
  var _referenceSyncBlockStoreManager = require("./referenceSyncBlockStoreManager");
12
12
  var _sourceSyncBlockStoreManager = require("./sourceSyncBlockStoreManager");
13
13
  // A store manager responsible for the lifecycle and state management of sync blocks in an editor instance.
@@ -30,16 +30,21 @@ var SyncBlockStoreManager = exports.SyncBlockStoreManager = /*#__PURE__*/functio
30
30
  return (0, _createClass2.default)(SyncBlockStoreManager, [{
31
31
  key: "fetchSyncBlocksData",
32
32
  value: function fetchSyncBlocksData(nodes) {
33
- var syncBlockNodes = nodes.filter(function (node) {
34
- return node.type.name === 'syncBlock' && node.attrs.resourceId && node.attrs.localId;
35
- }).map(function (node) {
36
- return (0, _createSyncBlock.createSyncBlockNode)(node.attrs.localId, node.attrs.resourceId);
33
+ var syncBlockNodes = nodes.map(function (node) {
34
+ return (0, _utils.convertPMNodeToSyncBlockNode)(node);
35
+ }).filter(function (node) {
36
+ return node !== undefined;
37
37
  }) || [];
38
38
  if (syncBlockNodes.length === 0) {
39
39
  return Promise.resolve([]);
40
40
  }
41
41
  return this.referenceSyncBlockStoreManager.fetchSyncBlocksData(syncBlockNodes);
42
42
  }
43
+ }, {
44
+ key: "getReferenceSyncBlockStoreManager",
45
+ value: function getReferenceSyncBlockStoreManager() {
46
+ return this.referenceSyncBlockStoreManager;
47
+ }
43
48
 
44
49
  /**
45
50
  * Add/update a sync block node to/from the local cache
@@ -100,11 +105,44 @@ var SyncBlockStoreManager = exports.SyncBlockStoreManager = /*#__PURE__*/functio
100
105
  // only applicable to source sync block, for now (will be refactored further)
101
106
  return this.sourceSyncBlockStoreManager.requireConfirmationBeforeDelete();
102
107
  }
108
+
109
+ /**
110
+ * Register callback function (which inserts node, handles focus etc) to be used later when creation to backend succeed
111
+ */
112
+ }, {
113
+ key: "registerCreationCallback",
114
+ value: function registerCreationCallback(callback) {
115
+ this.sourceSyncBlockStoreManager.registerCreationCallback(callback);
116
+ }
117
+
118
+ /**
119
+ *
120
+ * @returns true if waiting for the result of saving new bodiedSyncBlock to backend
121
+ */
122
+ }, {
123
+ key: "hasPendingCreation",
124
+ value: function hasPendingCreation() {
125
+ return this.sourceSyncBlockStoreManager.hasPendingCreation();
126
+ }
127
+
128
+ /**
129
+ * @returns attributes for a new bodiedSyncBlock node
130
+ */
131
+ }, {
132
+ key: "generateBodiedSyncBlockAttrs",
133
+ value: function generateBodiedSyncBlockAttrs() {
134
+ return this.sourceSyncBlockStoreManager.generateBodiedSyncBlockAttrs();
135
+ }
136
+
137
+ /**
138
+ * Save bodiedSyncBlock with empty content to backend
139
+ * @param attrs attributes Ids of the node
140
+ */
103
141
  }, {
104
- key: "createSyncBlockNode",
105
- value: function createSyncBlockNode() {
142
+ key: "createBodiedSyncBlockNode",
143
+ value: function createBodiedSyncBlockNode(attrs) {
106
144
  // only applicable to source sync block, for now (will be refactored further)
107
- return this.sourceSyncBlockStoreManager.createSyncBlockNode();
145
+ return this.sourceSyncBlockStoreManager.createBodiedSyncBlockNode(attrs);
108
146
  }
109
147
  }, {
110
148
  key: "subscribeToSyncBlockData",
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.stringifyError = void 0;
7
+ var stringifyError = exports.stringifyError = function stringifyError(error) {
8
+ try {
9
+ return JSON.stringify(error);
10
+ } catch (_unused) {
11
+ return undefined;
12
+ }
13
+ };
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isBlogPageType = exports.convertSyncBlockPMNodeToSyncBlockData = void 0;
6
+ exports.isBlogPageType = exports.createSyncBlockNode = exports.createBodiedSyncBlockNode = exports.convertSyncBlockPMNodeToSyncBlockData = exports.convertSyncBlockJSONNodeToSyncBlockNode = exports.convertPMNodeToSyncBlockNode = void 0;
7
7
  var convertSyncBlockPMNodeToSyncBlockData = exports.convertSyncBlockPMNodeToSyncBlockData = function convertSyncBlockPMNodeToSyncBlockData(node) {
8
8
  return {
9
9
  blockInstanceId: node.attrs.localId,
@@ -13,4 +13,35 @@ var convertSyncBlockPMNodeToSyncBlockData = exports.convertSyncBlockPMNodeToSync
13
13
  };
14
14
  var isBlogPageType = exports.isBlogPageType = function isBlogPageType(pageType) {
15
15
  return pageType === 'blogpost';
16
+ };
17
+ var createSyncBlockNode = exports.createSyncBlockNode = function createSyncBlockNode(localId, resourceId) {
18
+ return {
19
+ type: 'syncBlock',
20
+ attrs: {
21
+ localId: localId,
22
+ resourceId: resourceId
23
+ }
24
+ };
25
+ };
26
+ var createBodiedSyncBlockNode = exports.createBodiedSyncBlockNode = function createBodiedSyncBlockNode(localId, resourceId) {
27
+ return {
28
+ type: 'bodiedSyncBlock',
29
+ attrs: {
30
+ localId: localId,
31
+ resourceId: resourceId
32
+ }
33
+ };
34
+ };
35
+ var convertSyncBlockJSONNodeToSyncBlockNode = exports.convertSyncBlockJSONNodeToSyncBlockNode = function convertSyncBlockJSONNodeToSyncBlockNode(node) {
36
+ if (node.type !== 'syncBlock' || !node.attrs || !('localId' in node.attrs) || !('resourceId' in node.attrs) || typeof node.attrs.localId !== 'string' || typeof node.attrs.resourceId !== 'string') {
37
+ return undefined;
38
+ }
39
+ return createSyncBlockNode(node.attrs.localId, node.attrs.resourceId);
40
+ };
41
+ var convertPMNodeToSyncBlockNode = exports.convertPMNodeToSyncBlockNode = function convertPMNodeToSyncBlockNode(node) {
42
+ var _node$attrs, _node$attrs2;
43
+ if (node.type.name !== 'syncBlock' || !((_node$attrs = node.attrs) !== null && _node$attrs !== void 0 && _node$attrs.localId) || !((_node$attrs2 = node.attrs) !== null && _node$attrs2 !== void 0 && _node$attrs2.resourceId) || typeof node.attrs.localId !== 'string' || typeof node.attrs.resourceId !== 'string') {
44
+ return undefined;
45
+ }
46
+ return createSyncBlockNode(node.attrs.localId, node.attrs.resourceId);
16
47
  };
@@ -1,14 +1,43 @@
1
- import { useEffect, useState } from 'react';
2
- export const SYNC_BLOCK_FETCH_INTERVAL = 3000;
3
- export const useFetchSyncBlockData = (manager, syncBlockNode) => {
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { SyncBlockError } from '../common/types';
3
+ import { createSyncBlockNode } from '../utils/utils';
4
+ export const useFetchSyncBlockData = (manager, resourceId, localId) => {
4
5
  const [syncBlockInstance, setSyncBlockInstance] = useState(null);
6
+ const [isLoading, setIsLoading] = useState(true);
7
+ const referenceSyncBlockStoreManager = manager.getReferenceSyncBlockStoreManager();
8
+ const reloadData = useCallback(async () => {
9
+ if (isLoading) {
10
+ return;
11
+ }
12
+ const syncBlockNode = resourceId && localId ? createSyncBlockNode(localId, resourceId) : null;
13
+ if (!syncBlockNode) {
14
+ return;
15
+ }
16
+ setIsLoading(true);
17
+ try {
18
+ // Fetch sync block data, the `subscribeToSyncBlock` will update the state once data is fetched
19
+ await referenceSyncBlockStoreManager.fetchSyncBlocksData([syncBlockNode]);
20
+ } catch (error) {
21
+ // Set error state if fetching fails
22
+ setSyncBlockInstance({
23
+ resourceId: resourceId || '',
24
+ error: SyncBlockError.Errored
25
+ });
26
+ }
27
+ setIsLoading(false);
28
+ }, [isLoading, localId, referenceSyncBlockStoreManager, resourceId]);
5
29
  useEffect(() => {
6
- const unsubscribe = manager.subscribeToSyncBlockData(syncBlockNode, data => {
30
+ const unsubscribe = referenceSyncBlockStoreManager.subscribeToSyncBlock(resourceId || '', localId || '', data => {
7
31
  setSyncBlockInstance(data);
32
+ setIsLoading(false);
8
33
  });
9
34
  return () => {
10
35
  unsubscribe();
11
36
  };
12
- }, [manager, syncBlockNode]);
13
- return syncBlockInstance;
37
+ }, [localId, referenceSyncBlockStoreManager, resourceId]);
38
+ return {
39
+ syncBlockInstance,
40
+ isLoading,
41
+ reloadData
42
+ };
14
43
  };
@@ -1,14 +1,15 @@
1
1
  /* eslint-disable @atlaskit/editor/no-re-export */
2
2
 
3
- export { SyncBlockProvider as SyncedBlockProvider, useMemoizedSyncedBlockProvider } from './providers/syncBlockProvider';
4
- export { SyncBlockStoreManager } from './store-manager/syncBlockStoreManager';
3
+ export { rebaseTransaction } from './common/rebase-transaction';
4
+ export { getDefaultSyncBlockSchema } from './common/schema';
5
+ export { SyncBlockError } from './common/types';
5
6
  export { useFetchSyncBlockData } from './hooks/useFetchSyncBlockData';
6
7
  export { useFetchSyncBlockTitle } from './hooks/useFetchSyncBlockTitle';
7
8
  export { useHandleContentChanges } from './hooks/useHandleContentChanges';
8
- export { SyncBlockError } from './common/types';
9
- export { getDefaultSyncBlockSchema } from './common/schema';
10
9
  export { createContentAPIProvidersWithDefaultKey, useMemoizedContentAPIProviders } from './providers/confluence/confluenceContentAPI';
10
+ export { SyncBlockProvider as SyncedBlockProvider, useMemoizedSyncedBlockProvider } from './providers/syncBlockProvider';
11
+ export { ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
12
+ export { SyncBlockStoreManager } from './store-manager/syncBlockStoreManager';
11
13
  export { getConfluencePageAri, getPageIdAndTypeFromAri } from './utils/ari';
12
- export { convertSyncBlockPMNodeToSyncBlockData } from './utils/utils';
13
- export { rebaseTransaction } from './common/rebase-transaction';
14
+ export { createSyncBlockNode, convertSyncBlockPMNodeToSyncBlockData, convertSyncBlockJSONNodeToSyncBlockNode } from './utils/utils';
14
15
  export { resolveSyncBlockInstance } from './utils/resolveSyncBlockInstance';
@@ -3,6 +3,7 @@ import { useMemo } from 'react';
3
3
  import { SyncBlockError } from '../../common/types';
4
4
  import { getLocalIdFromAri, getPageIdAndTypeFromAri } from '../../utils/ari';
5
5
  import { getContentProperty, createContentProperty, updateContentProperty, deleteContentProperty } from '../../utils/contentProperty';
6
+ import { stringifyError } from '../../utils/errorHandling';
6
7
  import { isBlogPageType } from '../../utils/utils';
7
8
 
8
9
  /**
@@ -118,7 +119,7 @@ class ConfluenceADFWriteProvider {
118
119
  if (((_contentProperty$data7 = contentProperty.data.confluence.createBlogPostProperty.blogPostProperty) === null || _contentProperty$data7 === void 0 ? void 0 : _contentProperty$data7.key) === key) {
119
120
  return key;
120
121
  } else {
121
- throw new Error('Failed to create blog post content property');
122
+ return Promise.reject('Failed to create blog post content property');
122
123
  }
123
124
  } else {
124
125
  var _contentProperty$data8;
@@ -126,20 +127,31 @@ class ConfluenceADFWriteProvider {
126
127
  if (((_contentProperty$data8 = contentProperty.data.confluence.createPageProperty.pageProperty) === null || _contentProperty$data8 === void 0 ? void 0 : _contentProperty$data8.key) === key) {
127
128
  return key;
128
129
  } else {
129
- throw new Error('Failed to create page content property');
130
+ return Promise.reject('Failed to create page content property');
130
131
  }
131
132
  }
132
133
  });
133
134
  this.config = config;
134
135
  }
135
136
  async writeData(data) {
137
+ let match;
138
+ const {
139
+ resourceId
140
+ } = data;
141
+ try {
142
+ match = getPageIdAndTypeFromAri(data.resourceId);
143
+ } catch (error) {
144
+ return {
145
+ error: stringifyError(error)
146
+ };
147
+ }
136
148
  const {
137
149
  id: pageId,
138
150
  type: pageType
139
- } = getPageIdAndTypeFromAri(data.resourceId);
140
- if (data.resourceId) {
151
+ } = match;
152
+ try {
141
153
  // Update existing content property
142
- const localId = getLocalIdFromAri(data.resourceId);
154
+ const localId = getLocalIdFromAri(resourceId);
143
155
  const key = getContentPropertyKey(this.config.contentPropertyKey, localId);
144
156
  const options = {
145
157
  pageId,
@@ -148,55 +160,65 @@ class ConfluenceADFWriteProvider {
148
160
  cloudId: this.config.cloudId,
149
161
  pageType
150
162
  };
151
- if (isBlogPageType(pageType)) {
152
- var _contentProperty$data9;
153
- const contentProperty = await updateContentProperty(options);
154
- if (((_contentProperty$data9 = contentProperty.data.confluence.updateValueBlogPostProperty.blogPostProperty) === null || _contentProperty$data9 === void 0 ? void 0 : _contentProperty$data9.key) === key) {
155
- return key;
156
- } else if (contentProperty.data.confluence.updateValueBlogPostProperty.blogPostProperty === null) {
157
- return this.createNewContentProperty(pageId, key, data, pageType);
158
- } else {
159
- throw new Error('Failed to update blog post content property');
160
- }
163
+ const updatePayload = await updateContentProperty(options);
164
+ const updateResult = isBlogPageType(pageType) ? updatePayload.data.confluence.updateValueBlogPostProperty.blogPostProperty : updatePayload.data.confluence.updateValuePageProperty.pageProperty;
165
+ if ((updateResult === null || updateResult === void 0 ? void 0 : updateResult.key) === key) {
166
+ return {
167
+ resourceId
168
+ };
169
+ } else if (!updateResult) {
170
+ return this.createNewContentProperty(pageId, key, data, pageType).then(() => {
171
+ return {
172
+ resourceId
173
+ };
174
+ }, error => {
175
+ return {
176
+ error
177
+ };
178
+ });
161
179
  } else {
162
- var _contentProperty$data0;
163
- const contentProperty = await updateContentProperty(options);
164
- if (((_contentProperty$data0 = contentProperty.data.confluence.updateValuePageProperty.pageProperty) === null || _contentProperty$data0 === void 0 ? void 0 : _contentProperty$data0.key) === key) {
165
- return key;
166
- } else if (contentProperty.data.confluence.updateValuePageProperty.pageProperty === null) {
167
- return this.createNewContentProperty(pageId, key, data, pageType);
168
- } else {
169
- throw new Error('Failed to update content property');
170
- }
180
+ return {
181
+ error: `Failed to update ${pageType} content property`
182
+ };
171
183
  }
172
- } else {
173
- // Create new content property
174
- const key = getContentPropertyKey(this.config.contentPropertyKey, data.blockInstanceId);
175
- return this.createNewContentProperty(pageId, key, data, pageType);
184
+ } catch {
185
+ return {
186
+ error: `Failed to write ${pageType}`
187
+ };
176
188
  }
177
189
  }
178
190
  async deleteData(resourceId) {
191
+ let deletePayload, deleteResult, match;
192
+ try {
193
+ match = getPageIdAndTypeFromAri(resourceId);
194
+ } catch (error) {
195
+ return {
196
+ resourceId,
197
+ success: false,
198
+ error: stringifyError(error)
199
+ };
200
+ }
179
201
  const {
180
202
  id: pageId,
181
203
  type: pageType
182
- } = getPageIdAndTypeFromAri(resourceId);
183
- const localId = getLocalIdFromAri(resourceId);
184
- const key = getContentPropertyKey(this.config.contentPropertyKey, localId);
185
- const options = {
186
- pageId,
187
- key,
188
- cloudId: this.config.cloudId,
189
- pageType
190
- };
191
- let deletePayload, deleteResult;
204
+ } = match;
192
205
  try {
206
+ const localId = getLocalIdFromAri(resourceId);
207
+ const key = getContentPropertyKey(this.config.contentPropertyKey, localId);
208
+ const options = {
209
+ pageId,
210
+ key,
211
+ cloudId: this.config.cloudId,
212
+ pageType
213
+ };
193
214
  deletePayload = await deleteContentProperty(options);
194
215
  deleteResult = isBlogPageType(pageType) ? deletePayload.data.confluence.deleteBlogPostProperty : deletePayload.data.confluence.deletePageProperty;
195
- } catch {
216
+ } catch (error) {
217
+ var _stringifyError;
196
218
  return {
197
219
  resourceId,
198
220
  success: false,
199
- error: `Fail to delete ${pageType} content property`
221
+ error: (_stringifyError = stringifyError(error)) !== null && _stringifyError !== void 0 ? _stringifyError : `Fail to delete ${pageType} content property`
200
222
  };
201
223
  }
202
224
  return {
@@ -41,19 +41,25 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
41
41
  * @param nodes
42
42
  * @param data
43
43
  *
44
- * @returns the resource ids of the nodes that were written
44
+ * @returns Array of {resourceId?: string, error?: string}.
45
+ * resourceId: resource id of the node if write successfully , error: reason for when write failed
45
46
  */
46
- writeNodesData(nodes, data) {
47
- const resourceIds = [];
48
- nodes.forEach((_node, index) => {
47
+ async writeNodesData(nodes, data) {
48
+ const results = await Promise.allSettled(nodes.map((_node, index) => {
49
49
  if (!data[index].content) {
50
- resourceIds.push(Promise.reject('No Synced Block content to write'));
51
- return;
50
+ return Promise.reject('No Synced Block content to write');
51
+ }
52
+ return this.writeProvider.writeData(data[index]);
53
+ }));
54
+ return results.map(result => {
55
+ if (result.status === 'fulfilled') {
56
+ return result.value;
57
+ } else {
58
+ return {
59
+ error: result.reason
60
+ };
52
61
  }
53
- const resourceId = this.writeProvider.writeData(data[index]);
54
- resourceIds.push(resourceId);
55
62
  });
56
- return Promise.all(resourceIds);
57
63
  }
58
64
  async deleteNodesData(resourceIds) {
59
65
  const results = await Promise.allSettled(resourceIds.map(resourceId => this.writeProvider.deleteData(resourceId)));