@atlaskit/editor-synced-block-provider 3.31.0 → 3.31.2
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 +16 -0
- package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +117 -9
- package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +16 -0
- package/dist/cjs/store-manager/syncBlockBatchFetcher.js +76 -0
- package/dist/cjs/store-manager/syncBlockInMemorySessionCache.js +26 -0
- package/dist/cjs/store-manager/syncBlockProviderFactoryManager.js +175 -0
- package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +198 -0
- package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +93 -9
- package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +12 -0
- package/dist/es2019/store-manager/syncBlockBatchFetcher.js +56 -0
- package/dist/es2019/store-manager/syncBlockInMemorySessionCache.js +24 -0
- package/dist/es2019/store-manager/syncBlockProviderFactoryManager.js +158 -0
- package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +136 -0
- package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +117 -9
- package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +16 -0
- package/dist/esm/store-manager/syncBlockBatchFetcher.js +69 -0
- package/dist/esm/store-manager/syncBlockInMemorySessionCache.js +26 -0
- package/dist/esm/store-manager/syncBlockProviderFactoryManager.js +168 -0
- package/dist/esm/store-manager/syncBlockSubscriptionManager.js +191 -0
- package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +3 -0
- package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +2 -0
- package/dist/types/store-manager/syncBlockBatchFetcher.d.ts +25 -0
- package/dist/types/store-manager/syncBlockInMemorySessionCache.d.ts +18 -0
- package/dist/types/store-manager/syncBlockProviderFactoryManager.d.ts +25 -0
- package/dist/types/store-manager/syncBlockSubscriptionManager.d.ts +38 -0
- package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +3 -0
- package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +2 -0
- package/dist/types-ts4.5/store-manager/syncBlockBatchFetcher.d.ts +25 -0
- package/dist/types-ts4.5/store-manager/syncBlockInMemorySessionCache.d.ts +18 -0
- package/dist/types-ts4.5/store-manager/syncBlockProviderFactoryManager.d.ts +25 -0
- package/dist/types-ts4.5/store-manager/syncBlockSubscriptionManager.d.ts +38 -0
- package/package.json +5 -2
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.SyncBlockSubscriptionManager = void 0;
|
|
8
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
+
var _monitoring = require("@atlaskit/editor-common/monitoring");
|
|
12
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
13
|
+
var _errorHandling = require("../utils/errorHandling");
|
|
14
|
+
var _resolveSyncBlockInstance = require("../utils/resolveSyncBlockInstance");
|
|
15
|
+
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; } } }; }
|
|
16
|
+
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; } }
|
|
17
|
+
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; }
|
|
18
|
+
/**
|
|
19
|
+
* Manages the lifecycle of GraphQL WebSocket subscriptions for sync block
|
|
20
|
+
* real-time updates, and provides a listener API so React components can
|
|
21
|
+
* react when the set of subscribed resource IDs changes.
|
|
22
|
+
*/
|
|
23
|
+
var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
24
|
+
function SyncBlockSubscriptionManager(deps) {
|
|
25
|
+
(0, _classCallCheck2.default)(this, SyncBlockSubscriptionManager);
|
|
26
|
+
(0, _defineProperty2.default)(this, "graphqlSubscriptions", new Map());
|
|
27
|
+
(0, _defineProperty2.default)(this, "subscriptionChangeListeners", new Set());
|
|
28
|
+
(0, _defineProperty2.default)(this, "useRealTimeSubscriptions", false);
|
|
29
|
+
this.deps = deps;
|
|
30
|
+
}
|
|
31
|
+
return (0, _createClass2.default)(SyncBlockSubscriptionManager, [{
|
|
32
|
+
key: "setRealTimeSubscriptionsEnabled",
|
|
33
|
+
value: function setRealTimeSubscriptionsEnabled(enabled) {
|
|
34
|
+
if (this.useRealTimeSubscriptions === enabled) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.useRealTimeSubscriptions = enabled;
|
|
38
|
+
if (enabled) {
|
|
39
|
+
this.setupSubscriptionsForAllBlocks();
|
|
40
|
+
} else {
|
|
41
|
+
this.cleanupAll();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}, {
|
|
45
|
+
key: "isRealTimeSubscriptionsEnabled",
|
|
46
|
+
value: function isRealTimeSubscriptionsEnabled() {
|
|
47
|
+
return this.useRealTimeSubscriptions;
|
|
48
|
+
}
|
|
49
|
+
}, {
|
|
50
|
+
key: "getSubscribedResourceIds",
|
|
51
|
+
value: function getSubscribedResourceIds() {
|
|
52
|
+
return Array.from(this.deps.getSubscriptions().keys());
|
|
53
|
+
}
|
|
54
|
+
}, {
|
|
55
|
+
key: "onSubscriptionsChanged",
|
|
56
|
+
value: function onSubscriptionsChanged(listener) {
|
|
57
|
+
var _this = this;
|
|
58
|
+
this.subscriptionChangeListeners.add(listener);
|
|
59
|
+
return function () {
|
|
60
|
+
_this.subscriptionChangeListeners.delete(listener);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}, {
|
|
64
|
+
key: "notifySubscriptionChangeListeners",
|
|
65
|
+
value: function notifySubscriptionChangeListeners() {
|
|
66
|
+
var _this2 = this;
|
|
67
|
+
this.subscriptionChangeListeners.forEach(function (listener) {
|
|
68
|
+
try {
|
|
69
|
+
listener();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
var _this2$deps$getFireAn;
|
|
72
|
+
(0, _monitoring.logException)(error, {
|
|
73
|
+
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/notifySubscriptionChangeListeners'
|
|
74
|
+
});
|
|
75
|
+
(_this2$deps$getFireAn = _this2.deps.getFireAnalyticsEvent()) === null || _this2$deps$getFireAn === void 0 || _this2$deps$getFireAn((0, _errorHandling.fetchErrorPayload)(error.message));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}, {
|
|
80
|
+
key: "handleSubscriptionUpdate",
|
|
81
|
+
value: function handleSubscriptionUpdate(syncBlockInstance) {
|
|
82
|
+
if (!syncBlockInstance.resourceId) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
var existing = this.deps.getFromCache(syncBlockInstance.resourceId);
|
|
86
|
+
var resolved = existing ? (0, _resolveSyncBlockInstance.resolveSyncBlockInstance)(existing, syncBlockInstance) : syncBlockInstance;
|
|
87
|
+
this.deps.updateCache(resolved);
|
|
88
|
+
if (!syncBlockInstance.error) {
|
|
89
|
+
this.deps.fetchSyncBlockSourceInfo(resolved.resourceId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}, {
|
|
93
|
+
key: "setupSubscription",
|
|
94
|
+
value: function setupSubscription(resourceId) {
|
|
95
|
+
var _this3 = this;
|
|
96
|
+
if (this.graphqlSubscriptions.has(resourceId)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
var dataProvider = this.deps.getDataProvider();
|
|
100
|
+
if (!(dataProvider !== null && dataProvider !== void 0 && dataProvider.subscribeToBlockUpdates)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
var unsubscribe = dataProvider.subscribeToBlockUpdates(resourceId, function (syncBlockInstance) {
|
|
104
|
+
_this3.handleGraphQLUpdate(syncBlockInstance);
|
|
105
|
+
}, function (error) {
|
|
106
|
+
var _this3$deps$getFireAn;
|
|
107
|
+
(0, _monitoring.logException)(error, {
|
|
108
|
+
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/graphql-subscription'
|
|
109
|
+
});
|
|
110
|
+
(_this3$deps$getFireAn = _this3.deps.getFireAnalyticsEvent()) === null || _this3$deps$getFireAn === void 0 || _this3$deps$getFireAn((0, _errorHandling.fetchErrorPayload)(error.message));
|
|
111
|
+
});
|
|
112
|
+
if (unsubscribe) {
|
|
113
|
+
this.graphqlSubscriptions.set(resourceId, unsubscribe);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}, {
|
|
117
|
+
key: "cleanupSubscription",
|
|
118
|
+
value: function cleanupSubscription(resourceId) {
|
|
119
|
+
var unsubscribe = this.graphqlSubscriptions.get(resourceId);
|
|
120
|
+
if (unsubscribe) {
|
|
121
|
+
unsubscribe();
|
|
122
|
+
this.graphqlSubscriptions.delete(resourceId);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}, {
|
|
126
|
+
key: "setupSubscriptionsForAllBlocks",
|
|
127
|
+
value: function setupSubscriptionsForAllBlocks() {
|
|
128
|
+
var _iterator = _createForOfIteratorHelper(this.deps.getSubscriptions().keys()),
|
|
129
|
+
_step;
|
|
130
|
+
try {
|
|
131
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
132
|
+
var resourceId = _step.value;
|
|
133
|
+
this.setupSubscription(resourceId);
|
|
134
|
+
}
|
|
135
|
+
} catch (err) {
|
|
136
|
+
_iterator.e(err);
|
|
137
|
+
} finally {
|
|
138
|
+
_iterator.f();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}, {
|
|
142
|
+
key: "cleanupAll",
|
|
143
|
+
value: function cleanupAll() {
|
|
144
|
+
var _iterator2 = _createForOfIteratorHelper(this.graphqlSubscriptions.values()),
|
|
145
|
+
_step2;
|
|
146
|
+
try {
|
|
147
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
148
|
+
var unsubscribe = _step2.value;
|
|
149
|
+
unsubscribe();
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
_iterator2.e(err);
|
|
153
|
+
} finally {
|
|
154
|
+
_iterator2.f();
|
|
155
|
+
}
|
|
156
|
+
this.graphqlSubscriptions.clear();
|
|
157
|
+
}
|
|
158
|
+
}, {
|
|
159
|
+
key: "destroy",
|
|
160
|
+
value: function destroy() {
|
|
161
|
+
this.cleanupAll();
|
|
162
|
+
this.subscriptionChangeListeners.clear();
|
|
163
|
+
this.useRealTimeSubscriptions = false;
|
|
164
|
+
}
|
|
165
|
+
}, {
|
|
166
|
+
key: "shouldUseRealTime",
|
|
167
|
+
value: function shouldUseRealTime() {
|
|
168
|
+
return this.useRealTimeSubscriptions;
|
|
169
|
+
}
|
|
170
|
+
}, {
|
|
171
|
+
key: "handleGraphQLUpdate",
|
|
172
|
+
value: function handleGraphQLUpdate(syncBlockInstance) {
|
|
173
|
+
var _this4 = this;
|
|
174
|
+
if (!syncBlockInstance.resourceId) {
|
|
175
|
+
if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_5')) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
throw new Error('Sync block instance provided to graphql subscription update missing resource id');
|
|
179
|
+
}
|
|
180
|
+
var existing = this.deps.getFromCache(syncBlockInstance.resourceId);
|
|
181
|
+
var resolved = existing ? (0, _resolveSyncBlockInstance.resolveSyncBlockInstance)(existing, syncBlockInstance) : syncBlockInstance;
|
|
182
|
+
this.deps.updateCache(resolved);
|
|
183
|
+
if (!syncBlockInstance.error) {
|
|
184
|
+
var callbacks = this.deps.getSubscriptions().get(syncBlockInstance.resourceId);
|
|
185
|
+
var localIds = callbacks ? Object.keys(callbacks) : [];
|
|
186
|
+
localIds.forEach(function (localId) {
|
|
187
|
+
var _this4$deps$getFireAn, _syncBlockInstance$da;
|
|
188
|
+
(_this4$deps$getFireAn = _this4.deps.getFireAnalyticsEvent()) === null || _this4$deps$getFireAn === void 0 || _this4$deps$getFireAn((0, _errorHandling.fetchSuccessPayload)(syncBlockInstance.resourceId, localId, (_syncBlockInstance$da = syncBlockInstance.data) === null || _syncBlockInstance$da === void 0 ? void 0 : _syncBlockInstance$da.product));
|
|
189
|
+
});
|
|
190
|
+
this.deps.fetchSyncBlockSourceInfo(resolved.resourceId);
|
|
191
|
+
} else {
|
|
192
|
+
var _syncBlockInstance$er, _syncBlockInstance$er2, _syncBlockInstance$er3, _this$deps$getFireAna;
|
|
193
|
+
var errorMessage = (0, _platformFeatureFlags.fg)('platform_synced_block_patch_3') ? ((_syncBlockInstance$er = syncBlockInstance.error) === null || _syncBlockInstance$er === void 0 ? void 0 : _syncBlockInstance$er.reason) || ((_syncBlockInstance$er2 = syncBlockInstance.error) === null || _syncBlockInstance$er2 === void 0 ? void 0 : _syncBlockInstance$er2.type) : (_syncBlockInstance$er3 = syncBlockInstance.error) === null || _syncBlockInstance$er3 === void 0 ? void 0 : _syncBlockInstance$er3.type;
|
|
194
|
+
(_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(errorMessage, syncBlockInstance.resourceId));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}]);
|
|
198
|
+
}();
|
|
@@ -10,7 +10,10 @@ import { getFetchExperience, getFetchSourceInfoExperience, getSaveReferenceExper
|
|
|
10
10
|
import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
|
|
11
11
|
import { parseResourceId } from '../utils/resourceId';
|
|
12
12
|
import { createSyncBlockNode } from '../utils/utils';
|
|
13
|
+
import { SyncBlockBatchFetcher } from './syncBlockBatchFetcher';
|
|
13
14
|
import { syncBlockInMemorySessionCache } from './syncBlockInMemorySessionCache';
|
|
15
|
+
import { SyncBlockProviderFactoryManager } from './syncBlockProviderFactoryManager';
|
|
16
|
+
import { SyncBlockSubscriptionManager } from './syncBlockSubscriptionManager';
|
|
14
17
|
const CACHE_KEY_PREFIX = 'sync-block-data-';
|
|
15
18
|
|
|
16
19
|
// A store manager responsible for the lifecycle and state management of reference sync blocks in an editor instance.
|
|
@@ -66,6 +69,26 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
66
69
|
this.graphqlSubscriptions = new Map();
|
|
67
70
|
this.subscriptionChangeListeners = new Set();
|
|
68
71
|
this.newlyAddedSyncBlocks = new Set();
|
|
72
|
+
if (fg('platform_synced_block_patch_5')) {
|
|
73
|
+
this._subscriptionManager = new SyncBlockSubscriptionManager({
|
|
74
|
+
getDataProvider: () => this.dataProvider,
|
|
75
|
+
getSubscriptions: () => this.subscriptions,
|
|
76
|
+
getFromCache: rid => this.getFromCache(rid),
|
|
77
|
+
updateCache: inst => this.updateCache(inst),
|
|
78
|
+
fetchSyncBlockSourceInfo: rid => this.fetchSyncBlockSourceInfo(rid),
|
|
79
|
+
getFireAnalyticsEvent: () => this.fireAnalyticsEvent
|
|
80
|
+
});
|
|
81
|
+
this._providerFactoryManager = new SyncBlockProviderFactoryManager({
|
|
82
|
+
getDataProvider: () => this.dataProvider,
|
|
83
|
+
getFromCache: rid => this.getFromCache(rid),
|
|
84
|
+
getFireAnalyticsEvent: () => this.fireAnalyticsEvent
|
|
85
|
+
});
|
|
86
|
+
this._batchFetcher = new SyncBlockBatchFetcher({
|
|
87
|
+
getSubscriptions: () => this.subscriptions,
|
|
88
|
+
fetchSyncBlocksData: nodes => this.fetchSyncBlocksData(nodes),
|
|
89
|
+
getFireAnalyticsEvent: () => this.fireAnalyticsEvent
|
|
90
|
+
});
|
|
91
|
+
}
|
|
69
92
|
|
|
70
93
|
// The provider might have SSR data cache already set, so we need to update the cache in session memory storage
|
|
71
94
|
this.setSSRDataInSessionCache((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
|
|
@@ -78,6 +101,10 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
78
101
|
* @param enabled - Whether to enable real-time subscriptions
|
|
79
102
|
*/
|
|
80
103
|
setRealTimeSubscriptionsEnabled(enabled) {
|
|
104
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
105
|
+
this._subscriptionManager.setRealTimeSubscriptionsEnabled(enabled);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
81
108
|
if (this.useRealTimeSubscriptions === enabled) {
|
|
82
109
|
return;
|
|
83
110
|
}
|
|
@@ -95,6 +122,9 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
95
122
|
* Checks if real-time subscriptions are currently enabled.
|
|
96
123
|
*/
|
|
97
124
|
isRealTimeSubscriptionsEnabled() {
|
|
125
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
126
|
+
return this._subscriptionManager.isRealTimeSubscriptionsEnabled();
|
|
127
|
+
}
|
|
98
128
|
return this.useRealTimeSubscriptions;
|
|
99
129
|
}
|
|
100
130
|
|
|
@@ -103,6 +133,9 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
103
133
|
* Used by React components to render subscription components.
|
|
104
134
|
*/
|
|
105
135
|
getSubscribedResourceIds() {
|
|
136
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
137
|
+
return this._subscriptionManager.getSubscribedResourceIds();
|
|
138
|
+
}
|
|
106
139
|
return Array.from(this.subscriptions.keys());
|
|
107
140
|
}
|
|
108
141
|
|
|
@@ -112,6 +145,9 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
112
145
|
* @returns Unsubscribe function to remove the listener
|
|
113
146
|
*/
|
|
114
147
|
onSubscriptionsChanged(listener) {
|
|
148
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
149
|
+
return this._subscriptionManager.onSubscriptionsChanged(listener);
|
|
150
|
+
}
|
|
115
151
|
this.subscriptionChangeListeners.add(listener);
|
|
116
152
|
return () => {
|
|
117
153
|
this.subscriptionChangeListeners.delete(listener);
|
|
@@ -122,6 +158,10 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
122
158
|
* Notifies all subscription change listeners.
|
|
123
159
|
*/
|
|
124
160
|
notifySubscriptionChangeListeners() {
|
|
161
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
162
|
+
this._subscriptionManager.notifySubscriptionChangeListeners();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
125
165
|
this.subscriptionChangeListeners.forEach(listener => {
|
|
126
166
|
try {
|
|
127
167
|
listener();
|
|
@@ -141,6 +181,10 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
141
181
|
* @param syncBlockInstance - The updated sync block instance
|
|
142
182
|
*/
|
|
143
183
|
handleSubscriptionUpdate(syncBlockInstance) {
|
|
184
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
185
|
+
this._subscriptionManager.handleSubscriptionUpdate(syncBlockInstance);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
144
188
|
if (!syncBlockInstance.resourceId) {
|
|
145
189
|
return;
|
|
146
190
|
}
|
|
@@ -249,6 +293,11 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
249
293
|
*/
|
|
250
294
|
setupGraphQLSubscription(resourceId) {
|
|
251
295
|
var _this$dataProvider3;
|
|
296
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
297
|
+
this._subscriptionManager.setupSubscription(resourceId);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
252
301
|
// Don't set up duplicate subscriptions
|
|
253
302
|
if (this.graphqlSubscriptions.has(resourceId)) {
|
|
254
303
|
return;
|
|
@@ -305,6 +354,10 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
305
354
|
* @param resourceId - The resource ID of the block to unsubscribe from
|
|
306
355
|
*/
|
|
307
356
|
cleanupGraphQLSubscription(resourceId) {
|
|
357
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
358
|
+
this._subscriptionManager.cleanupSubscription(resourceId);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
308
361
|
const unsubscribe = this.graphqlSubscriptions.get(resourceId);
|
|
309
362
|
if (unsubscribe) {
|
|
310
363
|
unsubscribe();
|
|
@@ -316,6 +369,10 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
316
369
|
* Sets up GraphQL subscriptions for all currently subscribed blocks.
|
|
317
370
|
*/
|
|
318
371
|
setupGraphQLSubscriptionsForAllBlocks() {
|
|
372
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
373
|
+
this._subscriptionManager.setupSubscriptionsForAllBlocks();
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
319
376
|
for (const resourceId of this.subscriptions.keys()) {
|
|
320
377
|
this.setupGraphQLSubscription(resourceId);
|
|
321
378
|
}
|
|
@@ -325,6 +382,10 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
325
382
|
* Cleans up all GraphQL subscriptions.
|
|
326
383
|
*/
|
|
327
384
|
cleanupAllGraphQLSubscriptions() {
|
|
385
|
+
if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
|
|
386
|
+
this._subscriptionManager.cleanupAll();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
328
389
|
for (const unsubscribe of this.graphqlSubscriptions.values()) {
|
|
329
390
|
unsubscribe();
|
|
330
391
|
}
|
|
@@ -591,14 +652,13 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
591
652
|
hasUnexpectedError = true;
|
|
592
653
|
}
|
|
593
654
|
return;
|
|
594
|
-
} else {
|
|
595
|
-
const callbacks = this.subscriptions.get(syncBlockInstance.resourceId);
|
|
596
|
-
const localIds = callbacks ? Object.keys(callbacks) : [];
|
|
597
|
-
localIds.forEach(localId => {
|
|
598
|
-
var _this$fireAnalyticsEv14, _syncBlockInstance$da2;
|
|
599
|
-
(_this$fireAnalyticsEv14 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv14 === void 0 ? void 0 : _this$fireAnalyticsEv14.call(this, fetchSuccessPayload(syncBlockInstance.resourceId, localId, (_syncBlockInstance$da2 = syncBlockInstance.data) === null || _syncBlockInstance$da2 === void 0 ? void 0 : _syncBlockInstance$da2.product));
|
|
600
|
-
});
|
|
601
655
|
}
|
|
656
|
+
const callbacks = this.subscriptions.get(syncBlockInstance.resourceId);
|
|
657
|
+
const localIds = callbacks ? Object.keys(callbacks) : [];
|
|
658
|
+
localIds.forEach(localId => {
|
|
659
|
+
var _this$fireAnalyticsEv14, _syncBlockInstance$da2;
|
|
660
|
+
(_this$fireAnalyticsEv14 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv14 === void 0 ? void 0 : _this$fireAnalyticsEv14.call(this, fetchSuccessPayload(syncBlockInstance.resourceId, localId, (_syncBlockInstance$da2 = syncBlockInstance.data) === null || _syncBlockInstance$da2 === void 0 ? void 0 : _syncBlockInstance$da2.product));
|
|
661
|
+
});
|
|
602
662
|
this.fetchSyncBlockSourceInfo(resolvedSyncBlockInstance.resourceId);
|
|
603
663
|
});
|
|
604
664
|
return {
|
|
@@ -659,9 +719,17 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
659
719
|
deleteFromCache(resourceId) {
|
|
660
720
|
var _this$dataProvider6;
|
|
661
721
|
(_this$dataProvider6 = this.dataProvider) === null || _this$dataProvider6 === void 0 ? void 0 : _this$dataProvider6.removeFromCache([resourceId]);
|
|
662
|
-
this.
|
|
722
|
+
if (this._providerFactoryManager && fg('platform_synced_block_patch_5')) {
|
|
723
|
+
this._providerFactoryManager.deleteFactory(resourceId);
|
|
724
|
+
} else {
|
|
725
|
+
this.providerFactories.delete(resourceId);
|
|
726
|
+
}
|
|
663
727
|
}
|
|
664
728
|
debouncedBatchedFetchSyncBlocks(resourceId) {
|
|
729
|
+
if (this._batchFetcher && fg('platform_synced_block_patch_5')) {
|
|
730
|
+
this._batchFetcher.queueFetch(resourceId);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
665
733
|
// Only add to pending requests if there are active subscriptions for this resource
|
|
666
734
|
if (this.subscriptions.has(resourceId) && Object.keys(this.subscriptions.get(resourceId) || {}).length > 0) {
|
|
667
735
|
this.pendingFetchRequests.add(resourceId);
|
|
@@ -714,7 +782,8 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
714
782
|
}
|
|
715
783
|
|
|
716
784
|
// Set up GraphQL subscription if real-time subscriptions are enabled
|
|
717
|
-
|
|
785
|
+
const useRealTime = this._subscriptionManager && fg('platform_synced_block_patch_5') ? this._subscriptionManager.shouldUseRealTime() : this.useRealTimeSubscriptions;
|
|
786
|
+
if (useRealTime) {
|
|
718
787
|
this.setupGraphQLSubscription(resourceId);
|
|
719
788
|
}
|
|
720
789
|
return () => {
|
|
@@ -825,6 +894,9 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
825
894
|
return (_syncBlock$data = syncBlock.data) === null || _syncBlock$data === void 0 ? void 0 : _syncBlock$data.sourceURL;
|
|
826
895
|
}
|
|
827
896
|
getProviderFactory(resourceId) {
|
|
897
|
+
if (this._providerFactoryManager && fg('platform_synced_block_patch_5')) {
|
|
898
|
+
return this._providerFactoryManager.getProviderFactory(resourceId);
|
|
899
|
+
}
|
|
828
900
|
if (!this.dataProvider) {
|
|
829
901
|
var _this$fireAnalyticsEv16;
|
|
830
902
|
const error = new Error('Data provider not set');
|
|
@@ -871,6 +943,9 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
871
943
|
return providerFactory;
|
|
872
944
|
}
|
|
873
945
|
getSSRProviders(resourceId) {
|
|
946
|
+
if (this._providerFactoryManager && fg('platform_synced_block_patch_5')) {
|
|
947
|
+
return this._providerFactoryManager.getSSRProviders(resourceId);
|
|
948
|
+
}
|
|
874
949
|
if (!this.dataProvider) {
|
|
875
950
|
return null;
|
|
876
951
|
}
|
|
@@ -1077,6 +1152,12 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
1077
1152
|
clearTimeout(this.queuedFlushTimeout);
|
|
1078
1153
|
this.queuedFlushTimeout = undefined;
|
|
1079
1154
|
}
|
|
1155
|
+
if (fg('platform_synced_block_patch_5')) {
|
|
1156
|
+
var _this$_subscriptionMa, _this$_providerFactor, _this$_batchFetcher;
|
|
1157
|
+
(_this$_subscriptionMa = this._subscriptionManager) === null || _this$_subscriptionMa === void 0 ? void 0 : _this$_subscriptionMa.destroy();
|
|
1158
|
+
(_this$_providerFactor = this._providerFactoryManager) === null || _this$_providerFactor === void 0 ? void 0 : _this$_providerFactor.destroy();
|
|
1159
|
+
(_this$_batchFetcher = this._batchFetcher) === null || _this$_batchFetcher === void 0 ? void 0 : _this$_batchFetcher.destroy();
|
|
1160
|
+
}
|
|
1080
1161
|
|
|
1081
1162
|
// Clean up all GraphQL subscriptions first
|
|
1082
1163
|
this.cleanupAllGraphQLSubscriptions();
|
|
@@ -1105,5 +1186,8 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
1105
1186
|
reason: 'editorDestroyed'
|
|
1106
1187
|
});
|
|
1107
1188
|
this.fireAnalyticsEvent = undefined;
|
|
1189
|
+
if (fg('platform_synced_block_patch_5')) {
|
|
1190
|
+
syncBlockInMemorySessionCache.clear();
|
|
1191
|
+
}
|
|
1108
1192
|
}
|
|
1109
1193
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import isEqual from 'lodash/isEqual';
|
|
2
3
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
5
|
import { SyncBlockError } from '../common/types';
|
|
4
6
|
import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
|
|
5
7
|
import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
|
|
@@ -11,6 +13,7 @@ import { convertSyncBlockPMNodeToSyncBlockData } from '../utils/utils';
|
|
|
11
13
|
// Ensures consistency between local and remote state, and can be used in both editor and renderer contexts.
|
|
12
14
|
export class SourceSyncBlockStoreManager {
|
|
13
15
|
constructor(dataProvider) {
|
|
16
|
+
_defineProperty(this, "hasReceivedContentChange", false);
|
|
14
17
|
_defineProperty(this, "setPendingDeletion", (Ids, value) => {
|
|
15
18
|
const syncBlock = this.syncBlockCache.get(Ids.resourceId);
|
|
16
19
|
if (syncBlock) {
|
|
@@ -49,6 +52,12 @@ export class SourceSyncBlockStoreManager {
|
|
|
49
52
|
throw new Error('Local ID or resource ID is not set');
|
|
50
53
|
}
|
|
51
54
|
const syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
|
|
55
|
+
if (fg('platform_synced_block_patch_5')) {
|
|
56
|
+
const cachedBlock = this.syncBlockCache.get(resourceId);
|
|
57
|
+
if (cachedBlock && !isEqual(syncBlockData.content, cachedBlock.content)) {
|
|
58
|
+
this.hasReceivedContentChange = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
52
61
|
this.syncBlockCache.set(resourceId, {
|
|
53
62
|
...syncBlockData,
|
|
54
63
|
isDirty: true
|
|
@@ -146,6 +155,9 @@ export class SourceSyncBlockStoreManager {
|
|
|
146
155
|
return false;
|
|
147
156
|
}
|
|
148
157
|
}
|
|
158
|
+
hasUnsavedChanges() {
|
|
159
|
+
return this.hasReceivedContentChange && Array.from(this.syncBlockCache.values()).some(syncBlockData => syncBlockData.isDirty);
|
|
160
|
+
}
|
|
149
161
|
isPendingCreation(resourceId) {
|
|
150
162
|
return this.creationCompletionCallbacks.has(resourceId);
|
|
151
163
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import rafSchedule from 'raf-schd';
|
|
3
|
+
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
4
|
+
import { fetchErrorPayload } from '../utils/errorHandling';
|
|
5
|
+
import { createSyncBlockNode } from '../utils/utils';
|
|
6
|
+
/**
|
|
7
|
+
* Handles debounced batch-fetching of sync block data via `raf-schd`.
|
|
8
|
+
* Accumulates resource IDs and flushes them in a single fetch per
|
|
9
|
+
* animation frame.
|
|
10
|
+
*/
|
|
11
|
+
export class SyncBlockBatchFetcher {
|
|
12
|
+
constructor(deps) {
|
|
13
|
+
_defineProperty(this, "pendingFetchRequests", new Set());
|
|
14
|
+
this.deps = deps;
|
|
15
|
+
this.scheduledBatchFetch = rafSchedule(() => {
|
|
16
|
+
if (this.pendingFetchRequests.size === 0) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const resourceIds = Array.from(this.pendingFetchRequests);
|
|
20
|
+
const syncBlockNodes = resourceIds.map(resId => {
|
|
21
|
+
const subscriptions = this.deps.getSubscriptions().get(resId) || {};
|
|
22
|
+
const firstLocalId = Object.keys(subscriptions)[0] || '';
|
|
23
|
+
return createSyncBlockNode(firstLocalId, resId);
|
|
24
|
+
});
|
|
25
|
+
this.pendingFetchRequests.clear();
|
|
26
|
+
this.deps.fetchSyncBlocksData(syncBlockNodes).catch(error => {
|
|
27
|
+
logException(error, {
|
|
28
|
+
location: 'editor-synced-block-provider/syncBlockBatchFetcher/batchedFetchSyncBlocks'
|
|
29
|
+
});
|
|
30
|
+
resourceIds.forEach(resId => {
|
|
31
|
+
var _this$deps$getFireAna;
|
|
32
|
+
(_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 ? void 0 : _this$deps$getFireAna(fetchErrorPayload(error.message, resId));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
queueFetch(resourceId) {
|
|
38
|
+
const subscriptions = this.deps.getSubscriptions();
|
|
39
|
+
if (subscriptions.has(resourceId) && Object.keys(subscriptions.get(resourceId) || {}).length > 0) {
|
|
40
|
+
this.pendingFetchRequests.add(resourceId);
|
|
41
|
+
this.scheduledBatchFetch();
|
|
42
|
+
} else {
|
|
43
|
+
this.pendingFetchRequests.delete(resourceId);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
cancel() {
|
|
47
|
+
this.scheduledBatchFetch.cancel();
|
|
48
|
+
}
|
|
49
|
+
clearPending() {
|
|
50
|
+
this.pendingFetchRequests.clear();
|
|
51
|
+
}
|
|
52
|
+
destroy() {
|
|
53
|
+
this.cancel();
|
|
54
|
+
this.clearPending();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -13,11 +13,26 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
13
13
|
* (least-recently-used) entries are evicted first.
|
|
14
14
|
*/
|
|
15
15
|
export class SyncBlockInMemorySessionCache {
|
|
16
|
+
/**
|
|
17
|
+
* Maximum total size of all cached values, measured in **UTF-16 code
|
|
18
|
+
* units** (i.e. `String.prototype.length`), not bytes. For ASCII-only
|
|
19
|
+
* content the two are equivalent; for content with characters outside
|
|
20
|
+
* the BMP each surrogate pair counts as 2.
|
|
21
|
+
*/
|
|
22
|
+
|
|
16
23
|
constructor(maxSize = 5 * 1024 * 1024) {
|
|
17
24
|
_defineProperty(this, "store", new Map());
|
|
18
25
|
_defineProperty(this, "currentSize", 0);
|
|
19
26
|
this.maxSize = maxSize;
|
|
20
27
|
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Retrieves a cached value by key.
|
|
31
|
+
*
|
|
32
|
+
* **Side-effect:** promotes the entry to the most-recently-used
|
|
33
|
+
* position by re-inserting it at the end of the underlying Map's
|
|
34
|
+
* iteration order.
|
|
35
|
+
*/
|
|
21
36
|
getItem(key) {
|
|
22
37
|
const value = this.store.get(key);
|
|
23
38
|
if (value === undefined) {
|
|
@@ -53,5 +68,14 @@ export class SyncBlockInMemorySessionCache {
|
|
|
53
68
|
this.store.delete(key);
|
|
54
69
|
}
|
|
55
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Removes all entries from the cache and resets the tracked size to zero.
|
|
74
|
+
* Useful for cleaning up the singleton on SPA navigation boundaries.
|
|
75
|
+
*/
|
|
76
|
+
clear() {
|
|
77
|
+
this.store.clear();
|
|
78
|
+
this.currentSize = 0;
|
|
79
|
+
}
|
|
56
80
|
}
|
|
57
81
|
export const syncBlockInMemorySessionCache = new SyncBlockInMemorySessionCache();
|