@atlaskit/editor-synced-block-provider 2.6.0 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/hooks/useFetchSyncBlockData.js +2 -2
  3. package/dist/cjs/index.js +9 -4
  4. package/dist/cjs/providers/confluence/confluenceContentAPI.js +86 -73
  5. package/dist/cjs/providers/syncBlockProvider.js +52 -75
  6. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +7 -7
  7. package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +78 -17
  8. package/dist/cjs/store-manager/syncBlockStoreManager.js +41 -8
  9. package/dist/cjs/utils/errorHandling.js +13 -0
  10. package/dist/cjs/utils/sourceInfo.js +119 -0
  11. package/dist/cjs/utils/utils.js +32 -1
  12. package/dist/es2019/hooks/useFetchSyncBlockData.js +1 -1
  13. package/dist/es2019/index.js +2 -3
  14. package/dist/es2019/providers/confluence/confluenceContentAPI.js +62 -40
  15. package/dist/es2019/providers/syncBlockProvider.js +18 -37
  16. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +4 -4
  17. package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +64 -12
  18. package/dist/es2019/store-manager/syncBlockStoreManager.js +31 -8
  19. package/dist/es2019/utils/errorHandling.js +7 -0
  20. package/dist/es2019/utils/sourceInfo.js +89 -0
  21. package/dist/es2019/utils/utils.js +31 -0
  22. package/dist/esm/hooks/useFetchSyncBlockData.js +1 -1
  23. package/dist/esm/index.js +2 -3
  24. package/dist/esm/providers/confluence/confluenceContentAPI.js +79 -66
  25. package/dist/esm/providers/syncBlockProvider.js +52 -75
  26. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +5 -5
  27. package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +79 -18
  28. package/dist/esm/store-manager/syncBlockStoreManager.js +41 -8
  29. package/dist/esm/utils/errorHandling.js +7 -0
  30. package/dist/esm/utils/sourceInfo.js +114 -0
  31. package/dist/esm/utils/utils.js +31 -0
  32. package/dist/types/index.d.ts +1 -2
  33. package/dist/types/providers/confluence/confluenceContentAPI.d.ts +2 -2
  34. package/dist/types/providers/syncBlockProvider.d.ts +5 -4
  35. package/dist/types/providers/types.d.ts +7 -3
  36. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +1 -1
  37. package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +15 -3
  38. package/dist/types/store-manager/syncBlockStoreManager.d.ts +20 -3
  39. package/dist/types/utils/errorHandling.d.ts +1 -0
  40. package/dist/types/utils/sourceInfo.d.ts +2 -0
  41. package/dist/types/utils/utils.d.ts +6 -1
  42. package/dist/types-ts4.5/index.d.ts +1 -2
  43. package/dist/types-ts4.5/providers/confluence/confluenceContentAPI.d.ts +2 -2
  44. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +5 -4
  45. package/dist/types-ts4.5/providers/types.d.ts +7 -3
  46. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +1 -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 +20 -3
  49. package/dist/types-ts4.5/utils/errorHandling.d.ts +1 -0
  50. package/dist/types-ts4.5/utils/sourceInfo.d.ts +2 -0
  51. package/dist/types-ts4.5/utils/utils.d.ts +6 -1
  52. package/package.json +2 -2
  53. package/dist/cjs/utils/createSyncBlock.js +0 -15
  54. package/dist/es2019/utils/createSyncBlock.js +0 -9
  55. package/dist/esm/utils/createSyncBlock.js +0 -9
  56. package/dist/types/utils/createSyncBlock.d.ts +0 -2
  57. package/dist/types-ts4.5/utils/createSyncBlock.d.ts +0 -2
@@ -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,10 +30,10 @@ 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([]);
@@ -105,11 +105,44 @@ var SyncBlockStoreManager = exports.SyncBlockStoreManager = /*#__PURE__*/functio
105
105
  // only applicable to source sync block, for now (will be refactored further)
