@atlaskit/editor-plugin-metrics 1.1.0 → 2.0.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/.eslintrc.js CHANGED
@@ -1,14 +1,14 @@
1
1
  module.exports = {
2
2
  rules: {
3
- '@typescript-eslint/no-duplicate-imports': 'error',
4
- '@typescript-eslint/no-explicit-any': 'error',
3
+ '@typescript-eslint/no-duplicate-imports': 'error',
4
+ '@typescript-eslint/no-explicit-any': 'error',
5
5
  },
6
6
  overrides: [
7
- {
8
- files: ['**/__tests__/**/*.{js,ts,tsx}', '**/examples/**/*.{js,ts,tsx}'],
9
- rules: {
10
- '@typescript-eslint/no-explicit-any': 'off',
7
+ {
8
+ files: ['**/__tests__/**/*.{js,ts,tsx}', '**/examples/**/*.{js,ts,tsx}'],
9
+ rules: {
10
+ '@typescript-eslint/no-explicit-any': 'off',
11
+ },
11
12
  },
12
- },
13
13
  ],
14
- };
14
+ };
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/editor-plugin-metrics
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#105399](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/105399)
8
+ [`ed98e34b5912b`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/ed98e34b5912b) -
9
+ ED-26234 Fire analytics at end of editor session
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
3
15
  ## 1.1.0
4
16
 
5
17
  ### Minor Changes
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.metricsPlugin = void 0;
7
7
  var _main = require("./pm-plugins/main");
