@atlaskit/editor-common 110.25.0 → 110.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/analytics/types/enums.js +2 -0
  3. package/dist/cjs/analytics/types/experience-events.js +5 -0
  4. package/dist/cjs/experiences/Experience.js +104 -46
  5. package/dist/cjs/experiences/consts.js +13 -2
  6. package/dist/cjs/experiences/experience-state.js +32 -0
  7. package/dist/cjs/monitoring/error.js +1 -1
  8. package/dist/cjs/styles/shared/table.js +1 -0
  9. package/dist/cjs/ui/DropList/index.js +1 -1
  10. package/dist/cjs/user-intent/UserIntentPopupWrapper.js +1 -1
  11. package/dist/es2019/analytics/types/enums.js +2 -0
  12. package/dist/es2019/analytics/types/experience-events.js +1 -0
  13. package/dist/es2019/experiences/Experience.js +102 -42
  14. package/dist/es2019/experiences/consts.js +12 -1
  15. package/dist/es2019/experiences/experience-state.js +26 -0
  16. package/dist/es2019/monitoring/error.js +1 -1
  17. package/dist/es2019/styles/shared/table.js +1 -0
  18. package/dist/es2019/ui/DropList/index.js +1 -1
  19. package/dist/es2019/user-intent/UserIntentPopupWrapper.js +2 -2
  20. package/dist/esm/analytics/types/enums.js +2 -0
  21. package/dist/esm/analytics/types/experience-events.js +1 -0
  22. package/dist/esm/experiences/Experience.js +104 -46
  23. package/dist/esm/experiences/consts.js +12 -1
  24. package/dist/esm/experiences/experience-state.js +26 -0
  25. package/dist/esm/monitoring/error.js +1 -1
  26. package/dist/esm/styles/shared/table.js +1 -0
  27. package/dist/esm/ui/DropList/index.js +1 -1
  28. package/dist/esm/user-intent/UserIntentPopupWrapper.js +1 -1
  29. package/dist/types/analytics/index.d.ts +1 -0
  30. package/dist/types/analytics/types/enums.d.ts +2 -0
  31. package/dist/types/analytics/types/events.d.ts +2 -1
  32. package/dist/types/analytics/types/experience-events.d.ts +34 -0
  33. package/dist/types/experiences/Experience.d.ts +57 -11
  34. package/dist/types/experiences/consts.d.ts +10 -0
  35. package/dist/types/experiences/experience-state.d.ts +16 -0
  36. package/dist/types/styles/shared/table.d.ts +1 -0
  37. package/dist/types-ts4.5/analytics/index.d.ts +1 -0
  38. package/dist/types-ts4.5/analytics/types/enums.d.ts +2 -0
  39. package/dist/types-ts4.5/analytics/types/events.d.ts +2 -1
  40. package/dist/types-ts4.5/analytics/types/experience-events.d.ts +34 -0
  41. package/dist/types-ts4.5/experiences/Experience.d.ts +57 -11
  42. package/dist/types-ts4.5/experiences/consts.d.ts +10 -0
  43. package/dist/types-ts4.5/experiences/experience-state.d.ts +16 -0
  44. package/dist/types-ts4.5/styles/shared/table.d.ts +1 -0
  45. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/editor-common
2
2
 
3
+ ## 110.25.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`855e2a1085226`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/855e2a1085226) -
8
+ [ux] Scaffolding for native sticky headers
9
+ - Updated dependencies
10
+
11
+ ## 110.25.1
12
+
13
+ ### Patch Changes
14
+
15
+ - [`bedd622f2826d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bedd622f2826d) -
16
+ Fix sentry error where currentUserIntent state is undefined
17
+ - [`373dccb169d0b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/373dccb169d0b) -
18
+ ED-29654 Editor experience custom tracking
19
+ - Updated dependencies
20
+
3
21
  ## 110.25.0
4
22
 
5
23
  ### Minor Changes
