@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 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: (0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true) ? function (steps) {
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({}, props), {}, {
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') && docChangedTransaction;
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(docChangedTransaction, oldEditorState, newEditorState);
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 newEditorState = _ref3.newEditorState,
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
- return task(stepsSentCache, onTrackDataProcessed);
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: editorExperiment('platform_editor_offline_editing_web', true) ? steps => mergeUnconfirmedSteps(steps, api) : undefined
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') && docChangedTransaction;
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(docChangedTransaction, oldEditorState, newEditorState);
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(() => task(stepsSentCache, onTrackDataProcessed), {
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: editorExperiment('platform_editor_offline_editing_web', true) ? function (steps) {
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({}, props), {}, {
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') && docChangedTransaction;
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(docChangedTransaction, oldEditorState, newEditorState);
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 newEditorState = _ref3.newEditorState,
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
- return task(stepsSentCache, onTrackDataProcessed);
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
- export {};
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
- export {};
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.7.2",
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.0.0",
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.16.0",
46
- "@atlaskit/tmp-editor-statsig": "^5.2.0",
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
  }