8
+ var _analytics = require("./pm-plugins/utils/analytics");
8
9
  /**
9
10
  * Metrics plugin to be added to an `EditorPresetBuilder` and used with `ComposableEditor`
10
11
  * from `@atlaskit/editor-core`.
@@ -29,43 +30,18 @@ var metricsPlugin = exports.metricsPlugin = function metricsPlugin(_ref) {
29
30
  return tr;
30
31
  }
31
32
  var newTr = tr;
33
+ var pluginState = api === null || api === void 0 ? void 0 : api.metrics.sharedState.currentState();
34
+ if (pluginState && pluginState.totalActionCount > 0 && pluginState.activeSessionTime > 0) {
35
+ var payloadToSend = (0, _analytics.getAnalyticsPayload)({
36
+ pluginState: pluginState
37
+ });
38
+ api === null || api === void 0 || api.analytics.actions.attachAnalyticsEvent(payloadToSend)(newTr);
39
+ }
32
40
  newTr.setMeta(_main.metricsKey, {
33
41
  stopActiveSession: true
34
42
  });
35
43
  return newTr;
36
44
  };
37
- },
38
- fireSessionAnalytics: function fireSessionAnalytics() {
39
- return function (_ref3) {
40
- var tr = _ref3.tr;
41
- if (!api) {
42
- return tr;
43
- }
44
- var state = api.metrics.sharedState.currentState();
45
- if (!state) {
46
- return tr;
47
- }
48
-
49
- // const eventAttributes = {
50
- // efficiency: {
51
- // totalActiveTime: state.activeSessionTime || 0,
52
- // totalActionCount: state.totalActionCount || 0,
53
- // actionTypeCount: state.actionTypeCount,
54
- // totalInactiveTime:
55
- // Date.now() - (state.editSessionStartTime || 0) - (state.activeSessionTime || 0),
56
- // },
57
- // TODO: Add effectiveness attributes
58
- // effectiveness: {
59
- // undoCount: 0,
60
- // repeatedActionCount: 0,
61
- // safeInsertCount: 0,
62
- // },
63
- // };
64
-
65
- // fire analytics event
66
- // api.analytics.actions.attachAnalyticsEvent({});
67
- return tr;
68
- };
69
45
  }
70
46
  },
71
47
  getSharedState: function getSharedState(editorState) {
@@ -6,27 +6,31 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.metricsKey = exports.initialPluginState = exports.createPlugin = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _bindEventListener = require("bind-event-listener");
9
10
  var _steps = require("@atlaskit/adf-schema/steps");
10
11
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
12
  var _utils = require("@atlaskit/editor-common/utils");
12
13
  var _state = require("@atlaskit/editor-prosemirror/state");
13
14
  var _activeSessionTimer = require("./utils/active-session-timer");
15
+ var _analytics = require("./utils/analytics");
16
+ var _isNonTextUndo = require("./utils/isNonTextUndo");
14
17
  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; }
15
18
  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; }
16
19
  var metricsKey = exports.metricsKey = new _state.PluginKey('metricsPlugin');
17
20
  var initialPluginState = exports.initialPluginState = {
18
- editSessionStartTime: undefined,
19
21
  intentToStartEditTime: undefined,
20
22
  lastSelection: undefined,
21
23
  activeSessionTime: 0,
22
24
  totalActionCount: 0,
25
+ contentSizeChanged: 0,
23
26
  timeOfLastTextInput: undefined,
24
27
  actionTypeCount: {
25
28
  textInputCount: 0,
26
29
  nodeInsertionCount: 0,
27
30
  nodeAttributeChangeCount: 0,
28
31
  contentMovedCount: 0,
29
- nodeDeletionCount: 0
32
+ nodeDeletionCount: 0,
33
+ undoCount: 0
30
34
  }
31
35
  };
32
36
  var createPlugin = exports.createPlugin = function createPlugin(api) {
@@ -35,23 +39,28 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
35
39
  key: metricsKey,
36
40
  state: {
37
41
  init: function init() {
38
- return _objectSpread(_objectSpread({}, initialPluginState), {}, {
39
- editSessionStartTime: performance.now()
40
- });
42
+ return initialPluginState;
41
43
  },
42
- apply: function apply(tr, pluginState) {
44
+ // eslint-disable-next-line @typescript-eslint/max-params
45
+ apply: function apply(tr, pluginState, oldState, newState) {
43
46
  var meta = tr.getMeta(metricsKey);
44
47
  var intentToStartEditTime = (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime;
45
48
  if (meta && meta.stopActiveSession) {
46
- // console.log('stopActiveSession');
47
- return _objectSpread(_objectSpread({}, pluginState), {}, {
48
- intentToStartEditTime: undefined,
49
- lastSelection: undefined
50
- });
49
+ return initialPluginState;
51
50
  }
52
51
  if (!intentToStartEditTime) {
53
- return pluginState;
52
+ if (tr.docChanged && !tr.getMeta('replaceDocument')) {
53
+ intentToStartEditTime = performance.now();
54
+ } else {
55
+ return pluginState;
56
+ }
54
57
  }
58
+ var undoCount = (0, _isNonTextUndo.isNonTextUndo)(tr) ? 1 : 0;
59
+ var newActionTypeCount = pluginState.actionTypeCount ? _objectSpread(_objectSpread({}, pluginState.actionTypeCount), {}, {
60
+ undoCount: pluginState.actionTypeCount.undoCount + undoCount
61
+ }) : _objectSpread(_objectSpread({}, initialPluginState.actionTypeCount), {}, {
62
+ undoCount: undoCount
63
+ });
55
64
  var canIgnoreTr = function canIgnoreTr() {
56
65
  return !tr.steps.every(function (e) {
57
66
  return e instanceof _steps.AnalyticsStep;
@@ -60,36 +69,64 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
60
69
  if (tr.docChanged && canIgnoreTr()) {
61
70
  var now = performance.now();
62
71
  timer.startTimer();
63
-
72
+ var actionTypeCount = pluginState.actionTypeCount,
73
+ timeOfLastTextInput = pluginState.timeOfLastTextInput,
74
+ totalActionCount = pluginState.totalActionCount,
75
+ activeSessionTime = pluginState.activeSessionTime;
64
76
  // If previous and current action is text insertion, then don't increase total action count
65
77
  var isActionTextInput = (0, _utils.isTextInput)(tr);
78
+ var newActiveSessionTime = activeSessionTime + (now - intentToStartEditTime);
79
+ var newTextInputCount = isActionTextInput ? actionTypeCount.textInputCount + 1 : actionTypeCount.textInputCount;
80
+ var newTotalActionCount = pluginState.totalActionCount + 1;
66
81
  if (pluginState.timeOfLastTextInput && isActionTextInput) {
67
- return _objectSpread(_objectSpread({}, pluginState), {}, {
68
- activeSessionTime: pluginState.activeSessionTime + (now - pluginState.timeOfLastTextInput),
69
- totalActionCount: pluginState.totalActionCount,
70
- timeOfLastTextInput: now
71
- });
82
+ newActiveSessionTime = activeSessionTime + (now - (timeOfLastTextInput || 0));
83
+ newTextInputCount = actionTypeCount.textInputCount;
84
+ newTotalActionCount = totalActionCount;
72
85
  }
73
-
74
- // TODO: Add actionTypeCount
75
- return _objectSpread(_objectSpread({}, pluginState), {}, {
76
- activeSessionTime: pluginState.activeSessionTime + (now - intentToStartEditTime),
77
- totalActionCount: pluginState.totalActionCount + 1,
78
- timeOfLastTextInput: isActionTextInput ? now : undefined
86
+ var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
87
+ activeSessionTime: newActiveSessionTime,
88
+ totalActionCount: newTotalActionCount,
89
+ timeOfLastTextInput: isActionTextInput ? now : undefined,
90
+ contentSizeChanged: pluginState.contentSizeChanged + (newState.doc.content.size - oldState.doc.content.size),
91
+ actionTypeCount: _objectSpread(_objectSpread({}, newActionTypeCount), {}, {
92
+ textInputCount: newTextInputCount
93
+ })
79
94
  });
95
+ return newPluginState;
80
96
  }
81
97
  return _objectSpread(_objectSpread({}, pluginState), {}, {
82
98
  lastSelection: (meta === null || meta === void 0 ? void 0 : meta.newSelection) || pluginState.lastSelection,
83
- intentToStartEditTime: (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime
99
+ intentToStartEditTime: intentToStartEditTime,
100
+ actionTypeCount: newActionTypeCount
84
101
  });
85
102
  }
86
103
  },
87
- view: function view() {
104
+ view: function view(_view) {
105
+ var fireAnalyticsEvent = function fireAnalyticsEvent() {
106
+ var pluginState = metricsKey.getState(_view.state);
107
+ if (!pluginState) {
108
+ return;
109
+ }
110
+ var payloadToSend = (0, _analytics.getAnalyticsPayload)({
111
+ pluginState: pluginState
112
+ });
113
+ if (pluginState && pluginState.totalActionCount > 0 && pluginState.activeSessionTime > 0) {
114
+ api === null || api === void 0 || api.analytics.actions.fireAnalyticsEvent(payloadToSend, undefined, {
115
+ immediate: true
116
+ });
117
+ }
118
+ };
119
+ var unbindBeforeUnload = (0, _bindEventListener.bind)(window, {
120
+ type: 'beforeunload',
121
+ listener: function listener() {
122
+ fireAnalyticsEvent();
123
+ }
124
+ });
88
125
  return {
89
126
  destroy: function destroy() {
90
- var _api$metrics;
91
- api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$metrics = api.metrics) === null || _api$metrics === void 0 ? void 0 : _api$metrics.commands.fireSessionAnalytics());
127
+ fireAnalyticsEvent();
92
128
  timer.cleanupTimer();
129
+ unbindBeforeUnload();
93
130
  }
94
131
  };
95
132
  },
@@ -8,6 +8,7 @@ exports.ActiveSessionTimer = void 0;
8
8
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
9
9
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+ var ACTIVE_SESSION_IDLE_TIME = 5000;
11
12
  var ActiveSessionTimer = exports.ActiveSessionTimer = /*#__PURE__*/(0, _createClass2.default)(function ActiveSessionTimer(api) {
12
13
  var _this = this;
13
14
  (0, _classCallCheck2.default)(this, ActiveSessionTimer);
@@ -16,14 +17,14 @@ var ActiveSessionTimer = exports.ActiveSessionTimer = /*#__PURE__*/(0, _createCl
16
17
  clearTimeout(_this.timerId);
17
18
  }
18
19
  _this.timerId = window.setTimeout(function () {
20
+ if (_this.api) {
21
+ var _this$api$metrics;
22
+ _this.api.core.actions.execute((_this$api$metrics = _this.api.metrics) === null || _this$api$metrics === void 0 ? void 0 : _this$api$metrics.commands.stopActiveSession());
23
+ }
19
24
  _this.cleanupTimer();
20
- }, 3000);
25
+ }, ACTIVE_SESSION_IDLE_TIME);
21
26
  });
