@atlaskit/editor-synced-block-provider 2.10.5 → 2.11.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 (62) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/clients/block-service/blockService.js +5 -4
  3. package/dist/cjs/clients/confluence/sourceInfo.js +20 -17
  4. package/dist/cjs/hooks/useFetchSyncBlockData.js +20 -11
  5. package/dist/cjs/hooks/useHandleContentChanges.js +1 -5
  6. package/dist/cjs/index.js +2 -2
  7. package/dist/cjs/providers/block-service/blockServiceAPI.js +17 -26
  8. package/dist/cjs/providers/confluence/confluenceContentAPI.js +0 -15
  9. package/dist/cjs/providers/syncBlockProvider.js +31 -41
  10. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +138 -63
  11. package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +93 -43
  12. package/dist/cjs/store-manager/syncBlockStoreManager.js +3 -3
  13. package/dist/cjs/utils/errorHandling.js +31 -1
  14. package/dist/es2019/clients/block-service/blockService.js +5 -4
  15. package/dist/es2019/clients/confluence/sourceInfo.js +13 -8
  16. package/dist/es2019/hooks/useFetchSyncBlockData.js +15 -7
  17. package/dist/es2019/hooks/useHandleContentChanges.js +1 -5
  18. package/dist/es2019/index.js +1 -1
  19. package/dist/es2019/providers/block-service/blockServiceAPI.js +13 -20
  20. package/dist/es2019/providers/confluence/confluenceContentAPI.js +1 -14
  21. package/dist/es2019/providers/syncBlockProvider.js +31 -45
  22. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +124 -49
  23. package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +65 -24
  24. package/dist/es2019/store-manager/syncBlockStoreManager.js +3 -3
  25. package/dist/es2019/utils/errorHandling.js +17 -1
  26. package/dist/esm/clients/block-service/blockService.js +5 -4
  27. package/dist/esm/clients/confluence/sourceInfo.js +19 -16
  28. package/dist/esm/hooks/useFetchSyncBlockData.js +20 -11
  29. package/dist/esm/hooks/useHandleContentChanges.js +1 -5
  30. package/dist/esm/index.js +1 -1
  31. package/dist/esm/providers/block-service/blockServiceAPI.js +17 -26
  32. package/dist/esm/providers/confluence/confluenceContentAPI.js +1 -16
  33. package/dist/esm/providers/syncBlockProvider.js +32 -42
  34. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +138 -63
  35. package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +93 -43
  36. package/dist/esm/store-manager/syncBlockStoreManager.js +3 -3
  37. package/dist/esm/utils/errorHandling.js +30 -0
  38. package/dist/types/clients/block-service/blockService.d.ts +0 -2
  39. package/dist/types/clients/confluence/sourceInfo.d.ts +2 -1
  40. package/dist/types/hooks/useFetchSyncBlockData.d.ts +2 -1
  41. package/dist/types/index.d.ts +2 -2
  42. package/dist/types/providers/block-service/blockServiceAPI.d.ts +7 -5
  43. package/dist/types/providers/confluence/confluenceContentAPI.d.ts +2 -3
  44. package/dist/types/providers/syncBlockProvider.d.ts +12 -9
  45. package/dist/types/providers/types.d.ts +9 -9
  46. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +6 -2
  47. package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +3 -1
  48. package/dist/types/store-manager/syncBlockStoreManager.d.ts +2 -1
  49. package/dist/types/utils/errorHandling.d.ts +10 -0
  50. package/dist/types-ts4.5/clients/block-service/blockService.d.ts +0 -2
  51. package/dist/types-ts4.5/clients/confluence/sourceInfo.d.ts +2 -1
  52. package/dist/types-ts4.5/hooks/useFetchSyncBlockData.d.ts +2 -1
  53. package/dist/types-ts4.5/index.d.ts +2 -2
  54. package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +7 -5
  55. package/dist/types-ts4.5/providers/confluence/confluenceContentAPI.d.ts +2 -3
  56. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +12 -9
  57. package/dist/types-ts4.5/providers/types.d.ts +9 -9
  58. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +6 -2
  59. package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +3 -1
  60. package/dist/types-ts4.5/store-manager/syncBlockStoreManager.d.ts +2 -1
  61. package/dist/types-ts4.5/utils/errorHandling.d.ts +10 -0
  62. package/package.json +2 -8
@@ -1,6 +1,8 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { logException } from '@atlaskit/editor-common/monitoring';
2
3
  import { ProviderFactory } from '@atlaskit/editor-common/provider-factory';
