@atlaskit/editor-synced-block-provider 6.6.3 → 6.6.4
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.
- package/CHANGELOG.md +8 -0
- package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +106 -25
- package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +80 -1
- package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +107 -26
- package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +24 -0
- package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +24 -0
- package/package.json +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @atlaskit/editor-synced-block-provider
|
|
2
2
|
|
|
3
|
+
## 6.6.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`7ddc63dca3716`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7ddc63dca3716) -
|
|
8
|
+
Fix synced block reference showing unpublished error when created from existing content on a live
|
|
9
|
+
page without further edits
|
|
10
|
+
|
|
3
11
|
## 6.6.3
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -12,6 +12,7 @@ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/cl
|
|
|
12
12
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
13
13
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
14
14
|
var _monitoring = require("@atlaskit/editor-common/monitoring");
|
|
15
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
15
16
|
var _types = require("../common/types");
|
|
16
17
|
var _errorHandling = require("../utils/errorHandling");
|
|
17
18
|
var _experienceTracking = require("../utils/experienceTracking");
|
|
@@ -21,6 +22,9 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
|
|
|
21
22
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
22
23
|
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; }
|
|
23
24
|
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; }
|
|
25
|
+
/** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
|
|
26
|
+
var FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
|
|
27
|
+
|
|
24
28
|
// A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
|
|
25
29
|
// Designed to manage local in-memory state and synchronize with an external data provider.
|
|
26
30
|
// Supports create, flush, and delete operations for source sync blocks.
|
|
@@ -31,6 +35,22 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
31
35
|
var _this = this;
|
|
32
36
|
(0, _classCallCheck2.default)(this, SourceSyncBlockStoreManager);
|
|
33
37
|
(0, _defineProperty2.default)(this, "hasReceivedContentChange", false);
|
|
38
|
+
/**
|
|
39
|
+
* Promises for in-flight block creations, keyed by resourceId.
|
|
40
|
+
* `flush()` awaits these so that blocks created from existing content are
|
|
41
|
+
* persisted even if no further edits trigger a subsequent flush.
|
|
42
|
+
* See EDITOR-7112.
|
|
43
|
+
*/
|
|
44
|
+
(0, _defineProperty2.default)(this, "pendingCreationPromises", new Map());
|
|
45
|
+
/**
|
|
46
|
+
* Set of resource IDs whose creation was still in-flight when a `flush()`
|
|
47
|
+
* timed out. Each completion (success or failure) is removed from this set;
|
|
48
|
+
* the first successful completion of any of these IDs triggers
|
|
49
|
+
* `postCreationFlushCallback` so the content is eventually persisted.
|
|
50
|
+
* Tracking IDs (not just a boolean) avoids dropping late completions when
|
|
51
|
+
* multiple blocks are created concurrently. See EDITOR-7112.
|
|
52
|
+
*/
|
|
53
|
+
(0, _defineProperty2.default)(this, "creationsTimedOutDuringFlush", new Set());
|
|
34
54
|
(0, _defineProperty2.default)(this, "setPendingDeletion", function (Ids, value) {
|
|
35
55
|
if (_this.viewMode === 'view') {
|
|
36
56
|
return;
|
|
@@ -57,6 +77,18 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
57
77
|
value: function registerFlushCompletionCallback(callback) {
|
|
58
78
|
this.flushCompletionCallback = callback;
|
|
59
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Register a callback to be invoked when flush() timed out waiting for a
|
|
83
|
+
* pending block creation and that creation subsequently completes. The
|
|
84
|
+
* callback should trigger a deferred flush to persist the content that
|
|
85
|
+
* was skipped due to the timeout. See EDITOR-7112.
|
|
86
|
+
*/
|
|
87
|
+
}, {
|
|
88
|
+
key: "registerPostCreationFlushCallback",
|
|
89
|
+
value: function registerPostCreationFlushCallback(callback) {
|
|
90
|
+
this.postCreationFlushCallback = callback;
|
|
91
|
+
}
|
|
60
92
|
}, {
|
|
61
93
|
key: "setFireAnalyticsEvent",
|
|
62
94
|
value: function setFireAnalyticsEvent(fireAnalyticsEvent) {
|
|
@@ -134,7 +166,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
134
166
|
value: (function () {
|
|
135
167
|
var _flush = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
136
168
|
var _this2 = this;
|
|
137
|
-
var _this$saveExperience, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
|
|
169
|
+
var _this$saveExperience, timedOut, timeoutId, timeout, _iterator, _step, resourceId, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
|
|
138
170
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
139
171
|
while (1) switch (_context.prev = _context.next) {
|
|
140
172
|
case 0:
|
|
@@ -145,6 +177,39 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
145
177
|
}
|
|
146
178
|
return _context.abrupt("return", true);
|
|
147
179
|
case 3:
|
|
180
|
+
if (!(this.pendingCreationPromises.size > 0 && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_12'))) {
|
|
181
|
+
_context.next = 10;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
timedOut = false;
|
|
185
|
+
timeout = new Promise(function (resolve) {
|
|
186
|
+
timeoutId = setTimeout(function () {
|
|
187
|
+
timedOut = true;
|
|
188
|
+
resolve();
|
|
189
|
+
}, FLUSH_CREATION_AWAIT_TIMEOUT_MS);
|
|
190
|
+
});
|
|
191
|
+
_context.next = 8;
|
|
192
|
+
return Promise.race([Promise.all(this.pendingCreationPromises.values()), timeout]);
|
|
193
|
+
case 8:
|
|
194
|
+
if (timeoutId !== undefined) {
|
|
195
|
+
clearTimeout(timeoutId);
|
|
196
|
+
}
|
|
197
|
+
if (timedOut) {
|
|
198
|
+
// Record every still-in-flight creation so each late
|
|
199
|
+
// completion is tracked independently.
|
|
200
|
+
_iterator = _createForOfIteratorHelper(this.pendingCreationPromises.keys());
|
|
201
|
+
try {
|
|
202
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
203
|
+
resourceId = _step.value;
|
|
204
|
+
this.creationsTimedOutDuringFlush.add(resourceId);
|
|
205
|
+
}
|
|
206
|
+
} catch (err) {
|
|
207
|
+
_iterator.e(err);
|
|
208
|
+
} finally {
|
|
209
|
+
_iterator.f();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
case 10:
|
|
148
213
|
bodiedSyncBlockNodes = [];
|
|
149
214
|
bodiedSyncBlockData = [];
|
|
150
215
|
Array.from(this.syncBlockCache.values()).forEach(function (syncBlockData) {
|
|
@@ -174,21 +239,21 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
174
239
|
}
|
|
175
240
|
});
|
|
176
241
|
if (!(bodiedSyncBlockNodes.length === 0)) {
|
|
177
|
-
_context.next =
|
|
242
|
+
_context.next = 15;
|
|
178
243
|
break;
|
|
179
244
|
}
|
|
180
245
|
return _context.abrupt("return", Promise.resolve(true));
|
|
181
|
-
case
|
|
246
|
+
case 15:
|
|
182
247
|
if (this.dataProvider) {
|
|
183
|
-
_context.next =
|
|
248
|
+
_context.next = 17;
|
|
184
249
|
break;
|
|
185
250
|
}
|
|
186
251
|
throw new Error('Data provider not set');
|
|
187
|
-
case
|
|
252
|
+
case 17:
|
|
188
253
|
(_this$saveExperience = this.saveExperience) === null || _this$saveExperience === void 0 || _this$saveExperience.start({});
|
|
189
|
-
_context.next =
|
|
254
|
+
_context.next = 20;
|
|
190
255
|
return this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
|
|
191
|
-
case
|
|
256
|
+
case 20:
|
|
192
257
|
writeResults = _context.sent;
|
|
193
258
|
writeResults.forEach(function (result) {
|
|
194
259
|
// set isDirty to true for cases where it failed to save the sync block to the BE
|
|
@@ -202,7 +267,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
202
267
|
if (!writeResults.every(function (result) {
|
|
203
268
|
return result.resourceId && !result.error;
|
|
204
269
|
})) {
|
|
205
|
-
_context.next =
|
|
270
|
+
_context.next = 28;
|
|
206
271
|
break;
|
|
207
272
|
}
|
|
208
273
|
(_this$saveExperience2 = this.saveExperience) === null || _this$saveExperience2 === void 0 || _this$saveExperience2.success();
|
|
@@ -218,7 +283,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
218
283
|
}
|
|
219
284
|
});
|
|
220
285
|
return _context.abrupt("return", true);
|
|
221
|
-
case
|
|
286
|
+
case 28:
|
|
222
287
|
(_this$saveExperience3 = this.saveExperience) === null || _this$saveExperience3 === void 0 || _this$saveExperience3.failure();
|
|
223
288
|
writeResults.filter(function (result) {
|
|
224
289
|
return !result.resourceId || result.error;
|
|
@@ -227,11 +292,11 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
227
292
|
(_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, (0, _errorHandling.updateErrorPayload)(result.error || 'Failed to write data', result.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(result.resourceId)));
|
|
228
293
|
});
|
|
229
294
|
return _context.abrupt("return", false);
|
|
230
|
-
case
|
|
231
|
-
_context.next =
|
|
295
|
+
case 31:
|
|
296
|
+
_context.next = 38;
|
|
232
297
|
break;
|
|
233
|
-
case
|
|
234
|
-
_context.prev =
|
|
298
|
+
case 33:
|
|
299
|
+
_context.prev = 33;
|
|
235
300
|
_context.t0 = _context["catch"](0);
|
|
236
301
|
(0, _monitoring.logException)(_context.t0, {
|
|
237
302
|
location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
|
|
@@ -239,15 +304,15 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
239
304
|
// Top-level flush failure is not tied to a single resourceId.
|
|
240
305
|
(_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 || _this$fireAnalyticsEv2.call(this, (0, _errorHandling.updateErrorPayload)(_context.t0.message));
|
|
241
306
|
return _context.abrupt("return", false);
|
|
242
|
-
case
|
|
243
|
-
_context.prev =
|
|
307
|
+
case 38:
|
|
308
|
+
_context.prev = 38;
|
|
244
309
|
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
|
|
245
|
-
return _context.finish(
|
|
246
|
-
case
|
|
310
|
+
return _context.finish(38);
|
|
311
|
+
case 41:
|
|
247
312
|
case "end":
|
|
248
313
|
return _context.stop();
|
|
249
314
|
}
|
|
250
|
-
}, _callee, this, [[0,
|
|
315
|
+
}, _callee, this, [[0, 33, 38, 41]]);
|
|
251
316
|
}));
|
|
252
317
|
function flush() {
|
|
253
318
|
return _flush.apply(this, arguments);
|
|
@@ -303,10 +368,20 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
303
368
|
if (onCompletion) {
|
|
304
369
|
this.creationCompletionCallbacks.delete(resourceId);
|
|
305
370
|
onCompletion(success);
|
|
371
|
+
// If a previous flush() timed out waiting for this specific
|
|
372
|
+
// creation, drop it from the tracking set regardless of outcome so
|
|
373
|
+
// it does not leak. See EDITOR-7112.
|
|
374
|
+
var wasTimedOut = this.creationsTimedOutDuringFlush.delete(resourceId);
|
|
306
375
|
if (success) {
|
|
307
376
|
// If creation is successful, set hasReceivedContentChange to true
|
|
308
377
|
// to indicate that there are unsaved changes in the cache
|
|
309
378
|
this.hasReceivedContentChange = true;
|
|
379
|
+
// If flush() timed out waiting for this creation, notify the
|
|
380
|
+
// plugin so it can trigger a deferred flush. See EDITOR-7112.
|
|
381
|
+
if (wasTimedOut) {
|
|
382
|
+
var _this$postCreationFlu;
|
|
383
|
+
(_this$postCreationFlu = this.postCreationFlushCallback) === null || _this$postCreationFlu === void 0 || _this$postCreationFlu.call(this);
|
|
384
|
+
}
|
|
310
385
|
}
|
|
311
386
|
} else {
|
|
312
387
|
var _this$fireAnalyticsEv3;
|
|
@@ -386,7 +461,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
386
461
|
}
|
|
387
462
|
this.creationCompletionCallbacks.set(resourceId, onCompletion);
|
|
388
463
|
(_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
|
|
389
|
-
this.dataProvider.createNodeData({
|
|
464
|
+
var creationPromise = this.dataProvider.createNodeData({
|
|
390
465
|
content: [],
|
|
391
466
|
blockInstanceId: blockInstanceId,
|
|
392
467
|
resourceId: resourceId
|
|
@@ -414,7 +489,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
414
489
|
reason: error.message
|
|
415
490
|
});
|
|
416
491
|
(_this4$fireAnalyticsE2 = _this4.fireAnalyticsEvent) === null || _this4$fireAnalyticsE2 === void 0 || _this4$fireAnalyticsE2.call(_this4, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
|
|
492
|
+
}).finally(function () {
|
|
493
|
+
_this4.pendingCreationPromises.delete(resourceId);
|
|
417
494
|
});
|
|
495
|
+
this.pendingCreationPromises.set(resourceId, creationPromise);
|
|
418
496
|
} catch (error) {
|
|
419
497
|
var _this$fireAnalyticsEv6;
|
|
420
498
|
if (this.isPendingCreation(resourceId)) {
|
|
@@ -575,7 +653,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
575
653
|
value: (function () {
|
|
576
654
|
var _fetchAndCacheStatuses = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
|
|
577
655
|
var _this6 = this;
|
|
578
|
-
var sourceToReferenceMap, syncBlockNodes, results,
|
|
656
|
+
var sourceToReferenceMap, syncBlockNodes, results, _iterator2, _step2, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
|
|
579
657
|
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
580
658
|
while (1) switch (_context4.prev = _context4.next) {
|
|
581
659
|
case 0:
|
|
@@ -611,10 +689,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
611
689
|
return this.dataProvider.fetchNodesData(syncBlockNodes);
|
|
612
690
|
case 7:
|
|
613
691
|
results = _context4.sent;
|
|
614
|
-
|
|
692
|
+
_iterator2 = _createForOfIteratorHelper(results);
|
|
615
693
|
try {
|
|
616
|
-
for (
|
|
617
|
-
result =
|
|
694
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
695
|
+
result = _step2.value;
|
|
618
696
|
// Map the reference resourceId back to the source resourceId
|
|
619
697
|
sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
|
|
620
698
|
cached = this.syncBlockCache.get(sourceResourceId);
|
|
@@ -623,9 +701,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
623
701
|
}
|
|
624
702
|
}
|
|
625
703
|
} catch (err) {
|
|
626
|
-
|
|
704
|
+
_iterator2.e(err);
|
|
627
705
|
} finally {
|
|
628
|
-
|
|
706
|
+
_iterator2.f();
|
|
629
707
|
}
|
|
630
708
|
_context4.next = 14;
|
|
631
709
|
break;
|
|
@@ -801,6 +879,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
801
879
|
this.confirmationCallback = undefined;
|
|
802
880
|
this.creationCompletionCallbacks.clear();
|
|
803
881
|
this.flushCompletionCallback = undefined;
|
|
882
|
+
this.postCreationFlushCallback = undefined;
|
|
883
|
+
this.pendingCreationPromises.clear();
|
|
884
|
+
this.creationsTimedOutDuringFlush.clear();
|
|
804
885
|
this.dataProvider = undefined;
|
|
805
886
|
(_this$saveExperience4 = this.saveExperience) === null || _this$saveExperience4 === void 0 || _this$saveExperience4.abort({
|
|
806
887
|
reason: 'editorDestroyed'
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
import { SyncBlockError } from '../common/types';
|
|
4
5
|
import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
|
|
5
6
|
import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
|
|
6
7
|
import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSafe } from '../utils/utils';
|
|
8
|
+
/** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
|
|
9
|
+
const FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
|
|
10
|
+
|
|
7
11
|
// A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
|
|
8
12
|
// Designed to manage local in-memory state and synchronize with an external data provider.
|
|
9
13
|
// Supports create, flush, and delete operations for source sync blocks.
|
|
@@ -12,6 +16,22 @@ import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSa
|
|
|
12
16
|
export class SourceSyncBlockStoreManager {
|
|
13
17
|
constructor(dataProvider, viewMode, isLivePage) {
|
|
14
18
|
_defineProperty(this, "hasReceivedContentChange", false);
|
|
19
|
+
/**
|
|
20
|
+
* Promises for in-flight block creations, keyed by resourceId.
|
|
21
|
+
* `flush()` awaits these so that blocks created from existing content are
|
|
22
|
+
* persisted even if no further edits trigger a subsequent flush.
|
|
23
|
+
* See EDITOR-7112.
|
|
24
|
+
*/
|
|
25
|
+
_defineProperty(this, "pendingCreationPromises", new Map());
|
|
26
|
+
/**
|
|
27
|
+
* Set of resource IDs whose creation was still in-flight when a `flush()`
|
|
28
|
+
* timed out. Each completion (success or failure) is removed from this set;
|
|
29
|
+
* the first successful completion of any of these IDs triggers
|
|
30
|
+
* `postCreationFlushCallback` so the content is eventually persisted.
|
|
31
|
+
* Tracking IDs (not just a boolean) avoids dropping late completions when
|
|
32
|
+
* multiple blocks are created concurrently. See EDITOR-7112.
|
|
33
|
+
*/
|
|
34
|
+
_defineProperty(this, "creationsTimedOutDuringFlush", new Set());
|
|
15
35
|
_defineProperty(this, "setPendingDeletion", (Ids, value) => {
|
|
16
36
|
if (this.viewMode === 'view') {
|
|
17
37
|
return;
|
|
@@ -36,6 +56,16 @@ export class SourceSyncBlockStoreManager {
|
|
|
36
56
|
registerFlushCompletionCallback(callback) {
|
|
37
57
|
this.flushCompletionCallback = callback;
|
|
38
58
|
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Register a callback to be invoked when flush() timed out waiting for a
|
|
62
|
+
* pending block creation and that creation subsequently completes. The
|
|
63
|
+
* callback should trigger a deferred flush to persist the content that
|
|
64
|
+
* was skipped due to the timeout. See EDITOR-7112.
|
|
65
|
+
*/
|
|
66
|
+
registerPostCreationFlushCallback(callback) {
|
|
67
|
+
this.postCreationFlushCallback = callback;
|
|
68
|
+
}
|
|
39
69
|
setFireAnalyticsEvent(fireAnalyticsEvent) {
|
|
40
70
|
this.fireAnalyticsEvent = fireAnalyticsEvent;
|
|
41
71
|
this.createExperience = getCreateSourceExperience(fireAnalyticsEvent);
|
|
@@ -110,6 +140,39 @@ export class SourceSyncBlockStoreManager {
|
|
|
110
140
|
if (this.viewMode === 'view') {
|
|
111
141
|
return true;
|
|
112
142
|
}
|
|
143
|
+
|
|
144
|
+
// Wait (up to FLUSH_CREATION_AWAIT_TIMEOUT_MS) for any in-flight
|
|
145
|
+
// block creations to complete before iterating the cache. Without
|
|
146
|
+
// this, blocks created from existing content are skipped
|
|
147
|
+
// (isPendingCreation check below) and if no further edits are made,
|
|
148
|
+
// no subsequent flush is triggered — causing references to show an
|
|
149
|
+
// "unpublished" error.
|
|
150
|
+
// If the timeout expires, any block whose creation is still
|
|
151
|
+
// in-flight is recorded in `creationsTimedOutDuringFlush` so that
|
|
152
|
+
// `commitPendingCreation()` can trigger a follow-up flush once that
|
|
153
|
+
// specific creation completes.
|
|
154
|
+
// See EDITOR-7112.
|
|
155
|
+
if (this.pendingCreationPromises.size > 0 && fg('platform_synced_block_patch_12')) {
|
|
156
|
+
let timedOut = false;
|
|
157
|
+
let timeoutId;
|
|
158
|
+
const timeout = new Promise(resolve => {
|
|
159
|
+
timeoutId = setTimeout(() => {
|
|
160
|
+
timedOut = true;
|
|
161
|
+
resolve();
|
|
162
|
+
}, FLUSH_CREATION_AWAIT_TIMEOUT_MS);
|
|
163
|
+
});
|
|
164
|
+
await Promise.race([Promise.all(this.pendingCreationPromises.values()), timeout]);
|
|
165
|
+
if (timeoutId !== undefined) {
|
|
166
|
+
clearTimeout(timeoutId);
|
|
167
|
+
}
|
|
168
|
+
if (timedOut) {
|
|
169
|
+
// Record every still-in-flight creation so each late
|
|
170
|
+
// completion is tracked independently.
|
|
171
|
+
for (const resourceId of this.pendingCreationPromises.keys()) {
|
|
172
|
+
this.creationsTimedOutDuringFlush.add(resourceId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
113
176
|
const bodiedSyncBlockNodes = [];
|
|
114
177
|
const bodiedSyncBlockData = [];
|
|
115
178
|
Array.from(this.syncBlockCache.values()).forEach(syncBlockData => {
|
|
@@ -232,10 +295,20 @@ export class SourceSyncBlockStoreManager {
|
|
|
232
295
|
if (onCompletion) {
|
|
233
296
|
this.creationCompletionCallbacks.delete(resourceId);
|
|
234
297
|
onCompletion(success);
|
|
298
|
+
// If a previous flush() timed out waiting for this specific
|
|
299
|
+
// creation, drop it from the tracking set regardless of outcome so
|
|
300
|
+
// it does not leak. See EDITOR-7112.
|
|
301
|
+
const wasTimedOut = this.creationsTimedOutDuringFlush.delete(resourceId);
|
|
235
302
|
if (success) {
|
|
236
303
|
// If creation is successful, set hasReceivedContentChange to true
|
|
237
304
|
// to indicate that there are unsaved changes in the cache
|
|
238
305
|
this.hasReceivedContentChange = true;
|
|
306
|
+
// If flush() timed out waiting for this creation, notify the
|
|
307
|
+
// plugin so it can trigger a deferred flush. See EDITOR-7112.
|
|
308
|
+
if (wasTimedOut) {
|
|
309
|
+
var _this$postCreationFlu;
|
|
310
|
+
(_this$postCreationFlu = this.postCreationFlushCallback) === null || _this$postCreationFlu === void 0 ? void 0 : _this$postCreationFlu.call(this);
|
|
311
|
+
}
|
|
239
312
|
}
|
|
240
313
|
} else {
|
|
241
314
|
var _this$fireAnalyticsEv5;
|
|
@@ -308,7 +381,7 @@ export class SourceSyncBlockStoreManager {
|
|
|
308
381
|
}
|
|
309
382
|
this.creationCompletionCallbacks.set(resourceId, onCompletion);
|
|
310
383
|
(_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 ? void 0 : _this$createExperienc.start({});
|
|
311
|
-
this.dataProvider.createNodeData({
|
|
384
|
+
const creationPromise = this.dataProvider.createNodeData({
|
|
312
385
|
content: [],
|
|
313
386
|
blockInstanceId,
|
|
314
387
|
resourceId
|
|
@@ -336,7 +409,10 @@ export class SourceSyncBlockStoreManager {
|
|
|
336
409
|
reason: error.message
|
|
337
410
|
});
|
|
338
411
|
(_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 ? void 0 : _this$fireAnalyticsEv9.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
|
|
412
|
+
}).finally(() => {
|
|
413
|
+
this.pendingCreationPromises.delete(resourceId);
|
|
339
414
|
});
|
|
415
|
+
this.pendingCreationPromises.set(resourceId, creationPromise);
|
|
340
416
|
} catch (error) {
|
|
341
417
|
var _this$fireAnalyticsEv0;
|
|
342
418
|
if (this.isPendingCreation(resourceId)) {
|
|
@@ -584,6 +660,9 @@ export class SourceSyncBlockStoreManager {
|
|
|
584
660
|
this.confirmationCallback = undefined;
|
|
585
661
|
this.creationCompletionCallbacks.clear();
|
|
586
662
|
this.flushCompletionCallback = undefined;
|
|
663
|
+
this.postCreationFlushCallback = undefined;
|
|
664
|
+
this.pendingCreationPromises.clear();
|
|
665
|
+
this.creationsTimedOutDuringFlush.clear();
|
|
587
666
|
this.dataProvider = undefined;
|
|
588
667
|
(_this$saveExperience4 = this.saveExperience) === null || _this$saveExperience4 === void 0 ? void 0 : _this$saveExperience4.abort({
|
|
589
668
|
reason: 'editorDestroyed'
|
|
@@ -3,17 +3,21 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
|
3
3
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
4
4
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
5
5
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
6
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
6
7
|
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; } } }; }
|
|
7
8
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
8
9
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
9
|
-
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
10
10
|
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; }
|
|
11
11
|
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; }
|
|
12
12
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
13
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
13
14
|
import { SyncBlockError } from '../common/types';
|
|
14
15
|
import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
|
|
15
16
|
import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
|
|
16
17
|
import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSafe } from '../utils/utils';
|
|
18
|
+
/** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
|
|
19
|
+
var FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
|
|
20
|
+
|
|
17
21
|
// A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
|
|
18
22
|
// Designed to manage local in-memory state and synchronize with an external data provider.
|
|
19
23
|
// Supports create, flush, and delete operations for source sync blocks.
|
|
@@ -24,6 +28,22 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
24
28
|
var _this = this;
|
|
25
29
|
_classCallCheck(this, SourceSyncBlockStoreManager);
|
|
26
30
|
_defineProperty(this, "hasReceivedContentChange", false);
|
|
31
|
+
/**
|
|
32
|
+
* Promises for in-flight block creations, keyed by resourceId.
|
|
33
|
+
* `flush()` awaits these so that blocks created from existing content are
|
|
34
|
+
* persisted even if no further edits trigger a subsequent flush.
|
|
35
|
+
* See EDITOR-7112.
|
|
36
|
+
*/
|
|
37
|
+
_defineProperty(this, "pendingCreationPromises", new Map());
|
|
38
|
+
/**
|
|
39
|
+
* Set of resource IDs whose creation was still in-flight when a `flush()`
|
|
40
|
+
* timed out. Each completion (success or failure) is removed from this set;
|
|
41
|
+
* the first successful completion of any of these IDs triggers
|
|
42
|
+
* `postCreationFlushCallback` so the content is eventually persisted.
|
|
43
|
+
* Tracking IDs (not just a boolean) avoids dropping late completions when
|
|
44
|
+
* multiple blocks are created concurrently. See EDITOR-7112.
|
|
45
|
+
*/
|
|
46
|
+
_defineProperty(this, "creationsTimedOutDuringFlush", new Set());
|
|
27
47
|
_defineProperty(this, "setPendingDeletion", function (Ids, value) {
|
|
28
48
|
if (_this.viewMode === 'view') {
|
|
29
49
|
return;
|
|
@@ -50,6 +70,18 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
50
70
|
value: function registerFlushCompletionCallback(callback) {
|
|
51
71
|
this.flushCompletionCallback = callback;
|
|
52
72
|
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Register a callback to be invoked when flush() timed out waiting for a
|
|
76
|
+
* pending block creation and that creation subsequently completes. The
|
|
77
|
+
* callback should trigger a deferred flush to persist the content that
|
|
78
|
+
* was skipped due to the timeout. See EDITOR-7112.
|
|
79
|
+
*/
|
|
80
|
+
}, {
|
|
81
|
+
key: "registerPostCreationFlushCallback",
|
|
82
|
+
value: function registerPostCreationFlushCallback(callback) {
|
|
83
|
+
this.postCreationFlushCallback = callback;
|
|
84
|
+
}
|
|
53
85
|
}, {
|
|
54
86
|
key: "setFireAnalyticsEvent",
|
|
55
87
|
value: function setFireAnalyticsEvent(fireAnalyticsEvent) {
|
|
@@ -127,7 +159,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
127
159
|
value: (function () {
|
|
128
160
|
var _flush = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
129
161
|
var _this2 = this;
|
|
130
|
-
var _this$saveExperience, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
|
|
162
|
+
var _this$saveExperience, timedOut, timeoutId, timeout, _iterator, _step, resourceId, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
|
|
131
163
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
132
164
|
while (1) switch (_context.prev = _context.next) {
|
|
133
165
|
case 0:
|
|
@@ -138,6 +170,39 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
138
170
|
}
|
|
139
171
|
return _context.abrupt("return", true);
|
|
140
172
|
case 3:
|
|
173
|
+
if (!(this.pendingCreationPromises.size > 0 && fg('platform_synced_block_patch_12'))) {
|
|
174
|
+
_context.next = 10;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
timedOut = false;
|
|
178
|
+
timeout = new Promise(function (resolve) {
|
|
179
|
+
timeoutId = setTimeout(function () {
|
|
180
|
+
timedOut = true;
|
|
181
|
+
resolve();
|
|
182
|
+
}, FLUSH_CREATION_AWAIT_TIMEOUT_MS);
|
|
183
|
+
});
|
|
184
|
+
_context.next = 8;
|
|
185
|
+
return Promise.race([Promise.all(this.pendingCreationPromises.values()), timeout]);
|
|
186
|
+
case 8:
|
|
187
|
+
if (timeoutId !== undefined) {
|
|
188
|
+
clearTimeout(timeoutId);
|
|
189
|
+
}
|
|
190
|
+
if (timedOut) {
|
|
191
|
+
// Record every still-in-flight creation so each late
|
|
192
|
+
// completion is tracked independently.
|
|
193
|
+
_iterator = _createForOfIteratorHelper(this.pendingCreationPromises.keys());
|
|
194
|
+
try {
|
|
195
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
196
|
+
resourceId = _step.value;
|
|
197
|
+
this.creationsTimedOutDuringFlush.add(resourceId);
|
|
198
|
+
}
|
|
199
|
+
} catch (err) {
|
|
200
|
+
_iterator.e(err);
|
|
201
|
+
} finally {
|
|
202
|
+
_iterator.f();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
case 10:
|
|
141
206
|
bodiedSyncBlockNodes = [];
|
|
142
207
|
bodiedSyncBlockData = [];
|
|
143
208
|
Array.from(this.syncBlockCache.values()).forEach(function (syncBlockData) {
|
|
@@ -167,21 +232,21 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
167
232
|
}
|
|
168
233
|
});
|
|
169
234
|
if (!(bodiedSyncBlockNodes.length === 0)) {
|
|
170
|
-
_context.next =
|
|
235
|
+
_context.next = 15;
|
|
171
236
|
break;
|
|
172
237
|
}
|
|
173
238
|
return _context.abrupt("return", Promise.resolve(true));
|
|
174
|
-
case
|
|
239
|
+
case 15:
|
|
175
240
|
if (this.dataProvider) {
|
|
176
|
-
_context.next =
|
|
241
|
+
_context.next = 17;
|
|
177
242
|
break;
|
|
178
243
|
}
|
|
179
244
|
throw new Error('Data provider not set');
|
|
180
|
-
case
|
|
245
|
+
case 17:
|
|
181
246
|
(_this$saveExperience = this.saveExperience) === null || _this$saveExperience === void 0 || _this$saveExperience.start({});
|
|
182
|
-
_context.next =
|
|
247
|
+
_context.next = 20;
|
|
183
248
|
return this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
|
|
184
|
-
case
|
|
249
|
+
case 20:
|
|
185
250
|
writeResults = _context.sent;
|
|
186
251
|
writeResults.forEach(function (result) {
|
|
187
252
|
// set isDirty to true for cases where it failed to save the sync block to the BE
|
|
@@ -195,7 +260,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
195
260
|
if (!writeResults.every(function (result) {
|
|
196
261
|
return result.resourceId && !result.error;
|
|
197
262
|
})) {
|
|
198
|
-
_context.next =
|
|
263
|
+
_context.next = 28;
|
|
199
264
|
break;
|
|
200
265
|
}
|
|
201
266
|
(_this$saveExperience2 = this.saveExperience) === null || _this$saveExperience2 === void 0 || _this$saveExperience2.success();
|
|
@@ -211,7 +276,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
211
276
|
}
|
|
212
277
|
});
|
|
213
278
|
return _context.abrupt("return", true);
|
|
214
|
-
case
|
|
279
|
+
case 28:
|
|
215
280
|
(_this$saveExperience3 = this.saveExperience) === null || _this$saveExperience3 === void 0 || _this$saveExperience3.failure();
|
|
216
281
|
writeResults.filter(function (result) {
|
|
217
282
|
return !result.resourceId || result.error;
|
|
@@ -220,11 +285,11 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
220
285
|
(_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, updateErrorPayload(result.error || 'Failed to write data', result.resourceId, getSourceProductFromResourceIdSafe(result.resourceId)));
|
|
221
286
|
});
|
|
222
287
|
return _context.abrupt("return", false);
|
|
223
|
-
case
|
|
224
|
-
_context.next =
|
|
288
|
+
case 31:
|
|
289
|
+
_context.next = 38;
|
|
225
290
|
break;
|
|
226
|
-
case
|
|
227
|
-
_context.prev =
|
|
291
|
+
case 33:
|
|
292
|
+
_context.prev = 33;
|
|
228
293
|
_context.t0 = _context["catch"](0);
|
|
229
294
|
logException(_context.t0, {
|
|
230
295
|
location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
|
|
@@ -232,15 +297,15 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
232
297
|
// Top-level flush failure is not tied to a single resourceId.
|
|
233
298
|
(_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 || _this$fireAnalyticsEv2.call(this, updateErrorPayload(_context.t0.message));
|
|
234
299
|
return _context.abrupt("return", false);
|
|
235
|
-
case
|
|
236
|
-
_context.prev =
|
|
300
|
+
case 38:
|
|
301
|
+
_context.prev = 38;
|
|
237
302
|
(_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
|
|
238
|
-
return _context.finish(
|
|
239
|
-
case
|
|
303
|
+
return _context.finish(38);
|
|
304
|
+
case 41:
|
|
240
305
|
case "end":
|
|
241
306
|
return _context.stop();
|
|
242
307
|
}
|
|
243
|
-
}, _callee, this, [[0,
|
|
308
|
+
}, _callee, this, [[0, 33, 38, 41]]);
|
|
244
309
|
}));
|
|
245
310
|
function flush() {
|
|
246
311
|
return _flush.apply(this, arguments);
|
|
@@ -296,10 +361,20 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
296
361
|
if (onCompletion) {
|
|
297
362
|
this.creationCompletionCallbacks.delete(resourceId);
|
|
298
363
|
onCompletion(success);
|
|
364
|
+
// If a previous flush() timed out waiting for this specific
|
|
365
|
+
// creation, drop it from the tracking set regardless of outcome so
|
|
366
|
+
// it does not leak. See EDITOR-7112.
|
|
367
|
+
var wasTimedOut = this.creationsTimedOutDuringFlush.delete(resourceId);
|
|
299
368
|
if (success) {
|
|
300
369
|
// If creation is successful, set hasReceivedContentChange to true
|
|
301
370
|
// to indicate that there are unsaved changes in the cache
|
|
302
371
|
this.hasReceivedContentChange = true;
|
|
372
|
+
// If flush() timed out waiting for this creation, notify the
|
|
373
|
+
// plugin so it can trigger a deferred flush. See EDITOR-7112.
|
|
374
|
+
if (wasTimedOut) {
|
|
375
|
+
var _this$postCreationFlu;
|
|
376
|
+
(_this$postCreationFlu = this.postCreationFlushCallback) === null || _this$postCreationFlu === void 0 || _this$postCreationFlu.call(this);
|
|
377
|
+
}
|
|
303
378
|
}
|
|
304
379
|
} else {
|
|
305
380
|
var _this$fireAnalyticsEv3;
|
|
@@ -379,7 +454,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
379
454
|
}
|
|
380
455
|
this.creationCompletionCallbacks.set(resourceId, onCompletion);
|
|
381
456
|
(_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
|
|
382
|
-
this.dataProvider.createNodeData({
|
|
457
|
+
var creationPromise = this.dataProvider.createNodeData({
|
|
383
458
|
content: [],
|
|
384
459
|
blockInstanceId: blockInstanceId,
|
|
385
460
|
resourceId: resourceId
|
|
@@ -407,7 +482,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
407
482
|
reason: error.message
|
|
408
483
|
});
|
|
409
484
|
(_this4$fireAnalyticsE2 = _this4.fireAnalyticsEvent) === null || _this4$fireAnalyticsE2 === void 0 || _this4$fireAnalyticsE2.call(_this4, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
|
|
485
|
+
}).finally(function () {
|
|
486
|
+
_this4.pendingCreationPromises.delete(resourceId);
|
|
410
487
|
});
|
|
488
|
+
this.pendingCreationPromises.set(resourceId, creationPromise);
|
|
411
489
|
} catch (error) {
|
|
412
490
|
var _this$fireAnalyticsEv6;
|
|
413
491
|
if (this.isPendingCreation(resourceId)) {
|
|
@@ -568,7 +646,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
568
646
|
value: (function () {
|
|
569
647
|
var _fetchAndCacheStatuses = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
570
648
|
var _this6 = this;
|
|
571
|
-
var sourceToReferenceMap, syncBlockNodes, results,
|
|
649
|
+
var sourceToReferenceMap, syncBlockNodes, results, _iterator2, _step2, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
|
|
572
650
|
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
|
|
573
651
|
while (1) switch (_context4.prev = _context4.next) {
|
|
574
652
|
case 0:
|
|
@@ -604,10 +682,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
604
682
|
return this.dataProvider.fetchNodesData(syncBlockNodes);
|
|
605
683
|
case 7:
|
|
606
684
|
results = _context4.sent;
|
|
607
|
-
|
|
685
|
+
_iterator2 = _createForOfIteratorHelper(results);
|
|
608
686
|
try {
|
|
609
|
-
for (
|
|
610
|
-
result =
|
|
687
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
688
|
+
result = _step2.value;
|
|
611
689
|
// Map the reference resourceId back to the source resourceId
|
|
612
690
|
sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
|
|
613
691
|
cached = this.syncBlockCache.get(sourceResourceId);
|
|
@@ -616,9 +694,9 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
616
694
|
}
|
|
617
695
|
}
|
|
618
696
|
} catch (err) {
|
|
619
|
-
|
|
697
|
+
_iterator2.e(err);
|
|
620
698
|
} finally {
|
|
621
|
-
|
|
699
|
+
_iterator2.f();
|
|
622
700
|
}
|
|
623
701
|
_context4.next = 14;
|
|
624
702
|
break;
|
|
@@ -794,6 +872,9 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
794
872
|
this.confirmationCallback = undefined;
|
|
795
873
|
this.creationCompletionCallbacks.clear();
|
|
796
874
|
this.flushCompletionCallback = undefined;
|
|
875
|
+
this.postCreationFlushCallback = undefined;
|
|
876
|
+
this.pendingCreationPromises.clear();
|
|
877
|
+
this.creationsTimedOutDuringFlush.clear();
|
|
797
878
|
this.dataProvider = undefined;
|
|
798
879
|
(_this$saveExperience4 = this.saveExperience) === null || _this$saveExperience4 === void 0 || _this$saveExperience4.abort({
|
|
799
880
|
reason: 'editorDestroyed'
|
|
@@ -18,6 +18,23 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
18
18
|
private deletionRetryInfo?;
|
|
19
19
|
private creationCompletionCallbacks;
|
|
20
20
|
private flushCompletionCallback?;
|
|
21
|
+
private postCreationFlushCallback?;
|
|
22
|
+
/**
|
|
23
|
+
* Promises for in-flight block creations, keyed by resourceId.
|
|
24
|
+
* `flush()` awaits these so that blocks created from existing content are
|
|
25
|
+
* persisted even if no further edits trigger a subsequent flush.
|
|
26
|
+
* See EDITOR-7112.
|
|
27
|
+
*/
|
|
28
|
+
private pendingCreationPromises;
|
|
29
|
+
/**
|
|
30
|
+
* Set of resource IDs whose creation was still in-flight when a `flush()`
|
|
31
|
+
* timed out. Each completion (success or failure) is removed from this set;
|
|
32
|
+
* the first successful completion of any of these IDs triggers
|
|
33
|
+
* `postCreationFlushCallback` so the content is eventually persisted.
|
|
34
|
+
* Tracking IDs (not just a boolean) avoids dropping late completions when
|
|
35
|
+
* multiple blocks are created concurrently. See EDITOR-7112.
|
|
36
|
+
*/
|
|
37
|
+
private creationsTimedOutDuringFlush;
|
|
21
38
|
private createExperience;
|
|
22
39
|
private saveExperience;
|
|
23
40
|
private deleteExperience;
|
|
@@ -29,6 +46,13 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
29
46
|
* hasUnsavedBodiedSyncBlockChanges is recalculated in plugin state.
|
|
30
47
|
*/
|
|
31
48
|
registerFlushCompletionCallback(callback: () => void): void;
|
|
49
|
+
/**
|
|
50
|
+
* Register a callback to be invoked when flush() timed out waiting for a
|
|
51
|
+
* pending block creation and that creation subsequently completes. The
|
|
52
|
+
* callback should trigger a deferred flush to persist the content that
|
|
53
|
+
* was skipped due to the timeout. See EDITOR-7112.
|
|
54
|
+
*/
|
|
55
|
+
registerPostCreationFlushCallback(callback: () => void): void;
|
|
32
56
|
setFireAnalyticsEvent(fireAnalyticsEvent?: (payload: SyncBlockEventPayload) => void): void;
|
|
33
57
|
isSourceBlock(node: PMNode): boolean;
|
|
34
58
|
/**
|
|
@@ -18,6 +18,23 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
18
18
|
private deletionRetryInfo?;
|
|
19
19
|
private creationCompletionCallbacks;
|
|
20
20
|
private flushCompletionCallback?;
|
|
21
|
+
private postCreationFlushCallback?;
|
|
22
|
+
/**
|
|
23
|
+
* Promises for in-flight block creations, keyed by resourceId.
|
|
24
|
+
* `flush()` awaits these so that blocks created from existing content are
|
|
25
|
+
* persisted even if no further edits trigger a subsequent flush.
|
|
26
|
+
* See EDITOR-7112.
|
|
27
|
+
*/
|
|
28
|
+
private pendingCreationPromises;
|
|
29
|
+
/**
|
|
30
|
+
* Set of resource IDs whose creation was still in-flight when a `flush()`
|
|
31
|
+
* timed out. Each completion (success or failure) is removed from this set;
|
|
32
|
+
* the first successful completion of any of these IDs triggers
|
|
33
|
+
* `postCreationFlushCallback` so the content is eventually persisted.
|
|
34
|
+
* Tracking IDs (not just a boolean) avoids dropping late completions when
|
|
35
|
+
* multiple blocks are created concurrently. See EDITOR-7112.
|
|
36
|
+
*/
|
|
37
|
+
private creationsTimedOutDuringFlush;
|
|
21
38
|
private createExperience;
|
|
22
39
|
private saveExperience;
|
|
23
40
|
private deleteExperience;
|
|
@@ -29,6 +46,13 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
29
46
|
* hasUnsavedBodiedSyncBlockChanges is recalculated in plugin state.
|
|
30
47
|
*/
|
|
31
48
|
registerFlushCompletionCallback(callback: () => void): void;
|
|
49
|
+
/**
|
|
50
|
+
* Register a callback to be invoked when flush() timed out waiting for a
|
|
51
|
+
* pending block creation and that creation subsequently completes. The
|
|
52
|
+
* callback should trigger a deferred flush to persist the content that
|
|
53
|
+
* was skipped due to the timeout. See EDITOR-7112.
|
|
54
|
+
*/
|
|
55
|
+
registerPostCreationFlushCallback(callback: () => void): void;
|
|
32
56
|
setFireAnalyticsEvent(fireAnalyticsEvent?: (payload: SyncBlockEventPayload) => void): void;
|
|
33
57
|
isSourceBlock(node: PMNode): boolean;
|
|
34
58
|
/**
|
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@atlaskit/editor-prosemirror": "^7.3.0",
|
|
30
30
|
"@atlaskit/node-data-provider": "^11.1.0",
|
|
31
31
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
32
|
-
"@atlaskit/tmp-editor-statsig": "^81.
|
|
32
|
+
"@atlaskit/tmp-editor-statsig": "^81.1.0",
|
|
33
33
|
"@babel/runtime": "^7.0.0",
|
|
34
34
|
"@compiled/react": "^0.20.0",
|
|
35
35
|
"graphql-ws": "^5.14.2",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"uuid": "^3.1.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@atlaskit/editor-common": "^114.
|
|
41
|
+
"@atlaskit/editor-common": "^114.35.0",
|
|
42
42
|
"react": "^18.2.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
@@ -81,11 +81,16 @@
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"name": "@atlaskit/editor-synced-block-provider",
|
|
84
|
-
"version": "6.6.
|
|
84
|
+
"version": "6.6.4",
|
|
85
85
|
"description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
|
|
86
86
|
"author": "Atlassian Pty Ltd",
|
|
87
87
|
"license": "Apache-2.0",
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"registry": "https://registry.npmjs.org/"
|
|
90
|
+
},
|
|
91
|
+
"platform-feature-flags": {
|
|
92
|
+
"platform_synced_block_patch_12": {
|
|
93
|
+
"type": "boolean"
|
|
94
|
+
}
|
|
90
95
|
}
|
|
91
96
|
}
|