106
106
  return this.sourceSyncBlockStoreManager.requireConfirmationBeforeDelete();
107
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
+ */
108
141
  }, {
109
- key: "createSyncBlockNode",
110
- value: function createSyncBlockNode() {
142
+ key: "createBodiedSyncBlockNode",
143
+ value: function createBodiedSyncBlockNode(attrs) {
111
144
  // only applicable to source sync block, for now (will be refactored further)
112
- return this.sourceSyncBlockStoreManager.createSyncBlockNode();
145
+ return this.sourceSyncBlockStoreManager.createBodiedSyncBlockNode(attrs);
113
146
  }
114
147
  }, {
115
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
+ };
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.fetchSourceInfo = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
+ var _ari = require("./ari");
12
+ var _utils = require("./utils");
13
+ 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; }
14
+ 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; } /* eslint-disable require-unicode-regexp */
15
+ var COMMON_HEADERS = {
16
+ 'Content-Type': 'application/json',
17
+ Accept: 'application/json'
18
+ };
19
+ var AGG_HEADERS = {
20
+ 'X-ExperimentalApi': 'confluence-agg-beta'
21
+ };
22
+ var GRAPHQL_ENDPOINT = '/gateway/api/graphql';
23
+ var GET_SOURCE_INFO_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_GET_SOURCE_INFO';
24
+ /**
25
+ * Query to get the page subtype by id (i.e. live or classic)
26
+ * @param documentARI
27
+ * @returns subType live if livePage, subType null if classic page
28
+ */
29
+ var GET_SOURCE_INFO_QUERY = "query ".concat(GET_SOURCE_INFO_OPERATION_NAME, " ($id: ID!) {\n\tcontent (id: $id) {\n\t\tnodes {\n\t\t\tid\n\t\t\tlinks {\n\t\t\t\tbase\n\t\t\t}\n\t\t\tspace {\n\t\t\t\tkey\n\t\t\t}\n\t\t\tsubType\n\t\t\ttitle\n\t\t}\n\t}\n}");
30
+ var getSourceInfo = /*#__PURE__*/function () {
31
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(ari) {
32
+ var bodyData, response;
33
+ return _regenerator.default.wrap(function _callee$(_context) {
34
+ while (1) switch (_context.prev = _context.next) {
35
+ case 0:
36
+ bodyData = {
37
+ query: GET_SOURCE_INFO_QUERY,
38
+ operationName: GET_SOURCE_INFO_OPERATION_NAME,
39
+ variables: {
40
+ id: ari
41
+ }
42
+ };
43
+ _context.next = 3;
44
+ return fetch(GRAPHQL_ENDPOINT, {
45
+ method: 'POST',
46
+ headers: _objectSpread(_objectSpread({}, COMMON_HEADERS), AGG_HEADERS),
47
+ body: JSON.stringify(bodyData)
48
+ });
49
+ case 3:
50
+ response = _context.sent;
51
+ if (response.ok) {
52
+ _context.next = 6;
53
+ break;
54
+ }
55
+ throw new Error("Failed to get url: ".concat(response.statusText));
56
+ case 6:
57
+ _context.next = 8;
58
+ return response.json();
59
+ case 8:
60
+ return _context.abrupt("return", _context.sent);
61
+ case 9:
62
+ case "end":
63
+ return _context.stop();
64
+ }
65
+ }, _callee);
66
+ }));
67
+ return function getSourceInfo(_x) {
68
+ return _ref.apply(this, arguments);
69
+ };
70
+ }();
71
+ var fetchSourceInfo = exports.fetchSourceInfo = /*#__PURE__*/function () {
72
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(ari, localId) {
73
+ var _response$data, _contentData$space, _getPageIdAndTypeFrom, pageType, response, contentData, title, url, _ref3, base;
74
+ return _regenerator.default.wrap(function _callee2$(_context2) {
75
+ while (1) switch (_context2.prev = _context2.next) {
76
+ case 0:
77
+ _context2.prev = 0;
78
+ _getPageIdAndTypeFrom = (0, _ari.getPageIdAndTypeFromAri)(ari), pageType = _getPageIdAndTypeFrom.type;
79
+ _context2.next = 4;
80
+ return getSourceInfo(ari);
81
+ case 4:
82
+ response = _context2.sent;
83
+ contentData = (_response$data = response.data) === null || _response$data === void 0 || (_response$data = _response$data.content) === null || _response$data === void 0 || (_response$data = _response$data.nodes) === null || _response$data === void 0 ? void 0 : _response$data[0];
84
+ if (contentData) {
85
+ _context2.next = 8;
86
+ break;
87
+ }
88
+ throw new Error("Failed to get content data");
89
+ case 8:
90
+ title = contentData.title;
91
+ _ref3 = contentData.links || {}, base = _ref3.base;
92
+ if (base && (_contentData$space = contentData.space) !== null && _contentData$space !== void 0 && _contentData$space.key && contentData.id) {
93
+ if ((0, _utils.isBlogPageType)(pageType)) {
94
+ url = "".concat(base, "/spaces/").concat(contentData.space.key, "/blog/edit-v2/").concat(contentData.id);
95
+ } else if (contentData.subType === 'live') {
96
+ url = "".concat(base, "/spaces/").concat(contentData.space.key, "/pages/").concat(contentData.id);
97
+ } else {
98
+ url = "".concat(base, "/spaces/").concat(contentData.space.key, "/pages/edit-v2/").concat(contentData.id);
99
+ }
100
+ }
101
+ url = url && localId ? "".concat(url, "#block-").concat(localId) : url;
102
+ return _context2.abrupt("return", Promise.resolve({
103
+ title: title,
104
+ url: url
105
+ }));
106
+ case 15:
107
+ _context2.prev = 15;
108
+ _context2.t0 = _context2["catch"](0);
109
+ return _context2.abrupt("return", Promise.resolve(undefined));
110
+ case 18:
111
+ case "end":
112
+ return _context2.stop();
113
+ }
114
+ }, _callee2, null, [[0, 15]]);
115
+ }));
116
+ return function fetchSourceInfo(_x2, _x3) {
117
+ return _ref2.apply(this, arguments);
118
+ };
119
+ }();
@@ -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,6 +1,6 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
2
  import { SyncBlockError } from '../common/types';