3
4
  import { SyncBlockError } from '../common/types';
5
+ import { fetchErrorPayload, getSourceInfoErrorPayload } from '../utils/errorHandling';
4
6
  import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
5
7
  import { createSyncBlockNode } from '../utils/utils';
6
8
 
@@ -10,7 +12,7 @@ import { createSyncBlockNode } from '../utils/utils';
10
12
  // Handles fetching source URL and title for sync blocks.
11
13
  // Can be used in both editor and renderer contexts.
12
14
  export class ReferenceSyncBlockStoreManager {
13
- constructor(dataProvider) {
15
+ constructor(dataProvider, fireAnalyticsEvent) {
14
16
  _defineProperty(this, "isRefreshingSubscriptions", false);
15
17
  this.syncBlockCache = new Map();
16
18
  this.subscriptions = new Map();
@@ -18,6 +20,10 @@ export class ReferenceSyncBlockStoreManager {
18
20
  this.dataProvider = dataProvider;
19
21
  this.syncBlockURLRequests = new Map();
20
22
  this.providerFactories = new Map();
23
+ this.fireAnalyticsEvent = fireAnalyticsEvent;
24
+ }
25
+ updateFireAnalyticsEvent(fireAnalyticsEvent) {
26
+ this.fireAnalyticsEvent = fireAnalyticsEvent;
21
27
  }
22
28
 
23
29
  /**
@@ -40,38 +46,62 @@ export class ReferenceSyncBlockStoreManager {
40
46
  // this function will update the cache and call the subscriptions
41
47
  await this.fetchSyncBlocksData(syncBlocks);
42
48
  } catch (error) {
43
- // TODO: EDITOR-1921 - add error analytics
49
+ var _this$fireAnalyticsEv;
50
+ logException(error, {
51
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
52
+ });
53
+ (_this$fireAnalyticsEv = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv === void 0 ? void 0 : _this$fireAnalyticsEv.call(this, fetchErrorPayload(error.message));
44
54
  } finally {
45
55
  this.isRefreshingSubscriptions = false;
46
56
  }
47
57
  }
48
- retrieveSyncBlockSourceInfo(resourceId) {
49
- if (!resourceId || !this.dataProvider) {
50
- return;
51
- }
52
-
53
- // TODO: EDITOR-3312 - retrieve the source info based on the source sync block product
54
-
55
- // if the sync block is a reference block, we need to fetch the URL to the source
56
- // we could optimise this further by checking if the sync block is on the same page as the source
57
- if (!this.syncBlockURLRequests.get(resourceId)) {
58
+ fetchSyncBlockSourceInfo(resourceId) {
59
+ try {
60
+ var _existingSyncBlock$da, _existingSyncBlock$da2;
61
+ if (!resourceId || !this.dataProvider) {
62
+ throw new Error('Data provider or resourceId not set');
63
+ }
64
+ if (this.syncBlockURLRequests.get(resourceId)) {
65
+ return;
66
+ }
58
67
  this.syncBlockURLRequests.set(resourceId, true);
59
- this.dataProvider.retrieveSyncBlockSourceInfo(createSyncBlockNode('', resourceId)).then(sourceInfo => {
60
- const existingSyncBlock = this.getFromCache(resourceId);
61
- if (existingSyncBlock && existingSyncBlock.data) {
62
- existingSyncBlock.data = {
63
- ...existingSyncBlock.data,
64
- sourceURL: sourceInfo === null || sourceInfo === void 0 ? void 0 : sourceInfo.url,
65
- sourceTitle: sourceInfo === null || sourceInfo === void 0 ? void 0 : sourceInfo.title
66
- };
67
- this.updateCache(existingSyncBlock);
68
- if (sourceInfo !== null && sourceInfo !== void 0 && sourceInfo.title) {
69
- this.updateSourceTitleSubscriptions(existingSyncBlock.resourceId, sourceInfo.title);
70
- }
68
+ const existingSyncBlock = this.getFromCache(resourceId);
69
+ if (!existingSyncBlock) {
70
+ throw new Error('No existing sync block to fetch source info for');
71
+ }
72
+
73
+ // skip if source URL and title are already present
74
+ if ((_existingSyncBlock$da = existingSyncBlock.data) !== null && _existingSyncBlock$da !== void 0 && _existingSyncBlock$da.sourceURL && (_existingSyncBlock$da2 = existingSyncBlock.data) !== null && _existingSyncBlock$da2 !== void 0 && _existingSyncBlock$da2.sourceTitle) {
75
+ return;
76
+ }
77
+ const {
78
+ sourceAri,
79
+ product,
80
+ blockInstanceId
81
+ } = existingSyncBlock.data || {};
82
+ if (!sourceAri || !product || !blockInstanceId) {
83
+ throw new Error('SourceAri, product or blockInstanceId missing');
84
+ }
85
+ this.dataProvider.fetchSyncBlockSourceInfo(blockInstanceId, sourceAri, product, this.fireAnalyticsEvent).then(sourceInfo => {
86
+ if (!sourceInfo) {
87
+ return;
71
88
  }
89
+ this.updateCacheWithSourceInfo(resourceId, sourceInfo);
90
+ if (sourceInfo.title) {
91
+ this.updateSourceTitleSubscriptions(resourceId, sourceInfo.title);
92
+ }
93
+ }).catch(error => {
94
+ var _this$fireAnalyticsEv2;
95
+ (_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 ? void 0 : _this$fireAnalyticsEv2.call(this, getSourceInfoErrorPayload(error.message));
72
96
  }).finally(() => {
73
- this.syncBlockURLRequests.set(resourceId, false);
97
+ this.syncBlockURLRequests.delete(resourceId);
98
+ });
99
+ } catch (error) {
100
+ var _this$fireAnalyticsEv3;
101
+ logException(error, {
102
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
74
103
  });
104
+ (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 ? void 0 : _this$fireAnalyticsEv3.call(this, getSourceInfoErrorPayload(error.message));
75
105
  }
76
106
  }
77
107
 
@@ -100,16 +130,16 @@ export class ReferenceSyncBlockStoreManager {
100
130
  }
101
131
  });
102
132
  const data = await this.dataProvider.fetchNodesData(nodesToFetch);
103
- if (!data) {
104
- throw new Error('Failed to fetch sync block node data');
105
- }
106
133
  const resolvedData = [];
107
134
  data.forEach(syncBlockInstance => {
108
- var _resolvedSyncBlockIns, _resolvedSyncBlockIns2;
109
135
  if (!syncBlockInstance.resourceId) {
136
+ var _this$fireAnalyticsEv4;
137
+ (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 ? void 0 : _this$fireAnalyticsEv4.call(this, fetchErrorPayload(syncBlockInstance.error || 'Returned sync block instance does not have resource id'));
110
138
  return;
111
139
  }
112
140
  if (syncBlockInstance.error) {
141
+ var _this$fireAnalyticsEv5;
142
+ (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 ? void 0 : _this$fireAnalyticsEv5.call(this, fetchErrorPayload(syncBlockInstance.error));
113
143
  this.updateCache(syncBlockInstance);
114
144
  resolvedData.push(syncBlockInstance);
115
145
  return;
@@ -118,14 +148,22 @@ export class ReferenceSyncBlockStoreManager {
118
148
  const resolvedSyncBlockInstance = existingSyncBlock ? resolveSyncBlockInstance(existingSyncBlock, syncBlockInstance) : syncBlockInstance;
119
149
  this.updateCache(resolvedSyncBlockInstance);
120
150
  resolvedData.push(resolvedSyncBlockInstance);
121
-
122
- // fetch source URL and title if not already present
123
- if ((!((_resolvedSyncBlockIns = resolvedSyncBlockInstance.data) !== null && _resolvedSyncBlockIns !== void 0 && _resolvedSyncBlockIns.sourceURL) || !((_resolvedSyncBlockIns2 = resolvedSyncBlockInstance.data) !== null && _resolvedSyncBlockIns2 !== void 0 && _resolvedSyncBlockIns2.sourceTitle)) && resolvedSyncBlockInstance.resourceId) {
124
- this.retrieveSyncBlockSourceInfo(resolvedSyncBlockInstance.resourceId);
125
- }
151
+ this.fetchSyncBlockSourceInfo(resolvedSyncBlockInstance.resourceId);
126
152
  });
127
153
  return [...resolvedData, ...blocksWithNotFoundError];
128
154
  }
155
+ updateCacheWithSourceInfo(resourceId, sourceInfo) {
156
+ const existingSyncBlock = this.getFromCache(resourceId);
157
+ if (existingSyncBlock && existingSyncBlock.data) {
158
+ existingSyncBlock.data.sourceURL = sourceInfo === null || sourceInfo === void 0 ? void 0 : sourceInfo.url;
159
+ existingSyncBlock.data = {
160
+ ...existingSyncBlock.data,
161
+ sourceURL: sourceInfo === null || sourceInfo === void 0 ? void 0 : sourceInfo.url,
162
+ sourceTitle: sourceInfo === null || sourceInfo === void 0 ? void 0 : sourceInfo.title
163
+ };
164
+ this.updateCache(existingSyncBlock);
165
+ }
166
+ }
129
167
  updateCache(syncBlock) {
130
168
  const {
131
169
  resourceId
@@ -168,7 +206,13 @@ export class ReferenceSyncBlockStoreManager {
168
206
  if (cachedData) {
169
207
  callback(cachedData);
170
208
  } else {
171
- this.fetchSyncBlocksData([createSyncBlockNode(localId, resourceId)]).catch(() => {});
209
+ this.fetchSyncBlocksData([createSyncBlockNode(localId, resourceId)]).catch(error => {
210
+ var _this$fireAnalyticsEv6;
211
+ logException(error, {
212
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
213
+ });
214
+ (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 ? void 0 : _this$fireAnalyticsEv6.call(this, fetchErrorPayload(error.message));
215
+ });
172
216
  }
173
217
  return () => {
174
218
  const resourceSubscriptions = this.subscriptions.get(resourceId);
@@ -220,18 +264,27 @@ export class ReferenceSyncBlockStoreManager {
220
264
  };
221
265
  }
222
266
  subscribe(node, callback) {
223
- // check node is a sync block, as we only support sync block subscriptions
224
- if (node.type.name !== 'syncBlock') {
225
- return () => {};
226
- }
227
- const {
228
- resourceId,
229
- localId
230
- } = node.attrs;
231
- if (!localId || !resourceId) {
267
+ try {
268
+ // check node is a sync block, as we only support sync block subscriptions
269
+ if (node.type.name !== 'syncBlock') {
270
+ throw new Error('Only sync block node subscriptions are supported');
271
+ }
272
+ const {
273
+ resourceId,
274
+ localId
275
+ } = node.attrs;
276
+ if (!localId || !resourceId) {
277
+ throw new Error('Missing local id or resource id');
278
+ }
279
+ return this.subscribeToSyncBlock(resourceId, localId, callback);
280
+ } catch (error) {
281
+ var _this$fireAnalyticsEv7;
282
+ logException(error, {
283
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
284
+ });
285
+ (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 ? void 0 : _this$fireAnalyticsEv7.call(this, fetchErrorPayload(error.message));
232
286
  return () => {};
233
287
  }
234
- return this.subscribeToSyncBlock(resourceId, localId, callback);
235
288
  }
236
289
 
237
290
  /**
@@ -249,6 +302,12 @@ export class ReferenceSyncBlockStoreManager {
249
302
  }
250
303
  getProviderFactory(resourceId) {
251
304
  if (!this.dataProvider) {
305
+ var _this$fireAnalyticsEv8;
306
+ const error = new Error('Data provider not set');
307
+ logException(error, {
308
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
309
+ });
310
+ (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 ? void 0 : _this$fireAnalyticsEv8.call(this, fetchErrorPayload(error.message));
252
311
  return undefined;
253
312
  }
254
313
  const {
@@ -265,23 +324,38 @@ export class ReferenceSyncBlockStoreManager {
265
324
  this.providerFactories.set(resourceId, providerFactory);
266
325
  }
267
326
  if (providerCreator) {
268
- this.retrieveDynamicProviders(resourceId, providerFactory, providerCreator);
327
+ try {
328
+ this.retrieveDynamicProviders(resourceId, providerFactory, providerCreator);
329
+ } catch (error) {
330
+ var _this$fireAnalyticsEv9;
331
+ logException(error, {
332
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
333
+ });
334
+ (_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 ? void 0 : _this$fireAnalyticsEv9.call(this, fetchErrorPayload(error.message));
335
+ }
269
336
  }
270
337
  return providerFactory;
271
338
  }
272
339
  retrieveDynamicProviders(resourceId, providerFactory, providerCreator) {
340
+ var _syncBlock$data2, _syncBlock$data3, _syncBlock$data4, _syncBlock$data5;
273
341
  if (!this.dataProvider) {
274
- return;
342
+ throw new Error('Data provider not set');
275
343
  }
276
344
  const hasMediaProvider = providerFactory.hasProvider('mediaProvider');
277
345
  const hasEmojiProvider = providerFactory.hasProvider('emojiProvider');
278
346
  if (hasMediaProvider && hasEmojiProvider) {
279
347
  return;
280
348
  }
281
- const parentInfo = this.dataProvider.retrieveSyncBlockParentInfo(this.syncBlockCache.get(resourceId));
282
- if (!parentInfo) {
349
+ const syncBlock = this.getFromCache(resourceId);
350
+ if (!syncBlock || !((_syncBlock$data2 = syncBlock.data) !== null && _syncBlock$data2 !== void 0 && _syncBlock$data2.sourceAri) || !((_syncBlock$data3 = syncBlock.data) !== null && _syncBlock$data3 !== void 0 && _syncBlock$data3.product)) {
351
+ var _this$fireAnalyticsEv0;
352
+ (_this$fireAnalyticsEv0 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv0 === void 0 ? void 0 : _this$fireAnalyticsEv0.call(this, fetchErrorPayload('Sync block or source ari or product not found'));
283
353
  return;
284
354
  }
355
+ const parentInfo = this.dataProvider.retrieveSyncBlockParentInfo((_syncBlock$data4 = syncBlock.data) === null || _syncBlock$data4 === void 0 ? void 0 : _syncBlock$data4.sourceAri, (_syncBlock$data5 = syncBlock.data) === null || _syncBlock$data5 === void 0 ? void 0 : _syncBlock$data5.product);
356
+ if (!parentInfo) {
357
+ throw new Error('Unable to retrive sync block parent info');
358
+ }
285
359
  const {
286
360
  contentId,
287
361
  contentProduct
@@ -321,5 +395,6 @@ export class ReferenceSyncBlockStoreManager {
321
395
  providerFactory.destroy();
322
396
  });
323
397
  this.providerFactories.clear();
398
+ this.fireAnalyticsEvent = undefined;
324
399
  }
325
400
  }
@@ -1,7 +1,9 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
3
3
  import uuid from 'uuid';
4
+ import { logException } from '@atlaskit/editor-common/monitoring';
4
5
  import { rebaseTransaction } from '../common/rebase-transaction';
6
+ import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload } from '../utils/errorHandling';
5
7
  import { convertSyncBlockPMNodeToSyncBlockData, createBodiedSyncBlockNode } from '../utils/utils';
6
8
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
7
9
  // Designed to manage local in-memory state and synchronize with an external data provider.
@@ -9,7 +11,7 @@ import { convertSyncBlockPMNodeToSyncBlockData, createBodiedSyncBlockNode } from
9
11
  // Handles caching, debouncing updates, and publish/subscribe for local changes.
10
12
  // Ensures consistency between local and remote state, and can be used in both editor and renderer contexts.
11
13
  export class SourceSyncBlockStoreManager {
12
- constructor(dataProvider) {
14
+ constructor(dataProvider, fireAnalyticsEvent) {
13
15
  _defineProperty(this, "setPendingDeletion", (Ids, value) => {
14
16
  const syncBlock = this.syncBlockCache.get(Ids.resourceId);
15
17
  if (syncBlock) {
@@ -18,6 +20,7 @@ export class SourceSyncBlockStoreManager {
18
20
  });
19
21
  this.dataProvider = dataProvider;
20
22
  this.syncBlockCache = new Map();
23
+ this.fireAnalyticsEvent = fireAnalyticsEvent;
21
24
  }
22
25
  isSourceBlock(node) {
23
26
  return node.type.name === 'bodiedSyncBlock';
@@ -28,19 +31,28 @@ export class SourceSyncBlockStoreManager {
28
31
  * @param syncBlockNode - The sync block node to update
29
32
  */
30
33
  updateSyncBlockData(syncBlockNode) {
31
- if (!this.isSourceBlock(syncBlockNode)) {
32
- throw new Error('Invalid sync block node type provided for updateSyncBlockData');
33
- }
34
- const {
35
- localId,
36
- resourceId
37
- } = syncBlockNode.attrs;
38
- if (!localId || !resourceId) {
39
- throw new Error('Local ID or resource ID is not set');
34
+ try {
35
+ if (!this.isSourceBlock(syncBlockNode)) {
36
+ throw new Error('Invalid sync block node type provided for updateSyncBlockData');
37
+ }
38
+ const {
39
+ localId,
40
+ resourceId
41
+ } = syncBlockNode.attrs;
42
+ if (!localId || !resourceId) {
43
+ throw new Error('Local ID or resource ID is not set');
44
+ }
45
+ const syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
46
+ this.syncBlockCache.set(resourceId, syncBlockData);
47
+ return true;
48
+ } catch (error) {
49
+ var _this$fireAnalyticsEv;
50
+ logException(error, {
51
+ location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
52
+ });
53
+ (_this$fireAnalyticsEv = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv === void 0 ? void 0 : _this$fireAnalyticsEv.call(this, updateCacheErrorPayload(error.message));
54
+ return false;
40
55
  }
41
- const syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
42
- this.syncBlockCache.set(resourceId, syncBlockData);
43
- return true;
44
56
  }
45
57
 
46
58
  /**
@@ -72,9 +84,21 @@ export class SourceSyncBlockStoreManager {
72
84
  return Promise.resolve(true);
73
85
  }
74
86
  const writeResults = await this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
75
- return writeResults.every(result => result.resourceId !== undefined);
76
- } catch {
77
- //TODO: EDITOR-1921 - add error analytics
87
+ if (writeResults.every(result => result.resourceId !== undefined)) {
88
+ return true;
89
+ } else {
90
+ writeResults.filter(result => result.resourceId === undefined).forEach(result => {
91
+ var _this$fireAnalyticsEv2;
92
+ (_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 ? void 0 : _this$fireAnalyticsEv2.call(this, updateErrorPayload(result.error || 'Failed to write data'));
93
+ });
94
+ return false;
95
+ }
96
+ } catch (error) {
97
+ var _this$fireAnalyticsEv3;
98
+ logException(error, {
99
+ location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
100
+ });
101
+ (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 ? void 0 : _this$fireAnalyticsEv3.call(this, updateErrorPayload(error.message));
78
102
  return false;
79
103
  }
80
104
  }
@@ -130,7 +154,7 @@ export class SourceSyncBlockStoreManager {
130
154
  const localId = uuid();
131
155
  const sourceId = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getSourceId();
132
156
  if (!this.dataProvider || !sourceId) {
133
- throw new Error('Provider of sync block plugin is not set');
157
+ throw new Error('Data provider not set or source id not set');
134
158
  }
135
159
  const resourceId = this.dataProvider.generateResourceId(sourceId, localId);
136
160
  return {
@@ -162,20 +186,29 @@ export class SourceSyncBlockStoreManager {
162
186
  if (resourceId) {
163
187
  this.commitPendingCreation(true);
164
188
  } else {
189
+ var _this$fireAnalyticsEv4;
165
190
  this.commitPendingCreation(false);
166
- // TODO: EDITOR-1921 - add error analytics
191
+ (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 ? void 0 : _this$fireAnalyticsEv4.call(this, createErrorPayload(result.error || 'Failed to create bodied sync block'));
167
192
  }
168
193
  });
169
- }).catch(_reason => {
194
+ }).catch(error => {
195
+ var _this$fireAnalyticsEv5;
170
196
  this.commitPendingCreation(false);
171
- // TODO: EDITOR-1921 - add error analytics
197
+ logException(error, {
198
+ location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
199
+ });
200
+ (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 ? void 0 : _this$fireAnalyticsEv5.call(this, createErrorPayload(error.message));
172
201
  });
173
202
  this.registerPendingCreation(resourceId);
174
203
  } catch (error) {
204
+ var _this$fireAnalyticsEv6;
175
205
  if (this.hasPendingCreation()) {
176
206
  this.commitPendingCreation(false);
177
207
  }
178
- // TODO: EDITOR-1921 - add error analytics
208
+ logException(error, {
209
+ location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
210
+ });
211
+ (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 ? void 0 : _this$fireAnalyticsEv6.call(this, createErrorPayload(error.message));
179
212
  }
180
213
  }
181
214
  async deleteSyncBlocksWithConfirmation(tr, syncBlockIds) {
@@ -200,14 +233,21 @@ export class SourceSyncBlockStoreManager {
200
233
  callback = Ids => {
201
234
  this.setPendingDeletion(Ids, false);
202
235
  };
203
- // TODO: EDITOR-1921 - add error analytics
236
+ results.filter(result => result.resourceId === undefined).forEach(result => {
237
+ var _this$fireAnalyticsEv7;
238
+ (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 ? void 0 : _this$fireAnalyticsEv7.call(this, deleteErrorPayload(result.error || 'Failed to delete synced block'));
239
+ });
204
240
  }
205
241
  syncBlockIds.forEach(callback);
206
- } catch (_error) {
242
+ } catch (error) {
243
+ var _this$fireAnalyticsEv8;
207
244
  syncBlockIds.forEach(Ids => {
208
245
  this.setPendingDeletion(Ids, false);
209
246
  });
210
- // TODO: EDITOR-1921 - add error analytics
247
+ logException(error, {
248
+ location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
249
+ });
250
+ (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 ? void 0 : _this$fireAnalyticsEv8.call(this, deleteErrorPayload(error.message));
211
251
  }
212
252
  }
213
253
  this.confirmationTransaction = undefined;
@@ -227,5 +267,6 @@ export class SourceSyncBlockStoreManager {
227
267
  this.creationCallback = undefined;
228
268
  this.dataProvider = undefined;
229
269
  this.editorView = undefined;
270
+ this.fireAnalyticsEvent = undefined;
230
271
  }
231
272
  }
@@ -7,11 +7,11 @@ import { SourceSyncBlockStoreManager } from './sourceSyncBlockStoreManager';
7
7
  // SourceSyncBlockStoreManager is responsible for the lifecycle and state management of source sync blocks in an editor instance.
8
8
  // Can be used in both editor and renderer contexts.
9
9
  export class SyncBlockStoreManager {
10
- constructor(dataProvider) {
10
+ constructor(dataProvider, fireAnalyticsEvent) {
11
11
  // In future, if reference manager needs to reach to source manager and read it's current in memorey cache
12
12
  // we can pass the source manager as a parameter to the reference manager constructor
13
- this.sourceSyncBlockStoreManager = new SourceSyncBlockStoreManager(dataProvider);
14
- this.referenceSyncBlockStoreManager = new ReferenceSyncBlockStoreManager(dataProvider);
13
+ this.sourceSyncBlockStoreManager = new SourceSyncBlockStoreManager(dataProvider, fireAnalyticsEvent);
14
+ this.referenceSyncBlockStoreManager = new ReferenceSyncBlockStoreManager(dataProvider, fireAnalyticsEvent);
15
15
  }
16
16
  get referenceManager() {
17
17
  return this.referenceSyncBlockStoreManager;
@@ -1,7 +1,23 @@
1
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, ACTION_SUBJECT_ID } from "@atlaskit/editor-common/analytics";
1
2
  export const stringifyError = error => {
2
3
  try {
3
4
  return JSON.stringify(error);
4
5
  } catch {
5
6
  return undefined;
6
7
  }
7
- };
8
+ };
9
+ export const getErrorPayload = (actionSubjectId, error) => ({
10
+ action: ACTION.ERROR,
11
+ actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
12
+ actionSubjectId,
13
+ eventType: EVENT_TYPE.OPERATIONAL,
14
+ attributes: {
15
+ error
16
+ }
17
+ });
18
+ export const fetchErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error);
19
+ export const getSourceInfoErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error);
20
+ export const updateErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error);
21
+ export const createErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error);
22
+ export const deleteErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE, error);
23
+ export const updateCacheErrorPayload = error => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE_CACHE, error);
@@ -32,7 +32,7 @@ export var getSyncedBlockContent = /*#__PURE__*/function () {
32
32
  case 0:
33
33
  blockAri = _ref.blockAri;
34
34
  _context.next = 3;
35
- return fetch("".concat(BLOCK_SERVICE_API_URL, "/block/").concat(blockAri), {
35
+ return fetch("".concat(BLOCK_SERVICE_API_URL, "/block/").concat(encodeURIComponent(blockAri)), {
36
36
  method: 'GET',
37
37
  headers: COMMON_HEADERS
38
38
  });
@@ -66,7 +66,7 @@ export var deleteSyncedBlock = /*#__PURE__*/function () {
66
66
  case 0:
67
67
  blockAri = _ref3.blockAri;
68
68
  _context2.next = 3;
69
- return fetch("".concat(BLOCK_SERVICE_API_URL, "/block/").concat(blockAri), {
69
+ return fetch("".concat(BLOCK_SERVICE_API_URL, "/block/").concat(encodeURIComponent(blockAri)), {
70
70
  method: 'DELETE',
71
71
  headers: COMMON_HEADERS
72
72
  });
@@ -95,7 +95,7 @@ export var updateSyncedBlock = /*#__PURE__*/function () {
95
95
  case 0:
96
96
  blockAri = _ref5.blockAri, content = _ref5.content;
97
97
  _context3.next = 3;
98
- return fetch("".concat(BLOCK_SERVICE_API_URL, "/block/").concat(blockAri), {
98
+ return fetch("".concat(BLOCK_SERVICE_API_URL, "/block/").concat(encodeURIComponent(blockAri)), {
99
99
  method: 'PUT',
100
100
  headers: COMMON_HEADERS,
101
101
  body: JSON.stringify({
@@ -127,10 +127,11 @@ export var createSyncedBlock = /*#__PURE__*/function () {
127
127
  case 0:
128
128
  blockAri = _ref7.blockAri, blockInstanceId = _ref7.blockInstanceId, sourceAri = _ref7.sourceAri, product = _ref7.product, content = _ref7.content;
129
129
  _context4.next = 3;
130
- return fetch("".concat(BLOCK_SERVICE_API_URL, "/block/").concat(blockAri), {
130
+ return fetch("".concat(BLOCK_SERVICE_API_URL, "/block"), {
131
131
  method: 'POST',
132
132
  headers: COMMON_HEADERS,
133
133
  body: JSON.stringify({
134
+ blockAri: blockAri,
134
135
  blockInstanceId: blockInstanceId,
135
136
  sourceAri: sourceAri,
136
137
  product: product,
@@ -5,6 +5,8 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
5
5
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6
6
  /* eslint-disable require-unicode-regexp */
7
7
 
8
+ import { logException } from '@atlaskit/editor-common/monitoring';
9
+ import { getSourceInfoErrorPayload } from '../../utils/errorHandling';
8
10
  import { getPageIdAndTypeFromConfluencePageAri } from './ari';
9
11
  import { isBlogPageType } from './utils';
10
12
  var COMMON_HEADERS = {
@@ -63,8 +65,8 @@ var getConfluenceSourceInfo = /*#__PURE__*/function () {
63
65
  return _ref.apply(this, arguments);
64
66
  };
65
67
  }();
66
- export var fetchConfluenceSourceInfo = /*#__PURE__*/function () {
67
- var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(pageAri, localId) {
68
+ export var fetchConfluencePageInfo = /*#__PURE__*/function () {
69
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(pageAri, localId, fireAnalyticsEvent) {
68
70
  var _response$data, _contentData$space, _getPageIdAndTypeFrom, pageType, response, contentData, title, url, _ref3, base;
69
71
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
70
72
  while (1) switch (_context2.prev = _context2.next) {
@@ -76,15 +78,9 @@ export var fetchConfluenceSourceInfo = /*#__PURE__*/function () {
76
78
  case 4:
77
79
  response = _context2.sent;
78
80
  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];
79
- if (contentData) {
80
- _context2.next = 8;
81
- break;
82
- }
83
- throw new Error("Failed to get content data");
84
- case 8:
85
- title = contentData.title;
86
- _ref3 = contentData.links || {}, base = _ref3.base;
87
- if (base && (_contentData$space = contentData.space) !== null && _contentData$space !== void 0 && _contentData$space.key && contentData.id) {
81
+ title = contentData === null || contentData === void 0 ? void 0 : contentData.title;
82
+ _ref3 = (contentData === null || contentData === void 0 ? void 0 : contentData.links) || {}, base = _ref3.base;
83
+ if (base && contentData !== null && contentData !== void 0 && (_contentData$space = contentData.space) !== null && _contentData$space !== void 0 && _contentData$space.key && contentData !== null && contentData !== void 0 && contentData.id) {
88
84
  if (isBlogPageType(pageType)) {
89
85
  url = "".concat(base, "/spaces/").concat(contentData.space.key, "/blog/edit-v2/").concat(contentData.id);
90
86
  } else if (contentData.subType === 'live') {
@@ -94,21 +90,28 @@ export var fetchConfluenceSourceInfo = /*#__PURE__*/function () {
94
90
  }
95
91
  }
96
92
  url = url && localId ? "".concat(url, "#block-").concat(localId) : url;
93
+ if (!title || !url) {
94
+ fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent(getSourceInfoErrorPayload('Failed to get confluence page source info'));
95
+ }
97
96
  return _context2.abrupt("return", Promise.resolve({
98
97
  title: title,
99
98
  url: url
100
99
  }));
101
- case 15:
102
- _context2.prev = 15;
100
+ case 14:
101
+ _context2.prev = 14;
103
102
  _context2.t0 = _context2["catch"](0);
103
+ logException(_context2.t0, {
104
+ location: 'editor-synced-block-provider/sourceInfo'
105
+ });
106
+ fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent(getSourceInfoErrorPayload(_context2.t0.message));
104
107
  return _context2.abrupt("return", Promise.resolve(undefined));
105
- case 18:
108
+ case 19:
106
109
  case "end":
107
110
  return _context2.stop();
108
111
  }
109
- }, _callee2, null, [[0, 15]]);
112
+ }, _callee2, null, [[0, 14]]);
110
113
  }));
111
- return function fetchConfluenceSourceInfo(_x2, _x3) {
114
+ return function fetchConfluencePageInfo(_x2, _x3, _x4) {
112
115
  return _ref2.apply(this, arguments);
113
116
  };
114
117
  }();