@atlaskit/editor-plugin-collab-edit 3.7.2 → 3.9.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.
- package/CHANGELOG.md +21 -0
- package/dist/cjs/collabEditPlugin.js +14 -4
- package/dist/cjs/pm-plugins/events/send-transaction.js +12 -2
- package/dist/cjs/pm-plugins/mergeUnconfirmed.js +21 -1
- package/dist/cjs/pm-plugins/track-step-metrics.js +80 -0
- package/dist/cjs/pm-plugins/track-steps.js +12 -2
- package/dist/es2019/collabEditPlugin.js +13 -2
- package/dist/es2019/pm-plugins/events/send-transaction.js +12 -2
- package/dist/es2019/pm-plugins/mergeUnconfirmed.js +19 -1
- package/dist/es2019/pm-plugins/track-step-metrics.js +77 -0
- package/dist/es2019/pm-plugins/track-steps.js +13 -1
- package/dist/esm/collabEditPlugin.js +15 -5
- package/dist/esm/pm-plugins/events/send-transaction.js +12 -2
- package/dist/esm/pm-plugins/mergeUnconfirmed.js +19 -1
- package/dist/esm/pm-plugins/track-step-metrics.js +73 -0
- package/dist/esm/pm-plugins/track-steps.js +12 -2
- package/dist/types/pm-plugins/mergeUnconfirmed.d.ts +9 -2
- package/dist/types/pm-plugins/track-step-metrics.d.ts +17 -0
- package/dist/types/pm-plugins/track-steps.d.ts +5 -1
- package/dist/types-ts4.5/pm-plugins/mergeUnconfirmed.d.ts +9 -2
- package/dist/types-ts4.5/pm-plugins/track-step-metrics.d.ts +17 -0
- package/dist/types-ts4.5/pm-plugins/track-steps.d.ts +5 -1
- package/package.json +8 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-collab-edit
|
|
2
2
|
|
|
3
|
+
## 3.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#159232](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/159232)
|
|
8
|
+
[`3edd7f2ef67fa`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3edd7f2ef67fa) -
|
|
9
|
+
[EDITOR-752] Add updateSessionMetrics to collab plugin, this will track and store the steps in a
|
|
10
|
+
single collab session
|
|
11
|
+
|
|
12
|
+
## 3.8.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- [#154562](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/154562)
|
|
17
|
+
[`9a3495cb72638`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9a3495cb72638) -
|
|
18
|
+
Support AnalyticsStep filtering for collab
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
|
|
3
24
|
## 3.7.2
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -201,14 +201,22 @@ var collabEditPlugin = exports.collabEditPlugin = function collabEditPlugin(_ref
|
|
|
201
201
|
useNativePlugin = _ref5$useNativePlugin === void 0 ? false : _ref5$useNativePlugin,
|
|
202
202
|
_ref5$userId = _ref5.userId,
|
|
203
203
|
userId = _ref5$userId === void 0 ? null : _ref5$userId;
|
|
204
|
+
var transformUnconfirmed = function transformUnconfirmed(steps) {
|
|
205
|
+
var transformed = steps;
|
|
206
|
+
if ((0, _experiments.editorExperiment)('platform_editor_reduce_noisy_steps_ncs', true)) {
|
|
207
|
+
transformed = (0, _mergeUnconfirmed.filterAnalyticsSteps)(transformed);
|
|
208
|
+
}
|
|
209
|
+
if ((0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true)) {
|
|
210
|
+
transformed = (0, _mergeUnconfirmed.mergeUnconfirmedSteps)(transformed, api);
|
|
211
|
+
}
|
|
212
|
+
return transformed;
|
|
213
|
+
};
|
|
204
214
|
var plugins = [].concat((0, _toConsumableArray2.default)(useNativePlugin ? [{
|
|
205
215
|
name: 'pmCollab',
|
|
206
216
|
plugin: function plugin() {
|
|
207
217
|
return (0, _prosemirrorCollab.collab)({
|
|
208
218
|
clientID: userId,
|
|
209
|
-
transformUnconfirmed:
|
|
210
|
-
return (0, _mergeUnconfirmed.mergeUnconfirmedSteps)(steps, api);
|
|
211
|
-
} : undefined
|
|
219
|
+
transformUnconfirmed: transformUnconfirmed
|
|
212
220
|
});
|
|
213
221
|
}
|
|
214
222
|
}, {
|
|
@@ -274,7 +282,9 @@ var collabEditPlugin = exports.collabEditPlugin = function collabEditPlugin(_ref
|
|
|
274
282
|
hideTelecursorOnLoad: !isEmptyDoc && ((_options$hideTelecurs = options.hideTelecursorOnLoad) !== null && _options$hideTelecurs !== void 0 ? _options$hideTelecurs : false),
|
|
275
283
|
viewMode: viewMode
|
|
276
284
|
}), addErrorAnalytics);
|
|
277
|
-
(0, _trackSteps.track)(_objectSpread(_objectSpread({
|
|
285
|
+
(0, _trackSteps.track)(_objectSpread(_objectSpread({
|
|
286
|
+
api: api
|
|
287
|
+
}, props), {}, {
|
|
278
288
|
onTrackDataProcessed: function onTrackDataProcessed(steps) {
|
|
279
289
|
var _api$analytics3;
|
|
280
290
|
api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.fireAnalyticsEvent({
|
|
@@ -4,7 +4,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.sendTransaction = void 0;
|
|
7
|
+
var _steps = require("@atlaskit/adf-schema/steps");
|
|
7
8
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
9
|
+
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
|
|
8
10
|
var _actions = require("../actions");
|
|
9
11
|
var _pluginKey = require("../main/plugin-key");
|
|
10
12
|
var sendTransaction = exports.sendTransaction = function sendTransaction(_ref) {
|
|
@@ -20,15 +22,23 @@ var sendTransaction = exports.sendTransaction = function sendTransaction(_ref) {
|
|
|
20
22
|
return tr.docChanged;
|
|
21
23
|
});
|
|
22
24
|
var currentPluginState = _pluginKey.pluginKey.getState(newEditorState);
|
|
25
|
+
var tr = oldEditorState.tr;
|
|
26
|
+
var trNoAnalytics = docChangedTransaction === null || docChangedTransaction === void 0 ? void 0 : docChangedTransaction.steps.reduce(function (nextTr, step) {
|
|
27
|
+
if (!(step instanceof _steps.AnalyticsStep)) {
|
|
28
|
+
return nextTr.step(step);
|
|
29
|
+
}
|
|
30
|
+
return nextTr;
|
|
31
|
+
}, tr);
|
|
23
32
|
if (!(currentPluginState !== null && currentPluginState !== void 0 && currentPluginState.isReady)) {
|
|
24
33
|
return;
|
|
25
34
|
}
|
|
35
|
+
var newTransaction = (0, _experiments.editorExperiment)('platform_editor_reduce_noisy_steps_ncs', true) ? trNoAnalytics : docChangedTransaction;
|
|
26
36
|
var shouldSendStepForSynchronyCollabProvider = !originalTransaction.getMeta('isRemote') &&
|
|
27
37
|
// TODO: ED-8995 - We need to do this check to reduce the number of race conditions when working with tables.
|
|
28
38
|
// This metadata is coming from the scaleTable command in table-resizing plugin
|
|
29
|
-
!originalTransaction.getMeta('scaleTable') &&
|
|
39
|
+
!originalTransaction.getMeta('scaleTable') && ((0, _experiments.editorExperiment)('platform_editor_reduce_noisy_steps_ncs', true) ? newTransaction === null || newTransaction === void 0 ? void 0 : newTransaction.docChanged : true);
|
|
30
40
|
if (useNativePlugin || shouldSendStepForSynchronyCollabProvider) {
|
|
31
|
-
provider.send(
|
|
41
|
+
provider.send(newTransaction, oldEditorState, newEditorState);
|
|
32
42
|
}
|
|
33
43
|
var prevPluginState = _pluginKey.pluginKey.getState(oldEditorState);
|
|
34
44
|
var _ref2 = prevPluginState || {},
|
|
@@ -4,12 +4,15 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
+
exports.LockableRebaseable = void 0;
|
|
8
|
+
exports.filterAnalyticsSteps = filterAnalyticsSteps;
|
|
7
9
|
exports.mergeUnconfirmedSteps = mergeUnconfirmedSteps;
|
|
8
10
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
9
11
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
12
|
+
var _steps = require("@atlaskit/adf-schema/steps");
|
|
10
13
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
11
14
|
// Based on: `packages/editor/prosemirror-collab/src/index.ts`
|
|
12
|
-
var LockableRebaseable = /*#__PURE__*/(0, _createClass2.default)(function LockableRebaseable(step, inverted, origin) {
|
|
15
|
+
var LockableRebaseable = exports.LockableRebaseable = /*#__PURE__*/(0, _createClass2.default)(function LockableRebaseable(step, inverted, origin) {
|
|
13
16
|
(0, _classCallCheck2.default)(this, LockableRebaseable);
|
|
14
17
|
this.step = step;
|
|
15
18
|
this.inverted = inverted;
|
|
@@ -53,4 +56,21 @@ function mergeUnconfirmedSteps(steps, api) {
|
|
|
53
56
|
return acc.concat(new LockableRebaseable(rebaseable.step, rebaseable.inverted, rebaseable.origin instanceof _state.Transaction ? rebaseable.origin.setMeta('isOffline', rebaseable.origin.getMeta('isOffline') === true || isOffline) : rebaseable.origin));
|
|
54
57
|
}, []);
|
|
55
58
|
return mergedSteps;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Filter out AnalyticsStep from the steps.
|
|
63
|
+
*
|
|
64
|
+
* @param steps Rebaseable steps
|
|
65
|
+
* @returns Rebaseable steps
|
|
66
|
+
* @example
|
|
67
|
+
*/
|
|
68
|
+
function filterAnalyticsSteps(steps) {
|
|
69
|
+
var filteredSteps = steps.reduce(function (acc, rebaseable) {
|
|
70
|
+
if (rebaseable.step instanceof _steps.AnalyticsStep) {
|
|
71
|
+
return acc;
|
|
72
|
+
}
|
|
73
|
+
return acc.concat(new LockableRebaseable(rebaseable.step, rebaseable.inverted, rebaseable.origin));
|
|
74
|
+
}, []);
|
|
75
|
+
return filteredSteps;
|
|
56
76
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.updateStepSessionMetrics = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _frontendUtilities = require("@atlaskit/frontend-utilities");
|
|
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
|
+
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; }
|
|
12
|
+
var STORAGE_CLIENT_KEY = 'ncs-step-metrics-storage';
|
|
13
|
+
var storageClient = new _frontendUtilities.StorageClient(STORAGE_CLIENT_KEY);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Gets the current step session metrics for a given session ID
|
|
17
|
+
* If the session ID does not exist, it initializes a new metrics object.
|
|
18
|
+
* It calculates the total size of the steps, the number of steps,
|
|
19
|
+
* the maximum step size, and the sum of step sizes for P90 calculation.
|
|
20
|
+
*
|
|
21
|
+
* @param metrics - The existing metrics object from local storage.
|
|
22
|
+
* @param sessionId - The session ID for which to get the metrics.
|
|
23
|
+
* @param steps - The steps to calculate the metrics from.
|
|
24
|
+
* @returns The updated step session metrics for the given session ID.
|
|
25
|
+
*/
|
|
26
|
+
var getStepSessionMetrics = function getStepSessionMetrics(metrics, sessionId, steps) {
|
|
27
|
+
var _metrics$sessionId;
|
|
28
|
+
var current = (_metrics$sessionId = metrics[sessionId]) !== null && _metrics$sessionId !== void 0 ? _metrics$sessionId : {
|
|
29
|
+
totalStepSize: 0,
|
|
30
|
+
numberOfSteps: 0,
|
|
31
|
+
maxStepSize: 0,
|
|
32
|
+
stepSizeSumForP90: []
|
|
33
|
+
};
|
|
34
|
+
steps.forEach(function (step) {
|
|
35
|
+
var stepSize = JSON.stringify(step).length;
|
|
36
|
+
current.totalStepSize += stepSize;
|
|
37
|
+
current.numberOfSteps += 1;
|
|
38
|
+
current.maxStepSize = Math.max(current.maxStepSize, stepSize || 0);
|
|
39
|
+
current.stepSizeSumForP90.push(stepSize || 0);
|
|
40
|
+
});
|
|
41
|
+
return current;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Gets the current active sessions from local storage
|
|
46
|
+
* If the session ID does not exist, it initializes a new active session.
|
|
47
|
+
*
|
|
48
|
+
* This is used in the ncsStepMetricsPlugin to determine if the session is still active
|
|
49
|
+
* before sending the ncs steps analytics event.
|
|
50
|
+
*
|
|
51
|
+
* @param sessionId - The session ID to check or update in local storage.
|
|
52
|
+
* @returns void
|
|
53
|
+
*/
|
|
54
|
+
var updateActiveSessions = function updateActiveSessions(sessionId) {
|
|
55
|
+
var currentActiveSessions = JSON.parse(storageClient.getItem('activeSessions') || '{}');
|
|
56
|
+
if (!currentActiveSessions[sessionId]) {
|
|
57
|
+
storageClient.setItemWithExpiry('ncsActiveSessions', JSON.stringify(_objectSpread(_objectSpread({}, currentActiveSessions), {}, (0, _defineProperty2.default)({}, sessionId, true))));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Updates the step session metrics in local storage for a given session ID.
|
|
62
|
+
* It calculates the metrics based on the provided steps and updates the storage.
|
|
63
|
+
*
|
|
64
|
+
* @param api - The API to access the collab edit plugin.
|
|
65
|
+
* @param steps - The steps to calculate the metrics from.
|
|
66
|
+
* @return void
|
|
67
|
+
*/
|
|
68
|
+
var updateStepSessionMetrics = exports.updateStepSessionMetrics = function updateStepSessionMetrics(_ref) {
|
|
69
|
+
var _api$collabEdit;
|
|
70
|
+
var api = _ref.api,
|
|
71
|
+
steps = _ref.steps;
|
|
72
|
+
var sessionId = api === null || api === void 0 || (_api$collabEdit = api.collabEdit) === null || _api$collabEdit === void 0 || (_api$collabEdit = _api$collabEdit.sharedState.currentState()) === null || _api$collabEdit === void 0 ? void 0 : _api$collabEdit.sessionId;
|
|
73
|
+
if (!sessionId) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
var existingMetrics = JSON.parse(storageClient.getItem('ncsStepSessionMetrics') || '{}');
|
|
77
|
+
var stepSessionMetrics = getStepSessionMetrics(existingMetrics, sessionId, steps);
|
|
78
|
+
storageClient.setItemWithExpiry('ncsStepSessionMetrics', JSON.stringify(_objectSpread(_objectSpread({}, existingMetrics), {}, (0, _defineProperty2.default)({}, sessionId, stepSessionMetrics))));
|
|
79
|
+
updateActiveSessions(sessionId);
|
|
80
|
+
};
|
|
@@ -8,7 +8,9 @@ exports.track = exports.task = exports.sanitizeStep = exports.groupSteps = void
|
|
|
8
8
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
9
|
var _steps = require("@atlaskit/adf-schema/steps");
|
|
10
10
|
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
11
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
11
12
|
var _prosemirrorCollab = require("@atlaskit/prosemirror-collab");
|
|
13
|
+
var _trackStepMetrics = require("./track-step-metrics");
|
|
12
14
|
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; } } }; }
|
|
13
15
|
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; } }
|
|
14
16
|
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; }
|
|
@@ -146,12 +148,14 @@ var getScheduler = function getScheduler(obj) {
|
|
|
146
148
|
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
147
149
|
*
|
|
148
150
|
* @param {TrackProps} props - The properties required for tracking steps.
|
|
151
|
+
* @param {ExtractInjectionAPI<CollabEditPlugin> | undefined} props.api - The API for the CollabEdit plugin.
|
|
149
152
|
* @param {EditorState} props.newEditorState - The new editor state.
|
|
150
153
|
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
151
154
|
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
152
155
|
*/
|
|
153
156
|
var track = exports.track = function track(_ref3) {
|
|
154
|
-
var
|
|
157
|
+
var api = _ref3.api,
|
|
158
|
+
newEditorState = _ref3.newEditorState,
|
|
155
159
|
transactions = _ref3.transactions,
|
|
156
160
|
onTrackDataProcessed = _ref3.onTrackDataProcessed;
|
|
157
161
|
var newSteps = transactions.flatMap(function (t) {
|
|
@@ -173,7 +177,13 @@ var track = exports.track = function track(_ref3) {
|
|
|
173
177
|
steps: steps
|
|
174
178
|
});
|
|
175
179
|
scheduler.postTask(function () {
|
|
176
|
-
|
|
180
|
+
if ((0, _platformFeatureFlags.fg)('platform_enable_ncs_step_metrics')) {
|
|
181
|
+
(0, _trackStepMetrics.updateStepSessionMetrics)({
|
|
182
|
+
api: api,
|
|
183
|
+
steps: newSteps
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
task(stepsSentCache, onTrackDataProcessed);
|
|
177
187
|
}, {
|
|
178
188
|
priority: 'background',
|
|
179
189
|
delay: LOW_PRIORITY_DELAY
|
|
@@ -8,7 +8,7 @@ import { addSynchronyErrorAnalytics } from './pm-plugins/analytics';
|
|
|
8
8
|
import { sendTransaction } from './pm-plugins/events/send-transaction';
|
|
9
9
|
import { createPlugin } from './pm-plugins/main';
|
|
10
10
|
import { pluginKey as mainPluginKey } from './pm-plugins/main/plugin-key';
|
|
11
|
-
import { mergeUnconfirmedSteps } from './pm-plugins/mergeUnconfirmed';
|
|
11
|
+
import { filterAnalyticsSteps, mergeUnconfirmedSteps } from './pm-plugins/mergeUnconfirmed';
|
|
12
12
|
import { nativeCollabProviderPlugin } from './pm-plugins/native-collab-provider-plugin';
|
|
13
13
|
import { sanitizeFilteredStep, createPlugin as trackSpammingStepsPlugin } from './pm-plugins/track-and-filter-spamming-steps';
|
|
14
14
|
import { createPlugin as createLastOrganicChangePlugin, trackLastOrganicChangePluginKey } from './pm-plugins/track-last-organic-change';
|
|
@@ -156,11 +156,21 @@ export const collabEditPlugin = ({
|
|
|
156
156
|
useNativePlugin = false,
|
|
157
157
|
userId = null
|
|
158
158
|
} = options || {};
|
|
159
|
+
const transformUnconfirmed = steps => {
|
|
160
|
+
let transformed = steps;
|
|
161
|
+
if (editorExperiment('platform_editor_reduce_noisy_steps_ncs', true)) {
|
|
162
|
+
transformed = filterAnalyticsSteps(transformed);
|
|
163
|
+
}
|
|
164
|
+
if (editorExperiment('platform_editor_offline_editing_web', true)) {
|
|
165
|
+
transformed = mergeUnconfirmedSteps(transformed, api);
|
|
166
|
+
}
|
|
167
|
+
return transformed;
|
|
168
|
+
};
|
|
159
169
|
const plugins = [...(useNativePlugin ? [{
|
|
160
170
|
name: 'pmCollab',
|
|
161
171
|
plugin: () => collab({
|
|
162
172
|
clientID: userId,
|
|
163
|
-
transformUnconfirmed
|
|
173
|
+
transformUnconfirmed
|
|
164
174
|
})
|
|
165
175
|
}, {
|
|
166
176
|
name: 'nativeCollabProviderPlugin',
|
|
@@ -221,6 +231,7 @@ export const collabEditPlugin = ({
|
|
|
221
231
|
viewMode
|
|
222
232
|
}), addErrorAnalytics);
|
|
223
233
|
track({
|
|
234
|
+
api,
|
|
224
235
|
...props,
|
|
225
236
|
onTrackDataProcessed: steps => {
|
|
226
237
|
var _api$analytics3, _api$analytics3$actio;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
|
|
1
2
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
2
4
|
import { getSendableSelection } from '../actions';
|
|
3
5
|
import { pluginKey } from '../main/plugin-key';
|
|
4
6
|
export const sendTransaction = ({
|
|
@@ -12,15 +14,23 @@ export const sendTransaction = ({
|
|
|
12
14
|
}) => provider => {
|
|
13
15
|
const docChangedTransaction = transactions.find(tr => tr.docChanged);
|
|
14
16
|
const currentPluginState = pluginKey.getState(newEditorState);
|
|
17
|
+
const tr = oldEditorState.tr;
|
|
18
|
+
const trNoAnalytics = docChangedTransaction === null || docChangedTransaction === void 0 ? void 0 : docChangedTransaction.steps.reduce((nextTr, step) => {
|
|
19
|
+
if (!(step instanceof AnalyticsStep)) {
|
|
20
|
+
return nextTr.step(step);
|
|
21
|
+
}
|
|
22
|
+
return nextTr;
|
|
23
|
+
}, tr);
|
|
15
24
|
if (!(currentPluginState !== null && currentPluginState !== void 0 && currentPluginState.isReady)) {
|
|
16
25
|
return;
|
|
17
26
|
}
|
|
27
|
+
const newTransaction = editorExperiment('platform_editor_reduce_noisy_steps_ncs', true) ? trNoAnalytics : docChangedTransaction;
|
|
18
28
|
const shouldSendStepForSynchronyCollabProvider = !originalTransaction.getMeta('isRemote') &&
|
|
19
29
|
// TODO: ED-8995 - We need to do this check to reduce the number of race conditions when working with tables.
|
|
20
30
|
// This metadata is coming from the scaleTable command in table-resizing plugin
|
|
21
|
-
!originalTransaction.getMeta('scaleTable') &&
|
|
31
|
+
!originalTransaction.getMeta('scaleTable') && (editorExperiment('platform_editor_reduce_noisy_steps_ncs', true) ? newTransaction === null || newTransaction === void 0 ? void 0 : newTransaction.docChanged : true);
|
|
22
32
|
if (useNativePlugin || shouldSendStepForSynchronyCollabProvider) {
|
|
23
|
-
provider.send(
|
|
33
|
+
provider.send(newTransaction, oldEditorState, newEditorState);
|
|
24
34
|
}
|
|
25
35
|
const prevPluginState = pluginKey.getState(oldEditorState);
|
|
26
36
|
const {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
|
|
1
2
|
import { Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
2
3
|
// Based on: `packages/editor/prosemirror-collab/src/index.ts`
|
|
3
|
-
class LockableRebaseable {
|
|
4
|
+
export class LockableRebaseable {
|
|
4
5
|
constructor(step, inverted, origin) {
|
|
5
6
|
this.step = step;
|
|
6
7
|
this.inverted = inverted;
|
|
@@ -45,4 +46,21 @@ export function mergeUnconfirmedSteps(steps, api) {
|
|
|
45
46
|
return acc.concat(new LockableRebaseable(rebaseable.step, rebaseable.inverted, rebaseable.origin instanceof Transaction ? rebaseable.origin.setMeta('isOffline', rebaseable.origin.getMeta('isOffline') === true || isOffline) : rebaseable.origin));
|
|
46
47
|
}, []);
|
|
47
48
|
return mergedSteps;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Filter out AnalyticsStep from the steps.
|
|
53
|
+
*
|
|
54
|
+
* @param steps Rebaseable steps
|
|
55
|
+
* @returns Rebaseable steps
|
|
56
|
+
* @example
|
|
57
|
+
*/
|
|
58
|
+
export function filterAnalyticsSteps(steps) {
|
|
59
|
+
const filteredSteps = steps.reduce((acc, rebaseable) => {
|
|
60
|
+
if (rebaseable.step instanceof AnalyticsStep) {
|
|
61
|
+
return acc;
|
|
62
|
+
}
|
|
63
|
+
return acc.concat(new LockableRebaseable(rebaseable.step, rebaseable.inverted, rebaseable.origin));
|
|
64
|
+
}, []);
|
|
65
|
+
return filteredSteps;
|
|
48
66
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { StorageClient } from '@atlaskit/frontend-utilities';
|
|
2
|
+
const STORAGE_CLIENT_KEY = 'ncs-step-metrics-storage';
|
|
3
|
+
const storageClient = new StorageClient(STORAGE_CLIENT_KEY);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Gets the current step session metrics for a given session ID
|
|
7
|
+
* If the session ID does not exist, it initializes a new metrics object.
|
|
8
|
+
* It calculates the total size of the steps, the number of steps,
|
|
9
|
+
* the maximum step size, and the sum of step sizes for P90 calculation.
|
|
10
|
+
*
|
|
11
|
+
* @param metrics - The existing metrics object from local storage.
|
|
12
|
+
* @param sessionId - The session ID for which to get the metrics.
|
|
13
|
+
* @param steps - The steps to calculate the metrics from.
|
|
14
|
+
* @returns The updated step session metrics for the given session ID.
|
|
15
|
+
*/
|
|
16
|
+
const getStepSessionMetrics = (metrics, sessionId, steps) => {
|
|
17
|
+
var _metrics$sessionId;
|
|
18
|
+
const current = (_metrics$sessionId = metrics[sessionId]) !== null && _metrics$sessionId !== void 0 ? _metrics$sessionId : {
|
|
19
|
+
totalStepSize: 0,
|
|
20
|
+
numberOfSteps: 0,
|
|
21
|
+
maxStepSize: 0,
|
|
22
|
+
stepSizeSumForP90: []
|
|
23
|
+
};
|
|
24
|
+
steps.forEach(step => {
|
|
25
|
+
const stepSize = JSON.stringify(step).length;
|
|
26
|
+
current.totalStepSize += stepSize;
|
|
27
|
+
current.numberOfSteps += 1;
|
|
28
|
+
current.maxStepSize = Math.max(current.maxStepSize, stepSize || 0);
|
|
29
|
+
current.stepSizeSumForP90.push(stepSize || 0);
|
|
30
|
+
});
|
|
31
|
+
return current;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Gets the current active sessions from local storage
|
|
36
|
+
* If the session ID does not exist, it initializes a new active session.
|
|
37
|
+
*
|
|
38
|
+
* This is used in the ncsStepMetricsPlugin to determine if the session is still active
|
|
39
|
+
* before sending the ncs steps analytics event.
|
|
40
|
+
*
|
|
41
|
+
* @param sessionId - The session ID to check or update in local storage.
|
|
42
|
+
* @returns void
|
|
43
|
+
*/
|
|
44
|
+
const updateActiveSessions = sessionId => {
|
|
45
|
+
const currentActiveSessions = JSON.parse(storageClient.getItem('activeSessions') || '{}');
|
|
46
|
+
if (!currentActiveSessions[sessionId]) {
|
|
47
|
+
storageClient.setItemWithExpiry('ncsActiveSessions', JSON.stringify({
|
|
48
|
+
...currentActiveSessions,
|
|
49
|
+
[sessionId]: true
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Updates the step session metrics in local storage for a given session ID.
|
|
55
|
+
* It calculates the metrics based on the provided steps and updates the storage.
|
|
56
|
+
*
|
|
57
|
+
* @param api - The API to access the collab edit plugin.
|
|
58
|
+
* @param steps - The steps to calculate the metrics from.
|
|
59
|
+
* @return void
|
|
60
|
+
*/
|
|
61
|
+
export const updateStepSessionMetrics = ({
|
|
62
|
+
api,
|
|
63
|
+
steps
|
|
64
|
+
}) => {
|
|
65
|
+
var _api$collabEdit, _api$collabEdit$share;
|
|
66
|
+
const sessionId = api === null || api === void 0 ? void 0 : (_api$collabEdit = api.collabEdit) === null || _api$collabEdit === void 0 ? void 0 : (_api$collabEdit$share = _api$collabEdit.sharedState.currentState()) === null || _api$collabEdit$share === void 0 ? void 0 : _api$collabEdit$share.sessionId;
|
|
67
|
+
if (!sessionId) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const existingMetrics = JSON.parse(storageClient.getItem('ncsStepSessionMetrics') || '{}');
|
|
71
|
+
const stepSessionMetrics = getStepSessionMetrics(existingMetrics, sessionId, steps);
|
|
72
|
+
storageClient.setItemWithExpiry('ncsStepSessionMetrics', JSON.stringify({
|
|
73
|
+
...existingMetrics,
|
|
74
|
+
[sessionId]: stepSessionMetrics
|
|
75
|
+
}));
|
|
76
|
+
updateActiveSessions(sessionId);
|
|
77
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
2
2
|
import { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, RemoveMarkStep, RemoveNodeMarkStep } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
import { sendableSteps } from '@atlaskit/prosemirror-collab';
|
|
5
|
+
import { updateStepSessionMetrics } from './track-step-metrics';
|
|
4
6
|
function groupBy(array, keyGetter) {
|
|
5
7
|
// Check group by exists, and that it's a function. If so, use the native browser code
|
|
6
8
|
if ('groupBy' in Object && typeof Object.groupBy === 'function') {
|
|
@@ -123,11 +125,13 @@ const getScheduler = obj => {
|
|
|
123
125
|
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
124
126
|
*
|
|
125
127
|
* @param {TrackProps} props - The properties required for tracking steps.
|
|
128
|
+
* @param {ExtractInjectionAPI<CollabEditPlugin> | undefined} props.api - The API for the CollabEdit plugin.
|
|
126
129
|
* @param {EditorState} props.newEditorState - The new editor state.
|
|
127
130
|
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
128
131
|
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
129
132
|
*/
|
|
130
133
|
export const track = ({
|
|
134
|
+
api,
|
|
131
135
|
newEditorState,
|
|
132
136
|
transactions,
|
|
133
137
|
onTrackDataProcessed
|
|
@@ -150,7 +154,15 @@ export const track = ({
|
|
|
150
154
|
endedAt,
|
|
151
155
|
steps
|
|
152
156
|
});
|
|
153
|
-
scheduler.postTask(() =>
|
|
157
|
+
scheduler.postTask(() => {
|
|
158
|
+
if (fg('platform_enable_ncs_step_metrics')) {
|
|
159
|
+
updateStepSessionMetrics({
|
|
160
|
+
api,
|
|
161
|
+
steps: newSteps
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
task(stepsSentCache, onTrackDataProcessed);
|
|
165
|
+
}, {
|
|
154
166
|
priority: 'background',
|
|
155
167
|
delay: LOW_PRIORITY_DELAY
|
|
156
168
|
});
|
|
@@ -14,7 +14,7 @@ import { addSynchronyErrorAnalytics } from './pm-plugins/analytics';
|
|
|
14
14
|
import { sendTransaction } from './pm-plugins/events/send-transaction';
|
|
15
15
|
import { createPlugin } from './pm-plugins/main';
|
|
16
16
|
import { pluginKey as mainPluginKey } from './pm-plugins/main/plugin-key';
|
|
17
|
-
import { mergeUnconfirmedSteps } from './pm-plugins/mergeUnconfirmed';
|
|
17
|
+
import { filterAnalyticsSteps, mergeUnconfirmedSteps } from './pm-plugins/mergeUnconfirmed';
|
|
18
18
|
import { nativeCollabProviderPlugin } from './pm-plugins/native-collab-provider-plugin';
|
|
19
19
|
import { sanitizeFilteredStep, createPlugin as trackSpammingStepsPlugin } from './pm-plugins/track-and-filter-spamming-steps';
|
|
20
20
|
import { createPlugin as createLastOrganicChangePlugin, trackLastOrganicChangePluginKey } from './pm-plugins/track-last-organic-change';
|
|
@@ -194,14 +194,22 @@ export var collabEditPlugin = function collabEditPlugin(_ref4) {
|
|
|
194
194
|
useNativePlugin = _ref5$useNativePlugin === void 0 ? false : _ref5$useNativePlugin,
|
|
195
195
|
_ref5$userId = _ref5.userId,
|
|
196
196
|
userId = _ref5$userId === void 0 ? null : _ref5$userId;
|
|
197
|
+
var transformUnconfirmed = function transformUnconfirmed(steps) {
|
|
198
|
+
var transformed = steps;
|
|
199
|
+
if (editorExperiment('platform_editor_reduce_noisy_steps_ncs', true)) {
|
|
200
|
+
transformed = filterAnalyticsSteps(transformed);
|
|
201
|
+
}
|
|
202
|
+
if (editorExperiment('platform_editor_offline_editing_web', true)) {
|
|
203
|
+
transformed = mergeUnconfirmedSteps(transformed, api);
|
|
204
|
+
}
|
|
205
|
+
return transformed;
|
|
206
|
+
};
|
|
197
207
|
var plugins = [].concat(_toConsumableArray(useNativePlugin ? [{
|
|
198
208
|
name: 'pmCollab',
|
|
199
209
|
plugin: function plugin() {
|
|
200
210
|
return collab({
|
|
201
211
|
clientID: userId,
|
|
202
|
-
transformUnconfirmed:
|
|
203
|
-
return mergeUnconfirmedSteps(steps, api);
|
|
204
|
-
} : undefined
|
|
212
|
+
transformUnconfirmed: transformUnconfirmed
|
|
205
213
|
});
|
|
206
214
|
}
|
|
207
215
|
}, {
|
|
@@ -267,7 +275,9 @@ export var collabEditPlugin = function collabEditPlugin(_ref4) {
|
|
|
267
275
|
hideTelecursorOnLoad: !isEmptyDoc && ((_options$hideTelecurs = options.hideTelecursorOnLoad) !== null && _options$hideTelecurs !== void 0 ? _options$hideTelecurs : false),
|
|
268
276
|
viewMode: viewMode
|
|
269
277
|
}), addErrorAnalytics);
|
|
270
|
-
track(_objectSpread(_objectSpread({
|
|
278
|
+
track(_objectSpread(_objectSpread({
|
|
279
|
+
api: api
|
|
280
|
+
}, props), {}, {
|
|
271
281
|
onTrackDataProcessed: function onTrackDataProcessed(steps) {
|
|
272
282
|
var _api$analytics3;
|
|
273
283
|
api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.fireAnalyticsEvent({
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
|
|
1
2
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
|
+
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
2
4
|
import { getSendableSelection } from '../actions';
|
|
3
5
|
import { pluginKey } from '../main/plugin-key';
|
|
4
6
|
export var sendTransaction = function sendTransaction(_ref) {
|
|
@@ -14,15 +16,23 @@ export var sendTransaction = function sendTransaction(_ref) {
|
|
|
14
16
|
return tr.docChanged;
|
|
15
17
|
});
|
|
16
18
|
var currentPluginState = pluginKey.getState(newEditorState);
|
|
19
|
+
var tr = oldEditorState.tr;
|
|
20
|
+
var trNoAnalytics = docChangedTransaction === null || docChangedTransaction === void 0 ? void 0 : docChangedTransaction.steps.reduce(function (nextTr, step) {
|
|
21
|
+
if (!(step instanceof AnalyticsStep)) {
|
|
22
|
+
return nextTr.step(step);
|
|
23
|
+
}
|
|
24
|
+
return nextTr;
|
|
25
|
+
}, tr);
|
|
17
26
|
if (!(currentPluginState !== null && currentPluginState !== void 0 && currentPluginState.isReady)) {
|
|
18
27
|
return;
|
|
19
28
|
}
|
|
29
|
+
var newTransaction = editorExperiment('platform_editor_reduce_noisy_steps_ncs', true) ? trNoAnalytics : docChangedTransaction;
|
|
20
30
|
var shouldSendStepForSynchronyCollabProvider = !originalTransaction.getMeta('isRemote') &&
|
|
21
31
|
// TODO: ED-8995 - We need to do this check to reduce the number of race conditions when working with tables.
|
|
22
32
|
// This metadata is coming from the scaleTable command in table-resizing plugin
|
|
23
|
-
!originalTransaction.getMeta('scaleTable') &&
|
|
33
|
+
!originalTransaction.getMeta('scaleTable') && (editorExperiment('platform_editor_reduce_noisy_steps_ncs', true) ? newTransaction === null || newTransaction === void 0 ? void 0 : newTransaction.docChanged : true);
|
|
24
34
|
if (useNativePlugin || shouldSendStepForSynchronyCollabProvider) {
|
|
25
|
-
provider.send(
|
|
35
|
+
provider.send(newTransaction, oldEditorState, newEditorState);
|
|
26
36
|
}
|
|
27
37
|
var prevPluginState = pluginKey.getState(oldEditorState);
|
|
28
38
|
var _ref2 = prevPluginState || {},
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
2
2
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
3
|
+
import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
|
|
3
4
|
import { Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
4
5
|
// Based on: `packages/editor/prosemirror-collab/src/index.ts`
|
|
5
|
-
var LockableRebaseable = /*#__PURE__*/_createClass(function LockableRebaseable(step, inverted, origin) {
|
|
6
|
+
export var LockableRebaseable = /*#__PURE__*/_createClass(function LockableRebaseable(step, inverted, origin) {
|
|
6
7
|
_classCallCheck(this, LockableRebaseable);
|
|
7
8
|
this.step = step;
|
|
8
9
|
this.inverted = inverted;
|
|
@@ -46,4 +47,21 @@ export function mergeUnconfirmedSteps(steps, api) {
|
|
|
46
47
|
return acc.concat(new LockableRebaseable(rebaseable.step, rebaseable.inverted, rebaseable.origin instanceof Transaction ? rebaseable.origin.setMeta('isOffline', rebaseable.origin.getMeta('isOffline') === true || isOffline) : rebaseable.origin));
|
|
47
48
|
}, []);
|
|
48
49
|
return mergedSteps;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Filter out AnalyticsStep from the steps.
|
|
54
|
+
*
|
|
55
|
+
* @param steps Rebaseable steps
|
|
56
|
+
* @returns Rebaseable steps
|
|
57
|
+
* @example
|
|
58
|
+
*/
|
|
59
|
+
export function filterAnalyticsSteps(steps) {
|
|
60
|
+
var filteredSteps = steps.reduce(function (acc, rebaseable) {
|
|
61
|
+
if (rebaseable.step instanceof AnalyticsStep) {
|
|
62
|
+
return acc;
|
|
63
|
+
}
|
|
64
|
+
return acc.concat(new LockableRebaseable(rebaseable.step, rebaseable.inverted, rebaseable.origin));
|
|
65
|
+
}, []);
|
|
66
|
+
return filteredSteps;
|
|
49
67
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
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; }
|
|
3
|
+
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; }
|
|
4
|
+
import { StorageClient } from '@atlaskit/frontend-utilities';
|
|
5
|
+
var STORAGE_CLIENT_KEY = 'ncs-step-metrics-storage';
|
|
6
|
+
var storageClient = new StorageClient(STORAGE_CLIENT_KEY);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Gets the current step session metrics for a given session ID
|
|
10
|
+
* If the session ID does not exist, it initializes a new metrics object.
|
|
11
|
+
* It calculates the total size of the steps, the number of steps,
|
|
12
|
+
* the maximum step size, and the sum of step sizes for P90 calculation.
|
|
13
|
+
*
|
|
14
|
+
* @param metrics - The existing metrics object from local storage.
|
|
15
|
+
* @param sessionId - The session ID for which to get the metrics.
|
|
16
|
+
* @param steps - The steps to calculate the metrics from.
|
|
17
|
+
* @returns The updated step session metrics for the given session ID.
|
|
18
|
+
*/
|
|
19
|
+
var getStepSessionMetrics = function getStepSessionMetrics(metrics, sessionId, steps) {
|
|
20
|
+
var _metrics$sessionId;
|
|
21
|
+
var current = (_metrics$sessionId = metrics[sessionId]) !== null && _metrics$sessionId !== void 0 ? _metrics$sessionId : {
|
|
22
|
+
totalStepSize: 0,
|
|
23
|
+
numberOfSteps: 0,
|
|
24
|
+
maxStepSize: 0,
|
|
25
|
+
stepSizeSumForP90: []
|
|
26
|
+
};
|
|
27
|
+
steps.forEach(function (step) {
|
|
28
|
+
var stepSize = JSON.stringify(step).length;
|
|
29
|
+
current.totalStepSize += stepSize;
|
|
30
|
+
current.numberOfSteps += 1;
|
|
31
|
+
current.maxStepSize = Math.max(current.maxStepSize, stepSize || 0);
|
|
32
|
+
current.stepSizeSumForP90.push(stepSize || 0);
|
|
33
|
+
});
|
|
34
|
+
return current;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Gets the current active sessions from local storage
|
|
39
|
+
* If the session ID does not exist, it initializes a new active session.
|
|
40
|
+
*
|
|
41
|
+
* This is used in the ncsStepMetricsPlugin to determine if the session is still active
|
|
42
|
+
* before sending the ncs steps analytics event.
|
|
43
|
+
*
|
|
44
|
+
* @param sessionId - The session ID to check or update in local storage.
|
|
45
|
+
* @returns void
|
|
46
|
+
*/
|
|
47
|
+
var updateActiveSessions = function updateActiveSessions(sessionId) {
|
|
48
|
+
var currentActiveSessions = JSON.parse(storageClient.getItem('activeSessions') || '{}');
|
|
49
|
+
if (!currentActiveSessions[sessionId]) {
|
|
50
|
+
storageClient.setItemWithExpiry('ncsActiveSessions', JSON.stringify(_objectSpread(_objectSpread({}, currentActiveSessions), {}, _defineProperty({}, sessionId, true))));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Updates the step session metrics in local storage for a given session ID.
|
|
55
|
+
* It calculates the metrics based on the provided steps and updates the storage.
|
|
56
|
+
*
|
|
57
|
+
* @param api - The API to access the collab edit plugin.
|
|
58
|
+
* @param steps - The steps to calculate the metrics from.
|
|
59
|
+
* @return void
|
|
60
|
+
*/
|
|
61
|
+
export var updateStepSessionMetrics = function updateStepSessionMetrics(_ref) {
|
|
62
|
+
var _api$collabEdit;
|
|
63
|
+
var api = _ref.api,
|
|
64
|
+
steps = _ref.steps;
|
|
65
|
+
var sessionId = api === null || api === void 0 || (_api$collabEdit = api.collabEdit) === null || _api$collabEdit === void 0 || (_api$collabEdit = _api$collabEdit.sharedState.currentState()) === null || _api$collabEdit === void 0 ? void 0 : _api$collabEdit.sessionId;
|
|
66
|
+
if (!sessionId) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
var existingMetrics = JSON.parse(storageClient.getItem('ncsStepSessionMetrics') || '{}');
|
|
70
|
+
var stepSessionMetrics = getStepSessionMetrics(existingMetrics, sessionId, steps);
|
|
71
|
+
storageClient.setItemWithExpiry('ncsStepSessionMetrics', JSON.stringify(_objectSpread(_objectSpread({}, existingMetrics), {}, _defineProperty({}, sessionId, stepSessionMetrics))));
|
|
72
|
+
updateActiveSessions(sessionId);
|
|
73
|
+
};
|
|
@@ -4,7 +4,9 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
|
|
|
4
4
|
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; }
|
|
5
5
|
import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
6
6
|
import { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, RemoveMarkStep, RemoveNodeMarkStep } from '@atlaskit/editor-prosemirror/transform';
|
|
7
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
8
|
import { sendableSteps } from '@atlaskit/prosemirror-collab';
|
|
9
|
+
import { updateStepSessionMetrics } from './track-step-metrics';
|
|
8
10
|
function groupBy(array, keyGetter) {
|
|
9
11
|
// Check group by exists, and that it's a function. If so, use the native browser code
|
|
10
12
|
if ('groupBy' in Object && typeof Object.groupBy === 'function') {
|
|
@@ -139,12 +141,14 @@ var getScheduler = function getScheduler(obj) {
|
|
|
139
141
|
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
140
142
|
*
|
|
141
143
|
* @param {TrackProps} props - The properties required for tracking steps.
|
|
144
|
+
* @param {ExtractInjectionAPI<CollabEditPlugin> | undefined} props.api - The API for the CollabEdit plugin.
|
|
142
145
|
* @param {EditorState} props.newEditorState - The new editor state.
|
|
143
146
|
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
144
147
|
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
145
148
|
*/
|
|
146
149
|
export var track = function track(_ref3) {
|
|
147
|
-
var
|
|
150
|
+
var api = _ref3.api,
|
|
151
|
+
newEditorState = _ref3.newEditorState,
|
|
148
152
|
transactions = _ref3.transactions,
|
|
149
153
|
onTrackDataProcessed = _ref3.onTrackDataProcessed;
|
|
150
154
|
var newSteps = transactions.flatMap(function (t) {
|
|
@@ -166,7 +170,13 @@ export var track = function track(_ref3) {
|
|
|
166
170
|
steps: steps
|
|
167
171
|
});
|
|
168
172
|
scheduler.postTask(function () {
|
|
169
|
-
|
|
173
|
+
if (fg('platform_enable_ncs_step_metrics')) {
|
|
174
|
+
updateStepSessionMetrics({
|
|
175
|
+
api: api,
|
|
176
|
+
steps: newSteps
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
task(stepsSentCache, onTrackDataProcessed);
|
|
170
180
|
}, {
|
|
171
181
|
priority: 'background',
|
|
172
182
|
delay: LOW_PRIORITY_DELAY
|
|
@@ -2,7 +2,7 @@ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
|
2
2
|
import { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform';
|
|
3
3
|
import type { Transform as ProseMirrorTransform } from '@atlaskit/editor-prosemirror/transform';
|
|
4
4
|
import type { CollabEditPlugin } from '../collabEditPluginType';
|
|
5
|
-
declare class LockableRebaseable {
|
|
5
|
+
export declare class LockableRebaseable {
|
|
6
6
|
readonly step: ProseMirrorStep;
|
|
7
7
|
readonly inverted: ProseMirrorStep;
|
|
8
8
|
readonly origin: ProseMirrorTransform;
|
|
@@ -19,4 +19,11 @@ declare class LockableRebaseable {
|
|
|
19
19
|
* @returns Rebaseable steps
|
|
20
20
|
*/
|
|
21
21
|
export declare function mergeUnconfirmedSteps(steps: LockableRebaseable[], api: ExtractInjectionAPI<CollabEditPlugin> | undefined): LockableRebaseable[];
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Filter out AnalyticsStep from the steps.
|
|
24
|
+
*
|
|
25
|
+
* @param steps Rebaseable steps
|
|
26
|
+
* @returns Rebaseable steps
|
|
27
|
+
* @example
|
|
28
|
+
*/
|
|
29
|
+
export declare function filterAnalyticsSteps(steps: LockableRebaseable[]): LockableRebaseable[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
2
|
+
import { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
import { CollabEditPlugin } from '../collabEditPluginType';
|
|
4
|
+
type UpdateStepSessionMetricProps = {
|
|
5
|
+
api: ExtractInjectionAPI<CollabEditPlugin> | undefined;
|
|
6
|
+
steps: Step[];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Updates the step session metrics in local storage for a given session ID.
|
|
10
|
+
* It calculates the metrics based on the provided steps and updates the storage.
|
|
11
|
+
*
|
|
12
|
+
* @param api - The API to access the collab edit plugin.
|
|
13
|
+
* @param steps - The steps to calculate the metrics from.
|
|
14
|
+
* @return void
|
|
15
|
+
*/
|
|
16
|
+
export declare const updateStepSessionMetrics: ({ api, steps }: UpdateStepSessionMetricProps) => void;
|
|
17
|
+
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
1
2
|
import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
2
3
|
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
4
|
+
import { CollabEditPlugin } from '../collabEditPluginType';
|
|
3
5
|
export type SanitizedStep = {
|
|
4
6
|
stepType: string;
|
|
5
7
|
attr?: string;
|
|
@@ -59,6 +61,7 @@ export type CacheType = Map<number, {
|
|
|
59
61
|
endedAt: number;
|
|
60
62
|
}>;
|
|
61
63
|
type TrackProps = {
|
|
64
|
+
api: ExtractInjectionAPI<CollabEditPlugin> | undefined;
|
|
62
65
|
newEditorState: EditorState;
|
|
63
66
|
transactions: Readonly<Transaction[]>;
|
|
64
67
|
onTrackDataProcessed: (data: StepMetadataAnalytics[]) => void;
|
|
@@ -69,9 +72,10 @@ type TrackProps = {
|
|
|
69
72
|
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
70
73
|
*
|
|
71
74
|
* @param {TrackProps} props - The properties required for tracking steps.
|
|
75
|
+
* @param {ExtractInjectionAPI<CollabEditPlugin> | undefined} props.api - The API for the CollabEdit plugin.
|
|
72
76
|
* @param {EditorState} props.newEditorState - The new editor state.
|
|
73
77
|
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
74
78
|
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
75
79
|
*/
|
|
76
|
-
export declare const track: ({ newEditorState, transactions, onTrackDataProcessed }: TrackProps) => void;
|
|
80
|
+
export declare const track: ({ api, newEditorState, transactions, onTrackDataProcessed }: TrackProps) => void;
|
|
77
81
|
export {};
|
|
@@ -2,7 +2,7 @@ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
|
2
2
|
import { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform';
|
|
3
3
|
import type { Transform as ProseMirrorTransform } from '@atlaskit/editor-prosemirror/transform';
|
|
4
4
|
import type { CollabEditPlugin } from '../collabEditPluginType';
|
|
5
|
-
declare class LockableRebaseable {
|
|
5
|
+
export declare class LockableRebaseable {
|
|
6
6
|
readonly step: ProseMirrorStep;
|
|
7
7
|
readonly inverted: ProseMirrorStep;
|
|
8
8
|
readonly origin: ProseMirrorTransform;
|
|
@@ -19,4 +19,11 @@ declare class LockableRebaseable {
|
|
|
19
19
|
* @returns Rebaseable steps
|
|
20
20
|
*/
|
|
21
21
|
export declare function mergeUnconfirmedSteps(steps: LockableRebaseable[], api: ExtractInjectionAPI<CollabEditPlugin> | undefined): LockableRebaseable[];
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Filter out AnalyticsStep from the steps.
|
|
24
|
+
*
|
|
25
|
+
* @param steps Rebaseable steps
|
|
26
|
+
* @returns Rebaseable steps
|
|
27
|
+
* @example
|
|
28
|
+
*/
|
|
29
|
+
export declare function filterAnalyticsSteps(steps: LockableRebaseable[]): LockableRebaseable[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
2
|
+
import { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
import { CollabEditPlugin } from '../collabEditPluginType';
|
|
4
|
+
type UpdateStepSessionMetricProps = {
|
|
5
|
+
api: ExtractInjectionAPI<CollabEditPlugin> | undefined;
|
|
6
|
+
steps: Step[];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Updates the step session metrics in local storage for a given session ID.
|
|
10
|
+
* It calculates the metrics based on the provided steps and updates the storage.
|
|
11
|
+
*
|
|
12
|
+
* @param api - The API to access the collab edit plugin.
|
|
13
|
+
* @param steps - The steps to calculate the metrics from.
|
|
14
|
+
* @return void
|
|
15
|
+
*/
|
|
16
|
+
export declare const updateStepSessionMetrics: ({ api, steps }: UpdateStepSessionMetricProps) => void;
|
|
17
|
+
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
1
2
|
import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
2
3
|
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
4
|
+
import { CollabEditPlugin } from '../collabEditPluginType';
|
|
3
5
|
export type SanitizedStep = {
|
|
4
6
|
stepType: string;
|
|
5
7
|
attr?: string;
|
|
@@ -59,6 +61,7 @@ export type CacheType = Map<number, {
|
|
|
59
61
|
endedAt: number;
|
|
60
62
|
}>;
|
|
61
63
|
type TrackProps = {
|
|
64
|
+
api: ExtractInjectionAPI<CollabEditPlugin> | undefined;
|
|
62
65
|
newEditorState: EditorState;
|
|
63
66
|
transactions: Readonly<Transaction[]>;
|
|
64
67
|
onTrackDataProcessed: (data: StepMetadataAnalytics[]) => void;
|
|
@@ -69,9 +72,10 @@ type TrackProps = {
|
|
|
69
72
|
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
70
73
|
*
|
|
71
74
|
* @param {TrackProps} props - The properties required for tracking steps.
|
|
75
|
+
* @param {ExtractInjectionAPI<CollabEditPlugin> | undefined} props.api - The API for the CollabEdit plugin.
|
|
72
76
|
* @param {EditorState} props.newEditorState - The new editor state.
|
|
73
77
|
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
74
78
|
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
75
79
|
*/
|
|
76
|
-
export declare const track: ({ newEditorState, transactions, onTrackDataProcessed }: TrackProps) => void;
|
|
80
|
+
export declare const track: ({ api, newEditorState, transactions, onTrackDataProcessed }: TrackProps) => void;
|
|
77
81
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-collab-edit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "Collab Edit plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@atlaskit/adf-schema": "^47.6.0",
|
|
35
35
|
"@atlaskit/custom-steps": "^0.11.0",
|
|
36
|
-
"@atlaskit/editor-common": "^106.
|
|
36
|
+
"@atlaskit/editor-common": "^106.1.0",
|
|
37
37
|
"@atlaskit/editor-json-transformer": "^8.24.0",
|
|
38
38
|
"@atlaskit/editor-plugin-analytics": "^2.3.0",
|
|
39
39
|
"@atlaskit/editor-plugin-connectivity": "^2.0.0",
|
|
@@ -41,9 +41,10 @@
|
|
|
41
41
|
"@atlaskit/editor-plugin-feature-flags": "^1.4.0",
|
|
42
42
|
"@atlaskit/editor-prosemirror": "7.0.0",
|
|
43
43
|
"@atlaskit/editor-shared-styles": "^3.4.0",
|
|
44
|
+
"@atlaskit/frontend-utilities": "^3.0.0",
|
|
44
45
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
45
|
-
"@atlaskit/prosemirror-collab": "^0.
|
|
46
|
-
"@atlaskit/tmp-editor-statsig": "^5.
|
|
46
|
+
"@atlaskit/prosemirror-collab": "^0.17.0",
|
|
47
|
+
"@atlaskit/tmp-editor-statsig": "^5.5.0",
|
|
47
48
|
"@babel/runtime": "^7.0.0",
|
|
48
49
|
"memoize-one": "^6.0.0"
|
|
49
50
|
},
|
|
@@ -115,6 +116,9 @@
|
|
|
115
116
|
},
|
|
116
117
|
"confluence_team_presence_scroll_to_pointer": {
|
|
117
118
|
"type": "boolean"
|
|
119
|
+
},
|
|
120
|
+
"platform_enable_ncs_step_metrics": {
|
|
121
|
+
"type": "boolean"
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
124
|
}
|