22
27
  (0, _defineProperty2.default)(this, "cleanupTimer", function () {
23
- if (_this.api) {
24
- var _this$api$metrics;
25
- _this.api.core.actions.execute((_this$api$metrics = _this.api.metrics) === null || _this$api$metrics === void 0 ? void 0 : _this$api$metrics.commands.stopActiveSession());
26
- }
27
28
  if (_this.timerId) {
28
29
  clearTimeout(_this.timerId);
29
30
  _this.timerId = null;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getPayloadAttributes = exports.getAnalyticsPayload = void 0;
7
+ var _analytics = require("@atlaskit/editor-common/analytics");
8
+ var getPayloadAttributes = exports.getPayloadAttributes = function getPayloadAttributes(_ref) {
9
+ var pluginState = _ref.pluginState,
10
+ contentSizeChanged = _ref.contentSizeChanged;
11
+ return {
12
+ efficiency: {
13
+ totalActiveTime: pluginState.activeSessionTime,
14
+ totalActionCount: pluginState.totalActionCount,
15
+ actionByTypeCount: pluginState.actionTypeCount
16
+ },
17
+ effectiveness: {
18
+ undoCount: pluginState.actionTypeCount.undoCount,
19
+ repeatedActionCount: 0,
20
+ safeInsertCount: 0
21
+ },
22
+ contentSizeChanged: contentSizeChanged
23
+ };
24
+ };
25
+ var getAnalyticsPayload = exports.getAnalyticsPayload = function getAnalyticsPayload(_ref2) {
26
+ var pluginState = _ref2.pluginState;
27
+ return {
28
+ action: _analytics.ACTION.ENDED,
29
+ actionSubject: _analytics.ACTION_SUBJECT.ACTIVITY_SESSION,
30
+ actionSubjectId: _analytics.ACTION_SUBJECT_ID.ACTIVITY,
31
+ attributes: {
32
+ efficiency: {
33
+ totalActiveTime: pluginState.activeSessionTime,
34
+ totalActionCount: pluginState.totalActionCount,
35
+ actionByTypeCount: pluginState.actionTypeCount
36
+ },
37
+ effectiveness: {
38
+ undoCount: pluginState.actionTypeCount.undoCount,
39
+ repeatedActionCount: 0,
40
+ safeInsertCount: 0
41
+ },
42
+ contentSizeChanged: pluginState.contentSizeChanged
43
+ },
44
+ eventType: _analytics.EVENT_TYPE.TRACK
45
+ };
46
+ };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isNonTextUndo = void 0;
7
+ var _transform = require("@atlaskit/editor-prosemirror/transform");
8
+ var isNonTextUndo = exports.isNonTextUndo = function isNonTextUndo(tr) {
9
+ if (tr.getMeta('undoRedoPlugin$') === undefined) {
10
+ return false;
11
+ }
12
+ var hasNonTextChange = false;
13
+ tr.steps.forEach(function (step) {
14
+ if (step instanceof _transform.ReplaceStep) {
15
+ var slice = step.slice;
16
+ if (slice.content) {
17
+ slice.content.forEach(function (node) {
18
+ if (node.type.name !== 'text') {
19
+ hasNonTextChange = true;
20
+ }
21
+ });
22
+ }
23
+ } else {
24
+ hasNonTextChange = true;
25
+ }
26
+ });
27
+ return hasNonTextChange;
28
+ };
@@ -1,4 +1,5 @@
1
1
  import { createPlugin, initialPluginState, metricsKey } from './pm-plugins/main';
2
+ import { getAnalyticsPayload } from './pm-plugins/utils/analytics';
2
3
  /**
3
4
  * Metrics plugin to be added to an `EditorPresetBuilder` and used with `ComposableEditor`
4
5
  * from `@atlaskit/editor-core`.
@@ -21,41 +22,17 @@ export const metricsPlugin = ({
21
22
  return tr;
22
23
  }
23
24
  const newTr = tr;
25
+ const pluginState = api === null || api === void 0 ? void 0 : api.metrics.sharedState.currentState();
26
+ if (pluginState && pluginState.totalActionCount > 0 && pluginState.activeSessionTime > 0) {
27
+ const payloadToSend = getAnalyticsPayload({
28
+ pluginState
29
+ });
30
+ api === null || api === void 0 ? void 0 : api.analytics.actions.attachAnalyticsEvent(payloadToSend)(newTr);
31
+ }
24
32
  newTr.setMeta(metricsKey, {
25
33
  stopActiveSession: true
26
34
  });
27
35
  return newTr;
28
- },
29
- fireSessionAnalytics: () => ({
30
- tr
31
- }) => {
32
- if (!api) {
33
- return tr;
34
- }
35
- const state = api.metrics.sharedState.currentState();
36
- if (!state) {
37
- return tr;
38
- }
39
-
40
- // const eventAttributes = {
41
- // efficiency: {
42
- // totalActiveTime: state.activeSessionTime || 0,
43
- // totalActionCount: state.totalActionCount || 0,
44
- // actionTypeCount: state.actionTypeCount,
45
- // totalInactiveTime:
46
- // Date.now() - (state.editSessionStartTime || 0) - (state.activeSessionTime || 0),
47
- // },
48
- // TODO: Add effectiveness attributes
49
- // effectiveness: {
50
- // undoCount: 0,
51
- // repeatedActionCount: 0,
52
- // safeInsertCount: 0,
53
- // },
54
- // };
55
-
56
- // fire analytics event
57
- // api.analytics.actions.attachAnalyticsEvent({});
58
- return tr;
59
36
  }
60
37
  },
61
38
  getSharedState(editorState) {
@@ -1,22 +1,26 @@
1
+ import { bind } from 'bind-event-listener';
1
2
  import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
2
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
4
  import { isTextInput } from '@atlaskit/editor-common/utils';
4
5
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
5
6
  import { ActiveSessionTimer } from './utils/active-session-timer';
7
+ import { getAnalyticsPayload } from './utils/analytics';
8
+ import { isNonTextUndo } from './utils/isNonTextUndo';
6
9
  export const metricsKey = new PluginKey('metricsPlugin');
7
10
  export const initialPluginState = {
8
- editSessionStartTime: undefined,
9
11
  intentToStartEditTime: undefined,
10
12
  lastSelection: undefined,
11
13
  activeSessionTime: 0,
12
14
  totalActionCount: 0,
15
+ contentSizeChanged: 0,
13
16
  timeOfLastTextInput: undefined,
14
17
  actionTypeCount: {
15
18
  textInputCount: 0,
16
19
  nodeInsertionCount: 0,
17
20
  nodeAttributeChangeCount: 0,
18
21
  contentMovedCount: 0,
19
- nodeDeletionCount: 0
22
+ nodeDeletionCount: 0,
23
+ undoCount: 0
20
24
  }
21
25
  };
22
26
  export const createPlugin = api => {
@@ -25,62 +29,97 @@ export const createPlugin = api => {
25
29
  key: metricsKey,
26
30
  state: {
27
31
  init: () => {
28
- return {
29
- ...initialPluginState,
30
- editSessionStartTime: performance.now()
31
- };
32
+ return initialPluginState;
32
33
  },
33
- apply(tr, pluginState) {
34
+ // eslint-disable-next-line @typescript-eslint/max-params
35
+ apply(tr, pluginState, oldState, newState) {
34
36
  const meta = tr.getMeta(metricsKey);
35
- const intentToStartEditTime = (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime;
37
+ let intentToStartEditTime = (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime;
36
38
  if (meta && meta.stopActiveSession) {
37
- // console.log('stopActiveSession');
38
- return {
39
- ...pluginState,
40
- intentToStartEditTime: undefined,
41
- lastSelection: undefined
42
- };
39
+ return initialPluginState;
43
40
  }
44
41
  if (!intentToStartEditTime) {
45
- return pluginState;
42
+ if (tr.docChanged && !tr.getMeta('replaceDocument')) {
43
+ intentToStartEditTime = performance.now();
44
+ } else {
45
+ return pluginState;
46
+ }
46
47
  }
48
+ const undoCount = isNonTextUndo(tr) ? 1 : 0;
49
+ const newActionTypeCount = pluginState.actionTypeCount ? {
50
+ ...pluginState.actionTypeCount,
51
+ undoCount: pluginState.actionTypeCount.undoCount + undoCount
52
+ } : {
53
+ ...initialPluginState.actionTypeCount,
54
+ undoCount
55
+ };
47
56
  const canIgnoreTr = () => !tr.steps.every(e => e instanceof AnalyticsStep);
48
57
  if (tr.docChanged && canIgnoreTr()) {
49
58
  const now = performance.now();
50
59
  timer.startTimer();
51
-
60
+ const {
61
+ actionTypeCount,
62
+ timeOfLastTextInput,
63
+ totalActionCount,
64
+ activeSessionTime
65
+ } = pluginState;
52
66
  // If previous and current action is text insertion, then don't increase total action count
53
67
  const isActionTextInput = isTextInput(tr);
68
+ let newActiveSessionTime = activeSessionTime + (now - intentToStartEditTime);
69
+ let newTextInputCount = isActionTextInput ? actionTypeCount.textInputCount + 1 : actionTypeCount.textInputCount;
70
+ let newTotalActionCount = pluginState.totalActionCount + 1;
54
71
  if (pluginState.timeOfLastTextInput && isActionTextInput) {
55
- return {
56
- ...pluginState,
57
- activeSessionTime: pluginState.activeSessionTime + (now - pluginState.timeOfLastTextInput),
58
- totalActionCount: pluginState.totalActionCount,
59
- timeOfLastTextInput: now
60
- };
72
+ newActiveSessionTime = activeSessionTime + (now - (timeOfLastTextInput || 0));
73
+ newTextInputCount = actionTypeCount.textInputCount;
74
+ newTotalActionCount = totalActionCount;
61
75
  }
62
-
63
- // TODO: Add actionTypeCount
64
- return {
76
+ const newPluginState = {
65
77
  ...pluginState,
66
- activeSessionTime: pluginState.activeSessionTime + (now - intentToStartEditTime),
67
- totalActionCount: pluginState.totalActionCount + 1,
68
- timeOfLastTextInput: isActionTextInput ? now : undefined
78
+ activeSessionTime: newActiveSessionTime,
79
+ totalActionCount: newTotalActionCount,
80
+ timeOfLastTextInput: isActionTextInput ? now : undefined,
81
+ contentSizeChanged: pluginState.contentSizeChanged + (newState.doc.content.size - oldState.doc.content.size),
82
+ actionTypeCount: {
83
+ ...newActionTypeCount,
84
+ textInputCount: newTextInputCount
85
+ }
69
86
  };
87
+ return newPluginState;
70
88
  }
71
89
  return {
72
90
  ...pluginState,
73
91
  lastSelection: (meta === null || meta === void 0 ? void 0 : meta.newSelection) || pluginState.lastSelection,
74
- intentToStartEditTime: (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime
92
+ intentToStartEditTime,
93
+ actionTypeCount: newActionTypeCount
75
94
  };
76
95
  }
77
96
  },
78
- view() {
97
+ view(view) {
98
+ const fireAnalyticsEvent = () => {
99
+ const pluginState = metricsKey.getState(view.state);
100
+ if (!pluginState) {
101
+ return;
102
+ }
103
+ const payloadToSend = getAnalyticsPayload({
104
+ pluginState
105
+ });
106
+ if (pluginState && pluginState.totalActionCount > 0 && pluginState.activeSessionTime > 0) {
107
+ api === null || api === void 0 ? void 0 : api.analytics.actions.fireAnalyticsEvent(payloadToSend, undefined, {
108
+ immediate: true
109
+ });
110
+ }
111
+ };
112
+ const unbindBeforeUnload = bind(window, {
113
+ type: 'beforeunload',
114
+ listener: () => {
115
+ fireAnalyticsEvent();
116
+ }
117
+ });
79
118
  return {
80
119
  destroy() {
81
- var _api$metrics;
82
- api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : (_api$metrics = api.metrics) === null || _api$metrics === void 0 ? void 0 : _api$metrics.commands.fireSessionAnalytics());
120
+ fireAnalyticsEvent();
83
121
  timer.cleanupTimer();
122
+ unbindBeforeUnload();
84
123
  }
85
124
  };
86
125
  },
@@ -1,4 +1,5 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ const ACTIVE_SESSION_IDLE_TIME = 5000;
2
3
  export class ActiveSessionTimer {
3
4
  constructor(api) {
4
5
  _defineProperty(this, "startTimer", () => {
@@ -6,14 +7,14 @@ export class ActiveSessionTimer {
6
7
  clearTimeout(this.timerId);
7
8
  }
8
9
  this.timerId = window.setTimeout(() => {
10
+ if (this.api) {
11
+ var _this$api$metrics;
12
+ this.api.core.actions.execute((_this$api$metrics = this.api.metrics) === null || _this$api$metrics === void 0 ? void 0 : _this$api$metrics.commands.stopActiveSession());
13
+ }
9
14
  this.cleanupTimer();
10
- }, 3000);
15
+ }, ACTIVE_SESSION_IDLE_TIME);
11
16
  });
12
17
  _defineProperty(this, "cleanupTimer", () => {
13
- if (this.api) {
14
- var _this$api$metrics;
15
- this.api.core.actions.execute((_this$api$metrics = this.api.metrics) === null || _this$api$metrics === void 0 ? void 0 : _this$api$metrics.commands.stopActiveSession());
16
- }
17
18
  if (this.timerId) {
18
19
  clearTimeout(this.timerId);
19
20
  this.timerId = null;
@@ -0,0 +1,38 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ export const getPayloadAttributes = ({
3
+ pluginState,
4
+ contentSizeChanged
5
+ }) => ({
6
+ efficiency: {
7
+ totalActiveTime: pluginState.activeSessionTime,
8
+ totalActionCount: pluginState.totalActionCount,
9
+ actionByTypeCount: pluginState.actionTypeCount
10
+ },
11
+ effectiveness: {
12
+ undoCount: pluginState.actionTypeCount.undoCount,
13
+ repeatedActionCount: 0,
14
+ safeInsertCount: 0
15
+ },
16
+ contentSizeChanged
17
+ });
18
+ export const getAnalyticsPayload = ({
19
+ pluginState
20
+ }) => ({
21
+ action: ACTION.ENDED,
22
+ actionSubject: ACTION_SUBJECT.ACTIVITY_SESSION,
23
+ actionSubjectId: ACTION_SUBJECT_ID.ACTIVITY,
24
+ attributes: {
25
+ efficiency: {
26
+ totalActiveTime: pluginState.activeSessionTime,
27
+ totalActionCount: pluginState.totalActionCount,
28
+ actionByTypeCount: pluginState.actionTypeCount
29
+ },
30
+ effectiveness: {
31
+ undoCount: pluginState.actionTypeCount.undoCount,
32
+ repeatedActionCount: 0,
33
+ safeInsertCount: 0
34
+ },
35
+ contentSizeChanged: pluginState.contentSizeChanged
36
+ },
37
+ eventType: EVENT_TYPE.TRACK
38
+ });
@@ -0,0 +1,24 @@
1
+ import { ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
2
+ export const isNonTextUndo = tr => {
3
+ if (tr.getMeta('undoRedoPlugin$') === undefined) {
4
+ return false;
5
+ }
6
+ let hasNonTextChange = false;
7
+ tr.steps.forEach(step => {
8
+ if (step instanceof ReplaceStep) {
9
+ const {
10
+ slice
11
+ } = step;
12
+ if (slice.content) {
13
+ slice.content.forEach(node => {
14
+ if (node.type.name !== 'text') {
15
+ hasNonTextChange = true;
16
+ }
17
+ });
18
+ }
19
+ } else {
20
+ hasNonTextChange = true;
21
+ }
22
+ });
23
+ return hasNonTextChange;
24
+ };
@@ -1,4 +1,5 @@
1
1
  import { createPlugin, initialPluginState, metricsKey } from './pm-plugins/main';
2
+ import { getAnalyticsPayload } from './pm-plugins/utils/analytics';
2
3
  /**
3
4
  * Metrics plugin to be added to an `EditorPresetBuilder` and used with `ComposableEditor`
4
5
  * from `@atlaskit/editor-core`.
@@ -23,43 +24,18 @@ export var metricsPlugin = function metricsPlugin(_ref) {
23
24
  return tr;
24
25
  }
25
26
  var newTr = tr;
27
+ var pluginState = api === null || api === void 0 ? void 0 : api.metrics.sharedState.currentState();
28
+ if (pluginState && pluginState.totalActionCount > 0 && pluginState.activeSessionTime > 0) {
29
+ var payloadToSend = getAnalyticsPayload({
30
+ pluginState: pluginState
31
+ });
32
+ api === null || api === void 0 || api.analytics.actions.attachAnalyticsEvent(payloadToSend)(newTr);
33
+ }
26
34
  newTr.setMeta(metricsKey, {
27
35
  stopActiveSession: true
28
36
  });
29
37
  return newTr;
30
38
  };
31
- },
32
- fireSessionAnalytics: function fireSessionAnalytics() {
33
- return function (_ref3) {
34
- var tr = _ref3.tr;
35
- if (!api) {
36
- return tr;
37
- }
38
- var state = api.metrics.sharedState.currentState();
39
- if (!state) {
40
- return tr;
41
- }
42
-
43
- // const eventAttributes = {
44
- // efficiency: {
45
- // totalActiveTime: state.activeSessionTime || 0,
46
- // totalActionCount: state.totalActionCount || 0,
47
- // actionTypeCount: state.actionTypeCount,
48
- // totalInactiveTime:
49
- // Date.now() - (state.editSessionStartTime || 0) - (state.activeSessionTime || 0),
50
- // },
51
- // TODO: Add effectiveness attributes
52
- // effectiveness: {
53
- // undoCount: 0,
54
- // repeatedActionCount: 0,
55
- // safeInsertCount: 0,
56
- // },
57
- // };
58
-
59
- // fire analytics event
60
- // api.analytics.actions.attachAnalyticsEvent({});
61
- return tr;
62
- };
63
39
  }
64
40
  },
65
41
  getSharedState: function getSharedState(editorState) {
@@ -1,25 +1,29 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
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
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 { bind } from 'bind-event-listener';
4
5
  import { AnalyticsStep } from '@atlaskit/adf-schema/steps';
5
6
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
7
  import { isTextInput } from '@atlaskit/editor-common/utils';
7
8
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
8
9
  import { ActiveSessionTimer } from './utils/active-session-timer';
10
+ import { getAnalyticsPayload } from './utils/analytics';
11
+ import { isNonTextUndo } from './utils/isNonTextUndo';
9
12
  export var metricsKey = new PluginKey('metricsPlugin');
10
13
  export var initialPluginState = {
11
- editSessionStartTime: undefined,
12
14
  intentToStartEditTime: undefined,
13
15
  lastSelection: undefined,
14
16
  activeSessionTime: 0,
15
17
  totalActionCount: 0,
18
+ contentSizeChanged: 0,
16
19
  timeOfLastTextInput: undefined,
17
20
  actionTypeCount: {
18
21
  textInputCount: 0,
19
22
  nodeInsertionCount: 0,
20
23
  nodeAttributeChangeCount: 0,
21
24
  contentMovedCount: 0,
22
- nodeDeletionCount: 0
25
+ nodeDeletionCount: 0,
26
+ undoCount: 0
23
27
  }
24
28
  };
25
29
  export var createPlugin = function createPlugin(api) {
@@ -28,23 +32,28 @@ export var createPlugin = function createPlugin(api) {
28
32
  key: metricsKey,
29
33
  state: {
30
34
  init: function init() {
31
- return _objectSpread(_objectSpread({}, initialPluginState), {}, {
32
- editSessionStartTime: performance.now()
33
- });
35
+ return initialPluginState;
34
36
  },
35
- apply: function apply(tr, pluginState) {
37
+ // eslint-disable-next-line @typescript-eslint/max-params
38
+ apply: function apply(tr, pluginState, oldState, newState) {
36
39
  var meta = tr.getMeta(metricsKey);
37
40
  var intentToStartEditTime = (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime;
38
41
  if (meta && meta.stopActiveSession) {
39
- // console.log('stopActiveSession');
40
- return _objectSpread(_objectSpread({}, pluginState), {}, {
41
- intentToStartEditTime: undefined,
42
- lastSelection: undefined
43
- });
42
+ return initialPluginState;
44
43
  }
45
44
  if (!intentToStartEditTime) {
46
- return pluginState;
45
+ if (tr.docChanged && !tr.getMeta('replaceDocument')) {
46
+ intentToStartEditTime = performance.now();
47
+ } else {
48
+ return pluginState;
49
+ }
47
50
  }
51
+ var undoCount = isNonTextUndo(tr) ? 1 : 0;
52
+ var newActionTypeCount = pluginState.actionTypeCount ? _objectSpread(_objectSpread({}, pluginState.actionTypeCount), {}, {
53
+ undoCount: pluginState.actionTypeCount.undoCount + undoCount
54
+ }) : _objectSpread(_objectSpread({}, initialPluginState.actionTypeCount), {}, {
55
+ undoCount: undoCount
56
+ });
48
57
  var canIgnoreTr = function canIgnoreTr() {
49
58
  return !tr.steps.every(function (e) {
50
59
  return e instanceof AnalyticsStep;
@@ -53,36 +62,64 @@ export var createPlugin = function createPlugin(api) {
53
62
  if (tr.docChanged && canIgnoreTr()) {
54
63
  var now = performance.now();
55
64
  timer.startTimer();
56
-
65
+ var actionTypeCount = pluginState.actionTypeCount,
66
+ timeOfLastTextInput = pluginState.timeOfLastTextInput,
67
+ totalActionCount = pluginState.totalActionCount,
68
+ activeSessionTime = pluginState.activeSessionTime;
57
69
  // If previous and current action is text insertion, then don't increase total action count
58
70
  var isActionTextInput = isTextInput(tr);
71
+ var newActiveSessionTime = activeSessionTime + (now - intentToStartEditTime);
72
+ var newTextInputCount = isActionTextInput ? actionTypeCount.textInputCount + 1 : actionTypeCount.textInputCount;
73
+ var newTotalActionCount = pluginState.totalActionCount + 1;
59
74
  if (pluginState.timeOfLastTextInput && isActionTextInput) {
60
- return _objectSpread(_objectSpread({}, pluginState), {}, {
61
- activeSessionTime: pluginState.activeSessionTime + (now - pluginState.timeOfLastTextInput),
62
- totalActionCount: pluginState.totalActionCount,
63
- timeOfLastTextInput: now
64
- });
75
+ newActiveSessionTime = activeSessionTime + (now - (timeOfLastTextInput || 0));
76
+ newTextInputCount = actionTypeCount.textInputCount;
77
+ newTotalActionCount = totalActionCount;
65
78
  }
66
-
67
- // TODO: Add actionTypeCount
68
- return _objectSpread(_objectSpread({}, pluginState), {}, {
69
- activeSessionTime: pluginState.activeSessionTime + (now - intentToStartEditTime),
70
- totalActionCount: pluginState.totalActionCount + 1,
71
- timeOfLastTextInput: isActionTextInput ? now : undefined
79
+ var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
80
+ activeSessionTime: newActiveSessionTime,
81
+ totalActionCount: newTotalActionCount,
82
+ timeOfLastTextInput: isActionTextInput ? now : undefined,
83
+ contentSizeChanged: pluginState.contentSizeChanged + (newState.doc.content.size - oldState.doc.content.size),
84
+ actionTypeCount: _objectSpread(_objectSpread({}, newActionTypeCount), {}, {
85
+ textInputCount: newTextInputCount
86
+ })
72
87
  });
88
+ return newPluginState;
73
89
  }
74
90
  return _objectSpread(_objectSpread({}, pluginState), {}, {
75
91
  lastSelection: (meta === null || meta === void 0 ? void 0 : meta.newSelection) || pluginState.lastSelection,
76
- intentToStartEditTime: (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime
92
+ intentToStartEditTime: intentToStartEditTime,
93
+ actionTypeCount: newActionTypeCount
77
94
  });
78
95
  }
79
96
  },
80
- view: function view() {
97
+ view: function view(_view) {
98
+ var fireAnalyticsEvent = function fireAnalyticsEvent() {
99
+ var pluginState = metricsKey.getState(_view.state);
100
+ if (!pluginState) {
101
+ return;
102
+ }
103
+ var payloadToSend = getAnalyticsPayload({
104
+ pluginState: pluginState
105
+ });
106
+ if (pluginState && pluginState.totalActionCount > 0 && pluginState.activeSessionTime > 0) {
107
+ api === null || api === void 0 || api.analytics.actions.fireAnalyticsEvent(payloadToSend, undefined, {
108
+ immediate: true
109
+ });
110
+ }
111
+ };
112
+ var unbindBeforeUnload = bind(window, {
113
+ type: 'beforeunload',
114
+ listener: function listener() {
115
+ fireAnalyticsEvent();
116
+ }
117
+ });
81
118
  return {
82
119
  destroy: function destroy() {
83
- var _api$metrics;
84
- api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$metrics = api.metrics) === null || _api$metrics === void 0 ? void 0 : _api$metrics.commands.fireSessionAnalytics());
120
+ fireAnalyticsEvent();
85
121
  timer.cleanupTimer();
122
+ unbindBeforeUnload();
86
123
  }
87
124
  };
88
125
  },
@@ -1,6 +1,7 @@
1
1
  import _createClass from "@babel/runtime/helpers/createClass";
2
2
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ var ACTIVE_SESSION_IDLE_TIME = 5000;
4
5
  export var ActiveSessionTimer = /*#__PURE__*/_createClass(function ActiveSessionTimer(api) {
5
6
  var _this = this;
6
7
  _classCallCheck(this, ActiveSessionTimer);
@@ -9,14 +10,14 @@ export var ActiveSessionTimer = /*#__PURE__*/_createClass(function ActiveSession
9
10
  clearTimeout(_this.timerId);
10
11
  }
11
12
  _this.timerId = window.setTimeout(function () {
13
+ if (_this.api) {
14
+ var _this$api$metrics;
15
+ _this.api.core.actions.execute((_this$api$metrics = _this.api.metrics) === null || _this$api$metrics === void 0 ? void 0 : _this$api$metrics.commands.stopActiveSession());
16
+ }
12
17
  _this.cleanupTimer();
13
- }, 3000);
18
+ }, ACTIVE_SESSION_IDLE_TIME);
14
19
  });
15
20
  _defineProperty(this, "cleanupTimer", function () {
16
- if (_this.api) {
17
- var _this$api$metrics;
18
- _this.api.core.actions.execute((_this$api$metrics = _this.api.metrics) === null || _this$api$metrics === void 0 ? void 0 : _this$api$metrics.commands.stopActiveSession());
19
- }
20
21
  if (_this.timerId) {
21
22
  clearTimeout(_this.timerId);
22
23
  _this.timerId = null;
@@ -0,0 +1,40 @@
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ export var getPayloadAttributes = function getPayloadAttributes(_ref) {
3
+ var pluginState = _ref.pluginState,
4
+ contentSizeChanged = _ref.contentSizeChanged;
5
+ return {
6
+ efficiency: {
7
+ totalActiveTime: pluginState.activeSessionTime,
8
+ totalActionCount: pluginState.totalActionCount,
9
+ actionByTypeCount: pluginState.actionTypeCount
10
+ },
11
+ effectiveness: {
12
+ undoCount: pluginState.actionTypeCount.undoCount,
13
+ repeatedActionCount: 0,
14
+ safeInsertCount: 0
15
+ },
16
+ contentSizeChanged: contentSizeChanged
17
+ };
18
+ };
19
+ export var getAnalyticsPayload = function getAnalyticsPayload(_ref2) {
20
+ var pluginState = _ref2.pluginState;
21
+ return {
22
+ action: ACTION.ENDED,
23
+ actionSubject: ACTION_SUBJECT.ACTIVITY_SESSION,
24
+ actionSubjectId: ACTION_SUBJECT_ID.ACTIVITY,
25
+ attributes: {
26
+ efficiency: {
27
+ totalActiveTime: pluginState.activeSessionTime,
28
+ totalActionCount: pluginState.totalActionCount,
29
+ actionByTypeCount: pluginState.actionTypeCount
30
+ },
31
+ effectiveness: {
32
+ undoCount: pluginState.actionTypeCount.undoCount,
33
+ repeatedActionCount: 0,
34
+ safeInsertCount: 0
35
+ },
36
+ contentSizeChanged: pluginState.contentSizeChanged
37
+ },
38
+ eventType: EVENT_TYPE.TRACK
39
+ };
40
+ };
@@ -0,0 +1,22 @@
1
+ import { ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
2
+ export var isNonTextUndo = function isNonTextUndo(tr) {
3
+ if (tr.getMeta('undoRedoPlugin$') === undefined) {
4
+ return false;
5
+ }
6
+ var hasNonTextChange = false;
7
+ tr.steps.forEach(function (step) {
8
+ if (step instanceof ReplaceStep) {
9
+ var slice = step.slice;
10
+ if (slice.content) {
11
+ slice.content.forEach(function (node) {
12
+ if (node.type.name !== 'text') {
13
+ hasNonTextChange = true;
14
+ }
15
+ });
16
+ }
17
+ } else {
18
+ hasNonTextChange = true;
19
+ }
20
+ });
21
+ return hasNonTextChange;
22
+ };
@@ -1,9 +1,10 @@
1
1
  import type { EditorCommand, NextEditorPlugin } from '@atlaskit/editor-common/types';
2
+ import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
2
3
  import type { MetricsState } from './pm-plugins/main';
3
4
  export type MetricsPlugin = NextEditorPlugin<'metrics', {
5
+ dependencies: [AnalyticsPlugin];
4
6
  sharedState: MetricsState;
5
7
  commands: {
6
8
  stopActiveSession: () => EditorCommand;
7
- fireSessionAnalytics: () => EditorCommand;
8
9
  };
9
10
  }>;
@@ -4,12 +4,12 @@ import { PluginKey, Selection } from '@atlaskit/editor-prosemirror/state';
4
4
  import { type MetricsPlugin } from '../metricsPluginType';
5
5
  export declare const metricsKey: PluginKey<any>;
6
6
  export type MetricsState = {
7
- editSessionStartTime?: number;
8
7
  intentToStartEditTime?: number;
9
8
  activeSessionTime: number;
10
9
  totalActionCount: number;
10
+ contentSizeChanged: number;
11
11
  lastSelection?: Selection;
12
- actionTypeCount?: ActionByType;
12
+ actionTypeCount: ActionByType;
13
13
  timeOfLastTextInput?: number;
14
14
  };
15
15
  export type ActionByType = {
@@ -18,6 +18,7 @@ export type ActionByType = {
18
18
  nodeAttributeChangeCount: number;
19
19
  contentMovedCount: number;
20
20
  nodeDeletionCount: number;
21
+ undoCount: number;
21
22
  };
22
23
  export declare const initialPluginState: MetricsState;
23
24
  export declare const createPlugin: (api: ExtractInjectionAPI<MetricsPlugin> | undefined) => SafePlugin<MetricsState>;
@@ -0,0 +1,11 @@
1
+ import { type ActiveSessionEventPayload, type ActiveSessionEventAttributes } from '@atlaskit/editor-common/analytics';
2
+ import type { MetricsState } from '../main';
3
+ type Props = {
4
+ pluginState: MetricsState;
5
+ contentSizeChanged: number;
6
+ };
7
+ export declare const getPayloadAttributes: ({ pluginState, contentSizeChanged, }: Props) => ActiveSessionEventAttributes;
8
+ export declare const getAnalyticsPayload: ({ pluginState, }: {
9
+ pluginState: MetricsState;
10
+ }) => ActiveSessionEventPayload;
11
+ export {};
@@ -0,0 +1,2 @@
1
+ import { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const isNonTextUndo: (tr: ReadonlyTransaction) => boolean;
@@ -1,9 +1,12 @@
1
1
  import type { EditorCommand, NextEditorPlugin } from '@atlaskit/editor-common/types';
2
+ import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
2
3
  import type { MetricsState } from './pm-plugins/main';
3
4
  export type MetricsPlugin = NextEditorPlugin<'metrics', {
5
+ dependencies: [
6
+ AnalyticsPlugin
7
+ ];
4
8
  sharedState: MetricsState;
5
9
  commands: {
6
10
  stopActiveSession: () => EditorCommand;
7
- fireSessionAnalytics: () => EditorCommand;
8
11
  };
9
12
  }>;
@@ -4,12 +4,12 @@ import { PluginKey, Selection } from '@atlaskit/editor-prosemirror/state';
4
4
  import { type MetricsPlugin } from '../metricsPluginType';
5
5
  export declare const metricsKey: PluginKey<any>;
6
6
  export type MetricsState = {
7
- editSessionStartTime?: number;
8
7
  intentToStartEditTime?: number;
9
8
  activeSessionTime: number;
10
9
  totalActionCount: number;
10
+ contentSizeChanged: number;
11
11
  lastSelection?: Selection;
12
- actionTypeCount?: ActionByType;
12
+ actionTypeCount: ActionByType;
13
13
  timeOfLastTextInput?: number;
14
14
  };
15
15
  export type ActionByType = {
@@ -18,6 +18,7 @@ export type ActionByType = {
18
18
  nodeAttributeChangeCount: number;
19
19
  contentMovedCount: number;
20
20
  nodeDeletionCount: number;
21
+ undoCount: number;
21
22
  };
22
23
  export declare const initialPluginState: MetricsState;
23
24
  export declare const createPlugin: (api: ExtractInjectionAPI<MetricsPlugin> | undefined) => SafePlugin<MetricsState>;
@@ -0,0 +1,11 @@
1
+ import { type ActiveSessionEventPayload, type ActiveSessionEventAttributes } from '@atlaskit/editor-common/analytics';
2
+ import type { MetricsState } from '../main';
3
+ type Props = {
4
+ pluginState: MetricsState;
5
+ contentSizeChanged: number;
6
+ };
7
+ export declare const getPayloadAttributes: ({ pluginState, contentSizeChanged, }: Props) => ActiveSessionEventAttributes;
8
+ export declare const getAnalyticsPayload: ({ pluginState, }: {
9
+ pluginState: MetricsState;
10
+ }) => ActiveSessionEventPayload;
11
+ export {};
@@ -0,0 +1,2 @@
1
+ import { ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const isNonTextUndo: (tr: ReadonlyTransaction) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-metrics",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "Metrics plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -25,10 +25,12 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@atlaskit/adf-schema": "^46.1.0",
28
- "@atlaskit/editor-common": "^99.1.1",
28
+ "@atlaskit/editor-common": "^99.5.0",
29
+ "@atlaskit/editor-plugin-analytics": "^1.11.0",
29
30
  "@atlaskit/editor-prosemirror": "6.2.1",
30
31
  "@atlaskit/platform-feature-flags": "^0.3.0",
31
- "@babel/runtime": "^7.0.0"
32
+ "@babel/runtime": "^7.0.0",
33
+ "bind-event-listener": "^3.0.0"
32
34
  },
33
35
  "peerDependencies": {
34
36
  "react": "^16.8.0"