3
- import { createSyncBlockNode } from '../utils/createSyncBlock';
3
+ import { createSyncBlockNode } from '../utils/utils';
4
4
  export const useFetchSyncBlockData = (manager, resourceId, localId) => {
5
5
  const [syncBlockInstance, setSyncBlockInstance] = useState(null);
6
6
  const [isLoading, setIsLoading] = useState(true);
@@ -11,6 +11,5 @@ export { SyncBlockProvider as SyncedBlockProvider, useMemoizedSyncedBlockProvide
11
11
  export { ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
12
12
  export { SyncBlockStoreManager } from './store-manager/syncBlockStoreManager';
13
13
  export { getConfluencePageAri, getPageIdAndTypeFromAri } from './utils/ari';
14
- export { createSyncBlockNode } from './utils/createSyncBlock';
15
- export { resolveSyncBlockInstance } from './utils/resolveSyncBlockInstance';
16
- export { convertSyncBlockPMNodeToSyncBlockData } from './utils/utils';
14
+ export { createSyncBlockNode, convertSyncBlockPMNodeToSyncBlockData, convertSyncBlockJSONNodeToSyncBlockNode } from './utils/utils';
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 {
@@ -3,6 +3,7 @@ import { useMemo } from 'react';
3
3
  import { SyncBlockError } from '../common/types';
4
4
  import { SyncBlockDataProvider } from '../providers/types';
5
5
  import { getLocalIdFromAri, getPageARIFromResourceId } from '../utils/ari';
6
+ import { fetchSourceInfo } from '../utils/sourceInfo';
6
7
  export class SyncBlockProvider extends SyncBlockDataProvider {
7
8
  constructor(fetchProvider, writeProvider, sourceId) {
8
9
  super();
@@ -41,19 +42,25 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
41
42
  * @param nodes
42
43
  * @param data
43
44
  *
44
- * @returns the resource ids of the nodes that were written
45
+ * @returns Array of {resourceId?: string, error?: string}.
46
+ * resourceId: resource id of the node if write successfully , error: reason for when write failed
45
47
  */
46
- writeNodesData(nodes, data) {
47
- const resourceIds = [];
48
- nodes.forEach((_node, index) => {
48
+ async writeNodesData(nodes, data) {
49
+ const results = await Promise.allSettled(nodes.map((_node, index) => {
49
50
  if (!data[index].content) {
50
- resourceIds.push(Promise.reject('No Synced Block content to write'));
51
- return;
51
+ return Promise.reject('No Synced Block content to write');
52
+ }
53
+ return this.writeProvider.writeData(data[index]);
54
+ }));
55
+ return results.map(result => {
56
+ if (result.status === 'fulfilled') {
57
+ return result.value;
58
+ } else {
59
+ return {
60
+ error: result.reason
61
+ };
52
62
  }
53
- const resourceId = this.writeProvider.writeData(data[index]);
54
- resourceIds.push(resourceId);
55
63
  });
56
- return Promise.all(resourceIds);
57
64
  }
58
65
  async deleteNodesData(resourceIds) {
59
66
  const results = await Promise.allSettled(resourceIds.map(resourceId => this.writeProvider.deleteData(resourceId)));
@@ -72,7 +79,7 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
72
79
  getSourceId() {
73
80
  return this.sourceId;
74
81
  }
75
- retrieveSyncBlockSourceUrlAndTitle(node) {
82
+ retrieveSyncBlockSourceInfo(node) {
76
83
  const {
77
84
  resourceId
78
85
  } = node.attrs;
@@ -90,37 +97,11 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
90
97
  // EDITOR-1921: log analytic here, safe to continue
91
98
  }
92
99
  }
93
- return pageARI ? fetchURLandTitlefromARI(pageARI, sourceLocalId) : Promise.resolve(undefined);
100
+ return pageARI ? fetchSourceInfo(pageARI, sourceLocalId) : Promise.resolve(undefined);
94
101
  }
95
102
  }
96
103
  export const useMemoizedSyncedBlockProvider = (fetchProvider, writeProvider, sourceId) => {
97
104
  return useMemo(() => {
98
105
  return new SyncBlockProvider(fetchProvider, writeProvider, sourceId);
99
106
  }, [fetchProvider, writeProvider, sourceId]);
100
- };
101
- const fetchURLandTitlefromARI = async (ari, sourceLocalId) => {
102
- const response = await fetch('/gateway/api/object-resolver/resolve/ari', {
103
- method: 'POST',
104
- headers: {
105
- 'Content-Type': 'application/json',
106
- Accept: 'application/json'
107
- },
108
- body: JSON.stringify({
109
- ari
110
- })
111
- });
112
- if (response.ok) {
113
- var _payload$data, _payload$data2;
114
- const payload = await response.json();
115
- const url = payload === null || payload === void 0 ? void 0 : (_payload$data = payload.data) === null || _payload$data === void 0 ? void 0 : _payload$data.url;
116
- const title = payload === null || payload === void 0 ? void 0 : (_payload$data2 = payload.data) === null || _payload$data2 === void 0 ? void 0 : _payload$data2.name;
117
- return {
118
- url: typeof url === 'string' ? sourceLocalId ? url + `?block=${sourceLocalId}` : url : undefined,
119
- title: typeof title === 'string' ? title : undefined
120
- };
121
- } else {
122
- //eslint-disable-next-line no-console
123
- console.error('Failed to fetch URL and title from ARI', response.statusText);
124
- }
125
- return undefined;
126
107
  };