@@ -62,6 +62,8 @@ var ACTION = exports.ACTION = /*#__PURE__*/function (ACTION) {
62
62
  ACTION["ENTERED"] = "entered";
63
63
  ACTION["ERROR"] = "error";
64
64
  ACTION["ERRORED"] = "errored";
65
+ ACTION["EXPERIENCE_MEASURED"] = "experienceMeasured";
66
+ ACTION["EXPERIENCE_SAMPLED"] = "experienceSampled";
65
67
  ACTION["EXPOSED"] = "exposed";
66
68
  ACTION["FAILED_TO_UNMOUNT"] = "failedToUnmount";
67
69
  ACTION["FAILED_TO_INSERT"] = "failedToInsert";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -5,52 +5,51 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.Experience = void 0;
8
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
8
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
10
9
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
11
- var _ufo = require("@atlaskit/ufo");
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+ var _analytics = require("../analytics");
12
+ var _consts = require("./consts");
13
+ var _experienceState = require("./experience-state");
12
14
  var _ExperienceCheckComposite = require("./ExperienceCheckComposite");
13
15
  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; }
14
16
  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; }
15
- var PROGRESS_STATES = [_ufo.UFOExperienceState.STARTED.id, _ufo.UFOExperienceState.IN_PROGRESS.id];
16
17
  var Experience = exports.Experience = /*#__PURE__*/function () {
17
- function Experience(id) {
18
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
18
+ /**
19
+ * Indicates whether sampled tracking is enabled for this current experience session.
20
+ *
21
+ * Set to true | false upon transitioning to 'started' state.
22
+ * When true, on subsequent transitions we fire experienceSampled events.
23
+ * Ensures that every tracked start has corresponding abort/fail/success tracked.
24
+ */
25
+
26
+ function Experience(id, options) {
27
+ var _options$sampleRate;
19
28
  (0, _classCallCheck2.default)(this, Experience);
29
+ (0, _defineProperty2.default)(this, "currentState", 'pending');
30
+ (0, _defineProperty2.default)(this, "statesSeen", new Set());
20
31
  this.id = id;
21
- this.options = options;
22
- this.check = new _ExperienceCheckComposite.ExperienceCheckComposite(this.options.checks || []);
32
+ this.dispatchAnalyticsEvent = options.dispatchAnalyticsEvent;
33
+ this.sampleRate = (_options$sampleRate = options.sampleRate) !== null && _options$sampleRate !== void 0 ? _options$sampleRate : _consts.DEFAULT_EXPERIENCE_SAMPLE_RATE;
34
+ this.check = new _ExperienceCheckComposite.ExperienceCheckComposite(options.checks || []);
23
35
  }
24
36
  return (0, _createClass2.default)(Experience, [{
25
- key: "ufoExperience",
26
- get: function get() {
27
- if (!this._ufoExperience) {
28
- this._ufoExperience = new _ufo.UFOExperience(this.id, {
29
- type: _ufo.ExperienceTypes.Experience,
30
- performanceType: _ufo.ExperiencePerformanceTypes.InlineResult,
31
- platform: {
32
- component: 'editor'
33
- }
34
- });
35
- }
36
- return this._ufoExperience;
37
- }
38
- }, {
39
37
  key: "startCheck",
40
38
  value: function startCheck() {
41
39
  var _this = this;
42
40
  this.stopCheck();
43
- this.check.start(function (result) {
44
- var metadata = result.metadata;
45
- if (result.status === 'success') {
41
+ this.check.start(function (_ref) {
42
+ var status = _ref.status,
43
+ metadata = _ref.metadata;
44
+ if (status === 'success') {
46
45
  _this.success({
47
46
  metadata: metadata
48
47
  });
49
- } else if (result.status === 'abort') {
48
+ } else if (status === 'abort') {
50
49
  _this.abort({
51
50
  metadata: metadata
52
51
  });
53
- } else if (result.status === 'failure') {
52
+ } else if (status === 'failure') {
54
53
  _this.failure({
55
54
  metadata: metadata
56
55
  });
@@ -62,11 +61,6 @@ var Experience = exports.Experience = /*#__PURE__*/function () {
62
61
  value: function stopCheck() {
63
62
  this.check.stop();
64
63
  }
65
- }, {
66
- key: "isInProgress",
67
- value: function isInProgress() {
68
- return PROGRESS_STATES.includes(this.ufoExperience.state.id);
69
- }
70
64
  }, {
71
65
  key: "getEndStateConfig",
72
66
  value: function getEndStateConfig(options) {
@@ -76,11 +70,72 @@ var Experience = exports.Experience = /*#__PURE__*/function () {
76
70
  };
77
71
  }
78
72
 
73
+ /**
74
+ * Transitions to a new experience state and tracks analytics events.
75
+ *
76
+ * Upon transition to each state, two events are tracked:
77
+ * - experienceMeasured: tracked on every successful transition, used for data analysis
78
+ * - experienceSampled: tracked only on 1 out of every N transitions based on sample rate
79
+ *
80
+ * @param toState - The target state to transition to
81
+ * @param metadata - Optional metadata to attach to the analytics events
82
+ * @returns true if transition was successful, false if invalid transition
83
+ */
84
+ }, {
85
+ key: "transitionTo",
86
+ value: function transitionTo(toState, metadata) {
87
+ if (!(0, _experienceState.canTransition)(this.currentState, toState)) {
88
+ return false;
89
+ }
90
+ this.statesSeen.add(toState);
91
+ this.currentState = toState;
92
+ if (toState === 'started') {
93
+ this.isSampledTrackingEnabled = Math.random() < this.sampleRate;
94
+ }
95
+ this.trackTransition(toState, metadata);
96
+ return true;
97
+ }
98
+
99
+ /**
100
+ * Tracks analytics events for a state transition.
101
+ *
102
+ * Fires both experienceMeasured (always) and experienceSampled (sampled) events.
103
+ *
104
+ * @param toState - The state that was transitioned to
105
+ * @param metadata - Metadata to include in the event, including firstInSession flag
106
+ */
107
+ }, {
108
+ key: "trackTransition",
109
+ value: function trackTransition(toState, metadata) {
110
+ var attributes = _objectSpread({
111
+ experienceKey: this.id,
112
+ experienceStatus: toState,
113
+ firstInSession: !this.statesSeen.has(toState)
114
+ }, metadata);
115
+ var experienceMeasuredEvent = {
116
+ action: _analytics.ACTION.EXPERIENCE_MEASURED,
117
+ actionSubject: _analytics.ACTION_SUBJECT.EDITOR,
118
+ actionSubjectId: undefined,
119
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
120
+ attributes: attributes
121
+ };
122
+ this.dispatchAnalyticsEvent(experienceMeasuredEvent);
123
+ if (this.isSampledTrackingEnabled) {
124
+ var experienceSampledEvent = {
125
+ action: _analytics.ACTION.EXPERIENCE_SAMPLED,
126
+ actionSubject: _analytics.ACTION_SUBJECT.EDITOR,
127
+ actionSubjectId: undefined,
128
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
129
+ attributes: attributes
130
+ };
131
+ this.dispatchAnalyticsEvent(experienceSampledEvent);
132
+ }
133
+ }
134
+
79
135
  /**
80
136
  * Starts tracking the experience and all checks which monitor for completion.
81
137
  *
82
- * If the experience is already in progress, this will restart the checks.
83
- * Metadata from options will be merged with any end state metadata.
138
+ * Metadata from options will be merged with metadata provided in subsequent events.
84
139
  *
85
140
  * @param options - Configuration for starting the experience
86
141
  * @param options.metadata - Optional metadata attached to all subsequent events for this started experience
@@ -89,8 +144,7 @@ var Experience = exports.Experience = /*#__PURE__*/function () {
89
144
  key: "start",
90
145
  value: function start(options) {
91
146
  this.startOptions = options;
92
- this.ufoExperience.start();
93
- if (this.isInProgress()) {
147
+ if (this.transitionTo('started', options === null || options === void 0 ? void 0 : options.metadata)) {
94
148
  this.startCheck();
95
149
  }
96
150
  }
@@ -98,17 +152,17 @@ var Experience = exports.Experience = /*#__PURE__*/function () {
98
152
  /**
99
153
  * Marks the experience as successful and stops any ongoing checks.
100
154
  *
101
- * Use this when the experience completes as expected.
102
- *
103
155
  * @param options - Configuration for the success event
104
156
  * @param options.metadata - Optional metadata attached to the success event
105
157
  */
106
158
  }, {
107
159
  key: "success",
108
160
  value: function success(options) {
109
- this.stopCheck();
110
- this.ufoExperience.success(this.getEndStateConfig(options));
111
- this.startOptions = undefined;
161
+ var mergedConfig = this.getEndStateConfig(options);
162
+ if (this.transitionTo('succeeded', mergedConfig.metadata)) {
163
+ this.stopCheck();
164
+ this.startOptions = undefined;
165
+ }
112
166
  }
113
167
 
114
168
  /**
@@ -129,9 +183,11 @@ var Experience = exports.Experience = /*#__PURE__*/function () {
129
183
  }, {
130
184
  key: "abort",
131
185
  value: function abort(options) {
132
- this.stopCheck();
133
- this.ufoExperience.abort(this.getEndStateConfig(options));
134
- this.startOptions = undefined;
186
+ var mergedConfig = this.getEndStateConfig(options);
187
+ if (this.transitionTo('aborted', mergedConfig.metadata)) {
188
+ this.stopCheck();
189
+ this.startOptions = undefined;
190
+ }
135
191
  }
136
192
 
137
193
  /**
@@ -145,9 +201,11 @@ var Experience = exports.Experience = /*#__PURE__*/function () {
145
201
  }, {
146
202
  key: "failure",
147
203
  value: function failure(options) {
148
- this.stopCheck();
149
- this.ufoExperience.failure(this.getEndStateConfig(options));
150
- this.startOptions = undefined;
204
+ var mergedConfig = this.getEndStateConfig(options);
205
+ if (this.transitionTo('failed', mergedConfig.metadata)) {
206
+ this.stopCheck();
207
+ this.startOptions = undefined;
208
+ }
151
209
  }
152
210
  }]);
153
211
  }();
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.EXPERIENCE_FAILURE_REASON = void 0;
6
+ exports.EXPERIENCE_FAILURE_REASON = exports.DEFAULT_EXPERIENCE_SAMPLE_RATE = void 0;
7
7
  /**
8
8
  * Built-in failure reasons for experience checks
9
9
  *
@@ -23,4 +23,15 @@ var EXPERIENCE_FAILURE_REASON = exports.EXPERIENCE_FAILURE_REASON = {
23
23
  * Error occurred during DOM mutation check execution
24
24
  */
25
25
  DOM_MUTATION_CHECK_ERROR: 'dom-mutation-check-error'
26
- };
26
+ };
27
+
28
+ /**
29
+ * Default sample rate for experienceSampled events.
30
+ * Set to 1 in 1000 (0.001) to balance data collection with event volume.
31
+ *
32
+ * Newly defined experiences should use this default unless they have data
33
+ * to justify a different rate. The expectation is that measurements will be
34
+ * gathered after initial instrumentation, then the sample rate can be tuned
35
+ * up to a safe threshold.
36
+ */
37
+ var DEFAULT_EXPERIENCE_SAMPLE_RATE = exports.DEFAULT_EXPERIENCE_SAMPLE_RATE = 0.001;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.canTransition = exports.EXPERIENCE_STATE_TRANSITIONS = void 0;
7
+ /**
8
+ * Represents the state of an experience throughout its lifecycle.
9
+ */
10
+
11
+ /**
12
+ * State transition map defining valid state transitions.
13
+ */
14
+ var EXPERIENCE_STATE_TRANSITIONS = exports.EXPERIENCE_STATE_TRANSITIONS = {
15
+ pending: ['started'],
16
+ started: ['aborted', 'failed', 'succeeded'],
17
+ aborted: ['started'],
18
+ failed: ['started'],
19
+ succeeded: ['started']
20
+ };
21
+
22
+ /**
23
+ * Validates whether a state transition is allowed.
24
+ *
25
+ * @param fromState - The current state
26
+ * @param toState - The target state to transition to
27
+ * @returns true if the transition is valid, false otherwise
28
+ */
29
+ var canTransition = exports.canTransition = function canTransition(fromState, toState) {
30
+ var _EXPERIENCE_STATE_TRA, _EXPERIENCE_STATE_TRA2;
31
+ return (_EXPERIENCE_STATE_TRA = (_EXPERIENCE_STATE_TRA2 = EXPERIENCE_STATE_TRANSITIONS[fromState]) === null || _EXPERIENCE_STATE_TRA2 === void 0 ? void 0 : _EXPERIENCE_STATE_TRA2.includes(toState)) !== null && _EXPERIENCE_STATE_TRA !== void 0 ? _EXPERIENCE_STATE_TRA : false;
32
+ };
@@ -16,7 +16,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
16
16
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
17
17
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
18
18
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
19
- var packageVersion = "110.24.3";
19
+ var packageVersion = "110.25.1";
20
20
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
21
21
  // Remove URL as it has UGC
22
22
  // Ignored via go/ees007
@@ -29,6 +29,7 @@ var tableControlsSpacing = exports.tableControlsSpacing = tableMarginTop + table
29
29
  var TableSharedCssClassName = exports.TableSharedCssClassName = {
30
30
  TABLE_CONTAINER: "".concat(_adfSchema.tablePrefixSelector, "-container"),
31
31
  TABLE_NODE_WRAPPER: "".concat(_adfSchema.tablePrefixSelector, "-wrapper"),
32
+ TABLE_NODE_WRAPPER_NO_OVERFLOW: "".concat(_adfSchema.tablePrefixSelector, "-wrapper-no-overflow"),
32
33
  TABLE_SCROLL_INLINE_SHADOW: "".concat(_adfSchema.tablePrefixSelector, "-scroll-inline-shadow"),
33
34
  TABLE_RIGHT_BORDER: "".concat(_adfSchema.tablePrefixSelector, "-right-border"),
34
35
  TABLE_LEFT_BORDER: "".concat(_adfSchema.tablePrefixSelector, "-left-border"),
@@ -24,7 +24,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
24
24
  * @jsx jsx
25
25
  */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
26
26
  var packageName = "@atlaskit/editor-common";
27
- var packageVersion = "110.24.3";
27
+ var packageVersion = "110.25.1";
28
28
  var halfFocusRing = 1;
29
29
  var dropOffset = '0, 8';
30
30
  var fadeIn = (0, _react2.keyframes)({
@@ -20,7 +20,7 @@ var UserIntentPopupWrapper = exports.UserIntentPopupWrapper = function UserInten
20
20
  api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent((0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_lovability_user_intent', 'isEnabled', true) ? userIntent : 'popupOpen'));
21
21
  return function () {
22
22
  var _api$userIntent2;
23
- if (userIntent === (api === null || api === void 0 || (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 ? void 0 : _api$userIntent2.sharedState.currentState().currentUserIntent) && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_lovability_user_intent', 'isEnabled', true)) {
23
+ if (userIntent === (api === null || api === void 0 || (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 || (_api$userIntent2 = _api$userIntent2.sharedState.currentState()) === null || _api$userIntent2 === void 0 ? void 0 : _api$userIntent2.currentUserIntent) && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_lovability_user_intent', 'isEnabled', true)) {
24
24
  var _api$userIntent3;
25
25
  api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent3 = api.userIntent) === null || _api$userIntent3 === void 0 ? void 0 : _api$userIntent3.commands.setCurrentUserIntent('default'));
26
26
  }
@@ -56,6 +56,8 @@ export let ACTION = /*#__PURE__*/function (ACTION) {
56
56
  ACTION["ENTERED"] = "entered";
57
57
  ACTION["ERROR"] = "error";
58
58
  ACTION["ERRORED"] = "errored";
59
+ ACTION["EXPERIENCE_MEASURED"] = "experienceMeasured";
60
+ ACTION["EXPERIENCE_SAMPLED"] = "experienceSampled";
59
61
  ACTION["EXPOSED"] = "exposed";
60
62
  ACTION["FAILED_TO_UNMOUNT"] = "failedToUnmount";
61
63
  ACTION["FAILED_TO_INSERT"] = "failedToInsert";
@@ -0,0 +1 @@
1
+ export {};
@@ -1,39 +1,41 @@
1
- import { ExperiencePerformanceTypes, ExperienceTypes, UFOExperience, UFOExperienceState } from '@atlaskit/ufo';
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '../analytics';
3
+ import { DEFAULT_EXPERIENCE_SAMPLE_RATE } from './consts';
4
+ import { canTransition } from './experience-state';
2
5
  import { ExperienceCheckComposite } from './ExperienceCheckComposite';
3
- const PROGRESS_STATES = [UFOExperienceState.STARTED.id, UFOExperienceState.IN_PROGRESS.id];
4
6
  export class Experience {
5
- constructor(id, options = {}) {
7
+ /**
8
+ * Indicates whether sampled tracking is enabled for this current experience session.
9
+ *
10
+ * Set to true | false upon transitioning to 'started' state.
11
+ * When true, on subsequent transitions we fire experienceSampled events.
12
+ * Ensures that every tracked start has corresponding abort/fail/success tracked.
13
+ */
14
+
15
+ constructor(id, options) {
16
+ var _options$sampleRate;
17
+ _defineProperty(this, "currentState", 'pending');
18
+ _defineProperty(this, "statesSeen", new Set());
6
19
  this.id = id;
7
- this.options = options;
8
- this.check = new ExperienceCheckComposite(this.options.checks || []);
9
- }
10
- get ufoExperience() {
11
- if (!this._ufoExperience) {
12
- this._ufoExperience = new UFOExperience(this.id, {
13
- type: ExperienceTypes.Experience,
14
- performanceType: ExperiencePerformanceTypes.InlineResult,
15
- platform: {
16
- component: 'editor'
17
- }
18
- });
19
- }
20
- return this._ufoExperience;
20
+ this.dispatchAnalyticsEvent = options.dispatchAnalyticsEvent;
21
+ this.sampleRate = (_options$sampleRate = options.sampleRate) !== null && _options$sampleRate !== void 0 ? _options$sampleRate : DEFAULT_EXPERIENCE_SAMPLE_RATE;
22
+ this.check = new ExperienceCheckComposite(options.checks || []);
21
23
  }
22
24
  startCheck() {
23
25
  this.stopCheck();
24
- this.check.start(result => {
25
- const {
26
- metadata
27
- } = result;
28
- if (result.status === 'success') {
26
+ this.check.start(({
27
+ status,
28
+ metadata
29
+ }) => {
30
+ if (status === 'success') {
29
31
  this.success({
30
32
  metadata
31
33
  });
32
- } else if (result.status === 'abort') {
34
+ } else if (status === 'abort') {
33
35
  this.abort({
34
36
  metadata
35
37
  });
36
- } else if (result.status === 'failure') {
38
+ } else if (status === 'failure') {
37
39
  this.failure({
38
40
  metadata
39
41
  });
@@ -43,9 +45,6 @@ export class Experience {
43
45
  stopCheck() {
44
46
  this.check.stop();
45
47
  }
46
- isInProgress() {
47
- return PROGRESS_STATES.includes(this.ufoExperience.state.id);
48
- }
49
48
  getEndStateConfig(options) {
50
49
  var _this$startOptions, _this$startOptions2;
51
50
  return {
@@ -56,19 +55,76 @@ export class Experience {
56
55
  };
57
56
  }
58
57
 
58
+ /**
59
+ * Transitions to a new experience state and tracks analytics events.
60
+ *
61
+ * Upon transition to each state, two events are tracked:
62
+ * - experienceMeasured: tracked on every successful transition, used for data analysis
63
+ * - experienceSampled: tracked only on 1 out of every N transitions based on sample rate
64
+ *
65
+ * @param toState - The target state to transition to
66
+ * @param metadata - Optional metadata to attach to the analytics events
67
+ * @returns true if transition was successful, false if invalid transition
68
+ */
69
+ transitionTo(toState, metadata) {
70
+ if (!canTransition(this.currentState, toState)) {
71
+ return false;
72
+ }
73
+ this.statesSeen.add(toState);
74
+ this.currentState = toState;
75
+ if (toState === 'started') {
76
+ this.isSampledTrackingEnabled = Math.random() < this.sampleRate;
77
+ }
78
+ this.trackTransition(toState, metadata);
79
+ return true;
80
+ }
81
+
82
+ /**
83
+ * Tracks analytics events for a state transition.
84
+ *
85
+ * Fires both experienceMeasured (always) and experienceSampled (sampled) events.
86
+ *
87
+ * @param toState - The state that was transitioned to
88
+ * @param metadata - Metadata to include in the event, including firstInSession flag
89
+ */
90
+ trackTransition(toState, metadata) {
91
+ const attributes = {
92
+ experienceKey: this.id,
93
+ experienceStatus: toState,
94
+ firstInSession: !this.statesSeen.has(toState),
95
+ ...metadata
96
+ };
97
+ const experienceMeasuredEvent = {
98
+ action: ACTION.EXPERIENCE_MEASURED,
99
+ actionSubject: ACTION_SUBJECT.EDITOR,
100
+ actionSubjectId: undefined,
101
+ eventType: EVENT_TYPE.OPERATIONAL,
102
+ attributes
103
+ };
104
+ this.dispatchAnalyticsEvent(experienceMeasuredEvent);
105
+ if (this.isSampledTrackingEnabled) {
106
+ const experienceSampledEvent = {
107
+ action: ACTION.EXPERIENCE_SAMPLED,
108
+ actionSubject: ACTION_SUBJECT.EDITOR,
109
+ actionSubjectId: undefined,
110
+ eventType: EVENT_TYPE.OPERATIONAL,
111
+ attributes
112
+ };
113
+ this.dispatchAnalyticsEvent(experienceSampledEvent);
114
+ }
115
+ }
116
+
59
117
  /**
60
118
  * Starts tracking the experience and all checks which monitor for completion.
61
119
  *
62
- * If the experience is already in progress, this will restart the checks.
63
- * Metadata from options will be merged with any end state metadata.
120
+ * Metadata from options will be merged with metadata provided in subsequent events.
64
121
  *
65
122
  * @param options - Configuration for starting the experience
66
123
  * @param options.metadata - Optional metadata attached to all subsequent events for this started experience
67
124
  */
68
125
  start(options) {
69
126
  this.startOptions = options;
70
- this.ufoExperience.start();
71
- if (this.isInProgress()) {
127
+ if (this.transitionTo('started', options === null || options === void 0 ? void 0 : options.metadata)) {
72
128
  this.startCheck();
73
129
  }
74
130
  }
@@ -76,15 +132,15 @@ export class Experience {
76
132
  /**
77
133
  * Marks the experience as successful and stops any ongoing checks.
78
134
  *
79
- * Use this when the experience completes as expected.
80
- *
81
135
  * @param options - Configuration for the success event
82
136
  * @param options.metadata - Optional metadata attached to the success event
83
137
  */
84
138
  success(options) {
85
- this.stopCheck();
86
- this.ufoExperience.success(this.getEndStateConfig(options));
87
- this.startOptions = undefined;
139
+ const mergedConfig = this.getEndStateConfig(options);
140
+ if (this.transitionTo('succeeded', mergedConfig.metadata)) {
141
+ this.stopCheck();
142
+ this.startOptions = undefined;
143
+ }
88
144
  }
89
145
 
90
146
  /**
@@ -103,9 +159,11 @@ export class Experience {
103
159
  * }, []);
104
160
  */
105
161
  abort(options) {
106
- this.stopCheck();
107
- this.ufoExperience.abort(this.getEndStateConfig(options));
108
- this.startOptions = undefined;
162
+ const mergedConfig = this.getEndStateConfig(options);
163
+ if (this.transitionTo('aborted', mergedConfig.metadata)) {
164
+ this.stopCheck();
165
+ this.startOptions = undefined;
166
+ }
109
167
  }
110
168
 
111
169
  /**
@@ -117,8 +175,10 @@ export class Experience {
117
175
  * @param options.metadata - Optional metadata attached to the failure event
118
176
  */
119
177
  failure(options) {
120
- this.stopCheck();
121
- this.ufoExperience.failure(this.getEndStateConfig(options));
122
- this.startOptions = undefined;
178
+ const mergedConfig = this.getEndStateConfig(options);
179
+ if (this.transitionTo('failed', mergedConfig.metadata)) {
180
+ this.stopCheck();
181
+ this.startOptions = undefined;
182
+ }
123
183
  }
124
184
  }
@@ -17,4 +17,15 @@ export const EXPERIENCE_FAILURE_REASON = {
17
17
  * Error occurred during DOM mutation check execution
18
18
  */
19
19
  DOM_MUTATION_CHECK_ERROR: 'dom-mutation-check-error'
20
- };
20
+ };
21
+
22
+ /**
23
+ * Default sample rate for experienceSampled events.
24
+ * Set to 1 in 1000 (0.001) to balance data collection with event volume.
25
+ *
26
+ * Newly defined experiences should use this default unless they have data
27
+ * to justify a different rate. The expectation is that measurements will be
28
+ * gathered after initial instrumentation, then the sample rate can be tuned
29
+ * up to a safe threshold.
30
+ */
31
+ export const DEFAULT_EXPERIENCE_SAMPLE_RATE = 0.001;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Represents the state of an experience throughout its lifecycle.
3
+ */
4
+
5
+ /**
6
+ * State transition map defining valid state transitions.
7
+ */
8
+ export const EXPERIENCE_STATE_TRANSITIONS = {
9
+ pending: ['started'],
10
+ started: ['aborted', 'failed', 'succeeded'],
11
+ aborted: ['started'],
12
+ failed: ['started'],
13
+ succeeded: ['started']
14
+ };
15
+
16
+ /**
17
+ * Validates whether a state transition is allowed.
18
+ *
19
+ * @param fromState - The current state
20
+ * @param toState - The target state to transition to
21
+ * @returns true if the transition is valid, false otherwise
22
+ */
23
+ export const canTransition = (fromState, toState) => {
24
+ var _EXPERIENCE_STATE_TRA, _EXPERIENCE_STATE_TRA2;
25
+ return (_EXPERIENCE_STATE_TRA = (_EXPERIENCE_STATE_TRA2 = EXPERIENCE_STATE_TRANSITIONS[fromState]) === null || _EXPERIENCE_STATE_TRA2 === void 0 ? void 0 : _EXPERIENCE_STATE_TRA2.includes(toState)) !== null && _EXPERIENCE_STATE_TRA !== void 0 ? _EXPERIENCE_STATE_TRA : false;
26
+ };
@@ -1,7 +1,7 @@
1
1
  import { isFedRamp } from './environment';
2
2
  const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
3
3
  const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
4
- const packageVersion = "110.24.3";
4
+ const packageVersion = "110.25.1";
5
5
  const sanitiseSentryEvents = (data, _hint) => {
6
6
  // Remove URL as it has UGC
7
7
  // Ignored via go/ees007
@@ -21,6 +21,7 @@ export const tableControlsSpacing = tableMarginTop + tablePadding - tableCellBor
21
21
  export const TableSharedCssClassName = {
22
22
  TABLE_CONTAINER: `${tablePrefixSelector}-container`,
23
23
  TABLE_NODE_WRAPPER: `${tablePrefixSelector}-wrapper`,
24
+ TABLE_NODE_WRAPPER_NO_OVERFLOW: `${tablePrefixSelector}-wrapper-no-overflow`,
24
25
  TABLE_SCROLL_INLINE_SHADOW: `${tablePrefixSelector}-scroll-inline-shadow`,
25
26
  TABLE_RIGHT_BORDER: `${tablePrefixSelector}-right-border`,
26
27
  TABLE_LEFT_BORDER: `${tablePrefixSelector}-left-border`,
@@ -14,7 +14,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
14
14
  import { fg } from '@atlaskit/platform-feature-flags';
15
15
  import Layer from '../Layer';
16
16
  const packageName = "@atlaskit/editor-common";
17
- const packageVersion = "110.24.3";
17
+ const packageVersion = "110.25.1";
18
18
  const halfFocusRing = 1;
19
19
  const dropOffset = '0, 8';
20
20
  const fadeIn = keyframes({