@atlaskit/react-ufo 4.6.0 → 4.6.1

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 (26) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/create-post-interaction-log-payload/get-late-mutations.js +15 -3
  3. package/dist/cjs/create-post-interaction-log-payload/index.js +2 -1
  4. package/dist/cjs/vc/vc-observer-new/index.js +74 -11
  5. package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +78 -34
  6. package/dist/es2019/create-post-interaction-log-payload/get-late-mutations.js +12 -3
  7. package/dist/es2019/create-post-interaction-log-payload/index.js +2 -1
  8. package/dist/es2019/vc/vc-observer-new/index.js +67 -10
  9. package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +41 -7
  10. package/dist/esm/create-post-interaction-log-payload/get-late-mutations.js +15 -3
  11. package/dist/esm/create-post-interaction-log-payload/index.js +2 -1
  12. package/dist/esm/vc/vc-observer-new/index.js +74 -11
  13. package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +78 -34
  14. package/dist/types/common/react-ufo-payload-schema.d.ts +2 -0
  15. package/dist/types/common/vc/types.d.ts +7 -0
  16. package/dist/types/create-post-interaction-log-payload/get-late-mutations.d.ts +2 -2
  17. package/dist/types/vc/vc-observer/getVCRevisionDebugDetails.d.ts +1 -1
  18. package/dist/types/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -0
  19. package/dist/types/vc/vc-observer-new/types.d.ts +5 -0
  20. package/dist/types-ts4.5/common/react-ufo-payload-schema.d.ts +2 -0
  21. package/dist/types-ts4.5/common/vc/types.d.ts +7 -0
  22. package/dist/types-ts4.5/create-post-interaction-log-payload/get-late-mutations.d.ts +2 -2
  23. package/dist/types-ts4.5/vc/vc-observer/getVCRevisionDebugDetails.d.ts +1 -1
  24. package/dist/types-ts4.5/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.d.ts +1 -0
  25. package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +5 -0
  26. package/package.json +7 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @atlaskit/ufo-interaction-ignore
2
2
 
3
+ ## 4.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`a308f1abf3cf2`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a308f1abf3cf2) -
8
+ unify abort status within TTVC debug data
9
+
3
10
  ## 4.6.0
4
11
 
5
12
  ### Minor Changes
@@ -4,10 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
7
8
  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; } } }; }
8
9
  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; } }
9
10
  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; }
10
- function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios) {
11
+ function getLateMutations(vcDetails) {
12
+ var labelStacks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13
+ var lastInteractionFinish = arguments.length > 2 ? arguments[2] : undefined;
14
+ var postInteractionFinishVCRatios = arguments.length > 3 ? arguments[3] : undefined;
11
15
  // Map to track which elements are already seen for each timestamp
12
16
  var seen = new Map();
13
17
  var result = [];
@@ -29,11 +33,19 @@ function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinis
29
33
  continue;
30
34
  }
31
35
  seenElements.add(element);
32
- result.push({
36
+ var lateMutation = {
33
37
  time: details.t,
34
38
  element: element,
35
39
  viewportHeatmapPercentage: (postInteractionFinishVCRatios === null || postInteractionFinishVCRatios === void 0 ? void 0 : postInteractionFinishVCRatios[element]) || 0
36
- });
40
+ };
41
+ if (labelStacks && (0, _platformFeatureFlags.fg)('platform_ufo_enable_late_mutation_label_stacks')) {
42
+ var labels = labelStacks[element];
43
+ if (labels) {
44
+ lateMutation.segment = labels.segment;
45
+ lateMutation.labelStack = labels.labelStack;
46
+ }
47
+ }
48
+ result.push(lateMutation);
37
49
  }
38
50
  } catch (err) {
39
51
  _iterator.e(err);
@@ -190,8 +190,9 @@ function createPostInteractionLogPayload(_ref2) {
190
190
  revisedVC90 = (_postInteractionFinis = postInteractionFinishRevision['metric:vc90']) !== null && _postInteractionFinis !== void 0 ? _postInteractionFinis : null;
191
191
  }
192
192
  var vcDetails = postInteractionFinishRevision.vcDetails;
193
+ var labelStacks = postInteractionFinishRevision.labelStacks;
193
194
  if (vcDetails) {
194
- lateMutations = (0, _getLateMutations.default)(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios);
195
+ lateMutations = (0, _getLateMutations.default)(vcDetails, labelStacks, lastInteractionFinish, postInteractionFinishVCRatios);
195
196
  }
196
197
  }
197
198
  return {
@@ -12,6 +12,7 @@ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
12
12
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13
13
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
14
14
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
15
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
16
  var _ssrPlaceholders = require("../vc-observer/observers/ssr-placeholders");
16
17
  var _entriesTimeline = _interopRequireDefault(require("./entries-timeline"));
17
18
  var _getElementName2 = _interopRequireDefault(require("./get-element-name"));
@@ -75,18 +76,27 @@ var VCObserverNew = exports.default = /*#__PURE__*/function () {
75
76
  if (element) {
76
77
  elementName = _this.getElementName(element);
77
78
  }
79
+ var data = {
80
+ type: type,
81
+ elementName: elementName,
82
+ rect: rect,
83
+ previousRect: previousRect,
84
+ visible: visible,
85
+ attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
86
+ oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
87
+ newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
88
+ };
89
+ if (element && _this.isPostInteraction && (0, _platformFeatureFlags.fg)('platform_ufo_enable_late_mutation_label_stacks')) {
90
+ var labelStacks = getLabelStacks(element);
91
+ if (labelStacks) {
92
+ Object.assign(data, {
93
+ labelStacks: labelStacks
94
+ });
95
+ }
96
+ }
78
97
  _this.entriesTimeline.push({
79
98
  time: time,
80
- data: {
81
- type: type,
82
- elementName: elementName,
83
- rect: rect,
84
- previousRect: previousRect,
85
- visible: visible,
86
- attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
87
- oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
88
- newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
89
- }
99
+ data: data
90
100
  });
91
101
  },
92
102
  // Pass SSR context to ViewportObserver
@@ -308,4 +318,57 @@ var VCObserverNew = exports.default = /*#__PURE__*/function () {
308
318
  return (0, _getElementName2.default)(this.selectorConfig, element);
309
319
  }
310
320
  }]);
311
- }();
321
+ }();
322
+ function labelStackFromFiber(fiber) {
323
+ var _fiber$child;
324
+ var value = fiber === null || fiber === void 0 || (_fiber$child = fiber.child) === null || _fiber$child === void 0 || (_fiber$child = _fiber$child.memoizedProps) === null || _fiber$child === void 0 ? void 0 : _fiber$child.value;
325
+ return Array.isArray(value === null || value === void 0 ? void 0 : value.labelStack) ? value.labelStack : [];
326
+ }
327
+ function labelStackToString(labelStack) {
328
+ return labelStack.map(function (label) {
329
+ return label.name;
330
+ }).join('/');
331
+ }
332
+ function labelStackToSegment(labelStack) {
333
+ var segmentIndex = -1;
334
+ for (var i = labelStack.length - 1; i >= 0; i--) {
335
+ if (labelStack[i].segmentId) {
336
+ segmentIndex = i;
337
+ break;
338
+ }
339
+ }
340
+ return labelStack.slice(0, segmentIndex + 1).map(function (label) {
341
+ return label.name;
342
+ }).join('/');
343
+ }
344
+ function traverseFiber(fiber) {
345
+ var segment = 'unknown';
346
+ var labelStackString = 'unknown';
347
+ var currentFiber = fiber;
348
+ while (currentFiber) {
349
+ if (currentFiber.type) {
350
+ var componentName = currentFiber.type.displayName || currentFiber.type.name;
351
+ if (componentName === 'UFOSegment' || componentName === 'UFOLabel') {
352
+ var labelStack = labelStackFromFiber(currentFiber);
353
+ labelStackString = labelStackToString(labelStack) || 'unknown';
354
+ segment = labelStackToSegment(labelStack) || 'unknown';
355
+ break;
356
+ }
357
+ }
358
+ currentFiber = currentFiber.return;
359
+ }
360
+ return {
361
+ segment: segment,
362
+ labelStack: labelStackString
363
+ };
364
+ }
365
+ function getLabelStacks(element) {
366
+ var reactFiberKey = Object.keys(element).find(function (key) {
367
+ return key.startsWith('__reactFiber$');
368
+ });
369
+ if (!reactFiberKey) {
370
+ return null;
371
+ }
372
+ var fiber = element[reactFiberKey];
373
+ return fiber ? traverseFiber(fiber) : null;
374
+ }
@@ -13,6 +13,9 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
13
13
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
14
14
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
15
15
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
16
+ var _getPageVisibilityUpToTtai = _interopRequireDefault(require("../../../create-payload/utils/get-page-visibility-up-to-ttai"));
17
+ var _interactionIdContext = require("../../../interaction-id-context");
18
+ var _constants = require("../../../interaction-metrics/common/constants");
16
19
  var _trackDisplayContentOccurrence = require("../viewport-observer/utils/track-display-content-occurrence");
17
20
  var _percentileCalc = require("./percentile-calc");
18
21
  var _getViewportHeight = _interopRequireDefault(require("./utils/get-viewport-height"));
@@ -82,12 +85,35 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
82
85
  }
83
86
  return ratios;
84
87
  }
88
+ }, {
89
+ key: "getLabelStacks",
90
+ value: function getLabelStacks(filteredEntries) {
91
+ var labelStacks = {};
92
+ var _iterator3 = _createForOfIteratorHelper(filteredEntries),
93
+ _step3;
94
+ try {
95
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
96
+ var _entry2 = _step3.value;
97
+ if ('elementName' in _entry2.data && _entry2.data.labelStacks) {
98
+ labelStacks[_entry2.data.elementName] = {
99
+ segment: _entry2.data.labelStacks.segment,
100
+ labelStack: _entry2.data.labelStacks.labelStack
101
+ };
102
+ }
103
+ }
104
+ } catch (err) {
105
+ _iterator3.e(err);
106
+ } finally {
107
+ _iterator3.f();
108
+ }
109
+ return labelStacks;
110
+ }
85
111
  }, {
86
112
  key: "calculateWithDebugInfo",
87
113
  value: function () {
88
114
  var _calculateWithDebugInfo = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason, allEntries, include3p) {
89
115
  var _window, _window2, _window3, _window5;
90
- var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _iterator3, _step3, _entry2, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculate3p, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator4, _step4, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator5, _step5, _entry3, _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou, viewportData, timestamp, additionalVcLogs, _iterator6, _step6, _step6$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _window4, _window4$__ufo_devtoo, _window6, _window6$__on_ufo_vc_;
116
+ var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _iterator4, _step4, _entry3, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculate3p, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator5, _step5, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator6, _step6, _entry4, _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou, viewportData, timestamp, additionalVcLogs, _iterator7, _step7, _step7$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _activeInteractionId$, activeInteractionId, activeInteraction, pageVisibilityUpToTTAI, isBackgrounded, _window4, _window4$__ufo_devtoo, _window6, _window6$__on_ufo_vc_;
91
117
  return _regenerator.default.wrap(function _callee$(_context) {
92
118
  while (1) switch (_context.prev = _context.next) {
93
119
  case 0:
@@ -115,16 +141,16 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
115
141
  _context.next = 29;
116
142
  break;
117
143
  }
118
- _iterator3 = _createForOfIteratorHelper(vcLogs);
144
+ _iterator4 = _createForOfIteratorHelper(vcLogs);
119
145
  _context.prev = 11;
120
- _iterator3.s();
146
+ _iterator4.s();
121
147
  case 13:
122
- if ((_step3 = _iterator3.n()).done) {
148
+ if ((_step4 = _iterator4.n()).done) {
123
149
  _context.next = 21;
124
150
  break;
125
151
  }
126
- _entry2 = _step3.value;
127
- time = _entry2.time, viewportPercentage = _entry2.viewportPercentage, entries = _entry2.entries; // Only process entries if we haven't reached all percentiles
152
+ _entry3 = _step4.value;
153
+ time = _entry3.time, viewportPercentage = _entry3.viewportPercentage, entries = _entry3.entries; // Only process entries if we haven't reached all percentiles
128
154
  if (!(percentileIndex >= percentiles.length)) {
129
155
  _context.next = 18;
130
156
  break;
@@ -161,10 +187,10 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
161
187
  case 23:
162
188
  _context.prev = 23;
163
189
  _context.t0 = _context["catch"](11);
164
- _iterator3.e(_context.t0);
190
+ _iterator4.e(_context.t0);
165
191
  case 26:
166
192
  _context.prev = 26;
167
- _iterator3.f();
193
+ _iterator4.f();
168
194
  return _context.finish(26);
169
195
  case 29:
170
196
  // Fill in any missing percentiles with the last known values
@@ -202,10 +228,10 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
202
228
  }); // Pre-calculate max viewport percentage up to each time for efficient lookups
203
229
  maxViewportPercentageAtTime = new Map();
204
230
  maxSoFar = 0;
205
- _iterator4 = _createForOfIteratorHelper(sortedVcLogs);
231
+ _iterator5 = _createForOfIteratorHelper(sortedVcLogs);
206
232
  try {
207
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
208
- log = _step4.value;
233
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
234
+ log = _step5.value;
209
235
  if (log.viewportPercentage !== null) {
210
236
  maxSoFar = Math.max(maxSoFar, log.viewportPercentage);
211
237
  maxViewportPercentageAtTime.set(log.time, maxSoFar);
@@ -214,9 +240,9 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
214
240
 
215
241
  // Helper function to find the biggest previous viewport percentage
216
242
  } catch (err) {
217
- _iterator4.e(err);
243
+ _iterator5.e(err);
218
244
  } finally {
219
- _iterator4.f();
245
+ _iterator5.f();
220
246
  }
221
247
  getBiggestPreviousViewportPercentage = function getBiggestPreviousViewportPercentage(targetTime) {
222
248
  // Binary search for the largest time <= targetTime
@@ -235,13 +261,13 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
235
261
  return result >= 0 ? maxViewportPercentageAtTime.get(sortedVcLogs[result].time) || null : null;
236
262
  }; // Group ignored entries by timestamp
237
263
  ignoredEntriesByTime = new Map();
238
- _iterator5 = _createForOfIteratorHelper(allEntries);
264
+ _iterator6 = _createForOfIteratorHelper(allEntries);
239
265
  try {
240
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
241
- _entry3 = _step5.value;
242
- if ('rect' in _entry3.data && !this.isEntryIncluded(_entry3, include3p)) {
243
- viewportData = _entry3.data;
244
- timestamp = Math.round(_entry3.time);
266
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
267
+ _entry4 = _step6.value;
268
+ if ('rect' in _entry4.data && !this.isEntryIncluded(_entry4, include3p)) {
269
+ viewportData = _entry4.data;
270
+ timestamp = Math.round(_entry4.time);
245
271
  if (!ignoredEntriesByTime.has(timestamp)) {
246
272
  ignoredEntriesByTime.set(timestamp, []);
247
273
  }
@@ -256,15 +282,15 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
256
282
 
257
283
  // Add ignored entries to vcLogs
258
284
  } catch (err) {
259
- _iterator5.e(err);
285
+ _iterator6.e(err);
260
286
  } finally {
261
- _iterator5.f();
287
+ _iterator6.f();
262
288
  }
263
289
  additionalVcLogs = [];
264
- _iterator6 = _createForOfIteratorHelper(ignoredEntriesByTime);
290
+ _iterator7 = _createForOfIteratorHelper(ignoredEntriesByTime);
265
291
  try {
266
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
267
- _step6$value = (0, _slicedToArray2.default)(_step6.value, 2), _timestamp = _step6$value[0], ignoredEntries = _step6$value[1];
292
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
293
+ _step7$value = (0, _slicedToArray2.default)(_step7.value, 2), _timestamp = _step7$value[0], ignoredEntries = _step7$value[1];
268
294
  if (ignoredEntries.length > 0) {
269
295
  _viewportPercentage = getBiggestPreviousViewportPercentage(_timestamp);
270
296
  additionalVcLogs.push({
@@ -277,9 +303,9 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
277
303
 
278
304
  // Combine and sort all vcLogs
279
305
  } catch (err) {
280
- _iterator6.e(err);
306
+ _iterator7.e(err);
281
307
  } finally {
282
- _iterator6.f();
308
+ _iterator7.f();
283
309
  }
284
310
  enhancedVcLogs = [].concat((0, _toConsumableArray2.default)(enhancedVcLogs), additionalVcLogs).sort(function (a, b) {
285
311
  return a.time - b.time;
@@ -289,13 +315,28 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
289
315
  // Only create debug details if callbacks exist
290
316
  v3RevisionDebugDetails = null;
291
317
  if (shouldCalculateDebugDetails) {
292
- v3RevisionDebugDetails = {
293
- revision: this.revisionNo,
294
- isClean: isVCClean,
295
- abortReason: dirtyReason,
296
- vcLogs: enhancedVcLogs,
297
- interactionId: interactionId
298
- };
318
+ if ((0, _platformFeatureFlags.fg)('platform_ufo_unify_abort_status_in_ttvc_debug_data')) {
319
+ // NOTE: using this instead of directly calling `getActiveInteraction()` to get around circular dependencies
320
+ activeInteractionId = (0, _interactionIdContext.getInteractionId)();
321
+ activeInteraction = _constants.interactions.get((_activeInteractionId$ = activeInteractionId.current) !== null && _activeInteractionId$ !== void 0 ? _activeInteractionId$ : '');
322
+ pageVisibilityUpToTTAI = activeInteraction ? (0, _getPageVisibilityUpToTtai.default)(activeInteraction) : null;
323
+ isBackgrounded = pageVisibilityUpToTTAI !== 'visible';
324
+ v3RevisionDebugDetails = {
325
+ revision: this.revisionNo,
326
+ isClean: isVCClean && !(activeInteraction !== null && activeInteraction !== void 0 && activeInteraction.abortReason) && !isBackgrounded,
327
+ abortReason: isBackgrounded ? 'browser_backgrounded' : dirtyReason !== null && dirtyReason !== void 0 ? dirtyReason : activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.abortReason,
328
+ vcLogs: enhancedVcLogs,
329
+ interactionId: interactionId
330
+ };
331
+ } else {
332
+ v3RevisionDebugDetails = {
333
+ revision: this.revisionNo,
334
+ isClean: isVCClean,
335
+ abortReason: dirtyReason,
336
+ vcLogs: enhancedVcLogs,
337
+ interactionId: interactionId
338
+ };
339
+ }
299
340
  }
300
341
 
301
342
  // Handle devtool callback
@@ -379,11 +420,14 @@ var AbstractVCCalculatorBase = exports.default = /*#__PURE__*/function () {
379
420
  vcDetails: vcDetails !== null && vcDetails !== void 0 ? vcDetails : undefined
380
421
  };
381
422
  result.ratios = this.calculateRatios(filteredEntries);
423
+ if (isPostInteraction) {
424
+ result.labelStacks = this.getLabelStacks(filteredEntries);
425
+ }
382
426
  if ((0, _platformFeatureFlags.fg)('platform_ufo_display_content_track_occurrence')) {
383
427
  result.displayContentsOccurrence = _trackDisplayContentOccurrence.cssIssueOccurrence;
384
428
  }
385
429
  return _context2.abrupt("return", result);
386
- case 14:
430
+ case 15:
387
431
  case "end":
388
432
  return _context2.stop();
389
433
  }
@@ -1,4 +1,5 @@
1
- function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios) {
1
+ import { fg } from '@atlaskit/platform-feature-flags';
2
+ function getLateMutations(vcDetails, labelStacks = {}, lastInteractionFinish, postInteractionFinishVCRatios) {
2
3
  // Map to track which elements are already seen for each timestamp
3
4
  const seen = new Map();
4
5
  const result = [];
@@ -16,11 +17,19 @@ function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinis
16
17
  continue;
17
18
  }
18
19
  seenElements.add(element);
19
- result.push({
20
+ const lateMutation = {
20
21
  time: details.t,
21
22
  element,
22
23
  viewportHeatmapPercentage: (postInteractionFinishVCRatios === null || postInteractionFinishVCRatios === void 0 ? void 0 : postInteractionFinishVCRatios[element]) || 0
23
- });
24
+ };
25
+ if (labelStacks && fg('platform_ufo_enable_late_mutation_label_stacks')) {
26
+ const labels = labelStacks[element];
27
+ if (labels) {
28
+ lateMutation.segment = labels.segment;
29
+ lateMutation.labelStack = labels.labelStack;
30
+ }
31
+ }
32
+ result.push(lateMutation);
24
33
  }
25
34
  }
26
35
  return result;
@@ -173,8 +173,9 @@ function createPostInteractionLogPayload({
173
173
  revisedVC90 = (_postInteractionFinis = postInteractionFinishRevision['metric:vc90']) !== null && _postInteractionFinis !== void 0 ? _postInteractionFinis : null;
174
174
  }
175
175
  const vcDetails = postInteractionFinishRevision.vcDetails;
176
+ const labelStacks = postInteractionFinishRevision.labelStacks;
176
177
  if (vcDetails) {
177
- lateMutations = getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios);
178
+ lateMutations = getLateMutations(vcDetails, labelStacks, lastInteractionFinish, postInteractionFinishVCRatios);
178
179
  }
179
180
  }
180
181
  return {
@@ -1,4 +1,5 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { fg } from '@atlaskit/platform-feature-flags';
2
3
  import { SSRPlaceholderHandlers } from '../vc-observer/observers/ssr-placeholders';
3
4
  import EntriesTimeline from './entries-timeline';
4
5
  import getElementName from './get-element-name';
@@ -61,18 +62,27 @@ export default class VCObserverNew {
61
62
  if (element) {
62
63
  elementName = this.getElementName(element);
63
64
  }
65
+ const data = {
66
+ type,
67
+ elementName,
68
+ rect,
69
+ previousRect,
70
+ visible,
71
+ attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
72
+ oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
73
+ newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
74
+ };
75
+ if (element && this.isPostInteraction && fg('platform_ufo_enable_late_mutation_label_stacks')) {
76
+ const labelStacks = getLabelStacks(element);
77
+ if (labelStacks) {
78
+ Object.assign(data, {
79
+ labelStacks
80
+ });
81
+ }
82
+ }
64
83
  this.entriesTimeline.push({
65
84
  time,
66
- data: {
67
- type,
68
- elementName,
69
- rect,
70
- previousRect,
71
- visible,
72
- attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
73
- oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
74
- newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
75
- }
85
+ data
76
86
  });
77
87
  },
78
88
  // Pass SSR context to ViewportObserver
@@ -245,4 +255,51 @@ export default class VCObserverNew {
245
255
  getElementName(element) {
246
256
  return getElementName(this.selectorConfig, element);
247
257
  }
258
+ }
259
+ function labelStackFromFiber(fiber) {
260
+ var _fiber$child, _fiber$child$memoized;
261
+ const value = fiber === null || fiber === void 0 ? void 0 : (_fiber$child = fiber.child) === null || _fiber$child === void 0 ? void 0 : (_fiber$child$memoized = _fiber$child.memoizedProps) === null || _fiber$child$memoized === void 0 ? void 0 : _fiber$child$memoized.value;
262
+ return Array.isArray(value === null || value === void 0 ? void 0 : value.labelStack) ? value.labelStack : [];
263
+ }
264
+ function labelStackToString(labelStack) {
265
+ return labelStack.map(label => label.name).join('/');
266
+ }
267
+ function labelStackToSegment(labelStack) {
268
+ let segmentIndex = -1;
269
+ for (let i = labelStack.length - 1; i >= 0; i--) {
270
+ if (labelStack[i].segmentId) {
271
+ segmentIndex = i;
272
+ break;
273
+ }
274
+ }
275
+ return labelStack.slice(0, segmentIndex + 1).map(label => label.name).join('/');
276
+ }
277
+ function traverseFiber(fiber) {
278
+ let segment = 'unknown';
279
+ let labelStackString = 'unknown';
280
+ let currentFiber = fiber;
281
+ while (currentFiber) {
282
+ if (currentFiber.type) {
283
+ const componentName = currentFiber.type.displayName || currentFiber.type.name;
284
+ if (componentName === 'UFOSegment' || componentName === 'UFOLabel') {
285
+ const labelStack = labelStackFromFiber(currentFiber);
286
+ labelStackString = labelStackToString(labelStack) || 'unknown';
287
+ segment = labelStackToSegment(labelStack) || 'unknown';
288
+ break;
289
+ }
290
+ }
291
+ currentFiber = currentFiber.return;
292
+ }
293
+ return {
294
+ segment,
295
+ labelStack: labelStackString
296
+ };
297
+ }
298
+ function getLabelStacks(element) {
299
+ const reactFiberKey = Object.keys(element).find(key => key.startsWith('__reactFiber$'));
300
+ if (!reactFiberKey) {
301
+ return null;
302
+ }
303
+ const fiber = element[reactFiberKey];
304
+ return fiber ? traverseFiber(fiber) : null;
248
305
  }
@@ -1,4 +1,7 @@
1
1
  import { fg } from '@atlaskit/platform-feature-flags';
2
+ import getPageVisibilityUpToTTAI from '../../../create-payload/utils/get-page-visibility-up-to-ttai';
3
+ import { getInteractionId } from '../../../interaction-id-context';
4
+ import { interactions } from '../../../interaction-metrics/common/constants';
2
5
  import { cssIssueOccurrence } from '../viewport-observer/utils/track-display-content-occurrence';
3
6
  import { calculateTTVCPercentilesWithDebugInfo } from './percentile-calc';
4
7
  import getViewportHeight from './utils/get-viewport-height';
@@ -40,6 +43,18 @@ export default class AbstractVCCalculatorBase {
40
43
  }
41
44
  return ratios;
42
45
  }
46
+ getLabelStacks(filteredEntries) {
47
+ const labelStacks = {};
48
+ for (const entry of filteredEntries) {
49
+ if ('elementName' in entry.data && entry.data.labelStacks) {
50
+ labelStacks[entry.data.elementName] = {
51
+ segment: entry.data.labelStacks.segment,
52
+ labelStack: entry.data.labelStacks.labelStack
53
+ };
54
+ }
55
+ }
56
+ return labelStacks;
57
+ }
43
58
  async calculateWithDebugInfo(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason, allEntries, include3p) {
44
59
  var _window, _window2, _window3, _window5;
45
60
  const percentiles = [25, 50, 75, 80, 85, 90, 95, 98, 99];
@@ -199,13 +214,29 @@ export default class AbstractVCCalculatorBase {
199
214
  // Only create debug details if callbacks exist
200
215
  let v3RevisionDebugDetails = null;
201
216
  if (shouldCalculateDebugDetails) {
202
- v3RevisionDebugDetails = {
203
- revision: this.revisionNo,
204
- isClean: isVCClean,
205
- abortReason: dirtyReason,
206
- vcLogs: enhancedVcLogs,
207
- interactionId
208
- };
217
+ if (fg('platform_ufo_unify_abort_status_in_ttvc_debug_data')) {
218
+ var _activeInteractionId$;
219
+ // NOTE: using this instead of directly calling `getActiveInteraction()` to get around circular dependencies
220
+ const activeInteractionId = getInteractionId();
221
+ const activeInteraction = interactions.get((_activeInteractionId$ = activeInteractionId.current) !== null && _activeInteractionId$ !== void 0 ? _activeInteractionId$ : '');
222
+ const pageVisibilityUpToTTAI = activeInteraction ? getPageVisibilityUpToTTAI(activeInteraction) : null;
223
+ const isBackgrounded = pageVisibilityUpToTTAI !== 'visible';
224
+ v3RevisionDebugDetails = {
225
+ revision: this.revisionNo,
226
+ isClean: isVCClean && !(activeInteraction !== null && activeInteraction !== void 0 && activeInteraction.abortReason) && !isBackgrounded,
227
+ abortReason: isBackgrounded ? 'browser_backgrounded' : dirtyReason !== null && dirtyReason !== void 0 ? dirtyReason : activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.abortReason,
228
+ vcLogs: enhancedVcLogs,
229
+ interactionId
230
+ };
231
+ } else {
232
+ v3RevisionDebugDetails = {
233
+ revision: this.revisionNo,
234
+ isClean: isVCClean,
235
+ abortReason: dirtyReason,
236
+ vcLogs: enhancedVcLogs,
237
+ interactionId
238
+ };
239
+ }
209
240
  }
210
241
 
211
242
  // Handle devtool callback
@@ -275,6 +306,9 @@ export default class AbstractVCCalculatorBase {
275
306
  vcDetails: vcDetails !== null && vcDetails !== void 0 ? vcDetails : undefined
276
307
  };
277
308
  result.ratios = this.calculateRatios(filteredEntries);
309
+ if (isPostInteraction) {
310
+ result.labelStacks = this.getLabelStacks(filteredEntries);
311
+ }
278
312
  if (fg('platform_ufo_display_content_track_occurrence')) {
279
313
  result.displayContentsOccurrence = cssIssueOccurrence;
280
314
  }
@@ -1,7 +1,11 @@
1
1
  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; } } }; }
2
2
  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; } }
3
3
  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; }
4
- function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios) {
4
+ import { fg } from '@atlaskit/platform-feature-flags';
5
+ function getLateMutations(vcDetails) {
6
+ var labelStacks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7
+ var lastInteractionFinish = arguments.length > 2 ? arguments[2] : undefined;
8
+ var postInteractionFinishVCRatios = arguments.length > 3 ? arguments[3] : undefined;
5
9
  // Map to track which elements are already seen for each timestamp
6
10
  var seen = new Map();
7
11
  var result = [];
@@ -23,11 +27,19 @@ function getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinis
23
27
  continue;
24
28
  }
25
29
  seenElements.add(element);
26
- result.push({
30
+ var lateMutation = {
27
31
  time: details.t,
28
32
  element: element,
29
33
  viewportHeatmapPercentage: (postInteractionFinishVCRatios === null || postInteractionFinishVCRatios === void 0 ? void 0 : postInteractionFinishVCRatios[element]) || 0
30
- });
34
+ };
35
+ if (labelStacks && fg('platform_ufo_enable_late_mutation_label_stacks')) {
36
+ var labels = labelStacks[element];
37
+ if (labels) {
38
+ lateMutation.segment = labels.segment;
39
+ lateMutation.labelStack = labels.labelStack;
40
+ }
41
+ }
42
+ result.push(lateMutation);
31
43
  }
32
44
  } catch (err) {
33
45
  _iterator.e(err);
@@ -183,8 +183,9 @@ function createPostInteractionLogPayload(_ref2) {
183
183
  revisedVC90 = (_postInteractionFinis = postInteractionFinishRevision['metric:vc90']) !== null && _postInteractionFinis !== void 0 ? _postInteractionFinis : null;
184
184
  }
185
185
  var vcDetails = postInteractionFinishRevision.vcDetails;
186
+ var labelStacks = postInteractionFinishRevision.labelStacks;
186
187
  if (vcDetails) {
187
- lateMutations = getLateMutations(vcDetails, lastInteractionFinish, postInteractionFinishVCRatios);
188
+ lateMutations = getLateMutations(vcDetails, labelStacks, lastInteractionFinish, postInteractionFinishVCRatios);
188
189
  }
189
190
  }
190
191
  return {
@@ -5,6 +5,7 @@ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
5
5
  import _createClass from "@babel/runtime/helpers/createClass";
6
6
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
7
7
  import _regeneratorRuntime from "@babel/runtime/regenerator";
8
+ import { fg } from '@atlaskit/platform-feature-flags';
8
9
  import { SSRPlaceholderHandlers } from '../vc-observer/observers/ssr-placeholders';
9
10
  import EntriesTimeline from './entries-timeline';
10
11
  import _getElementName from './get-element-name';
@@ -68,18 +69,27 @@ var VCObserverNew = /*#__PURE__*/function () {
68
69
  if (element) {
69
70
  elementName = _this.getElementName(element);
70
71
  }
72
+ var data = {
73
+ type: type,
74
+ elementName: elementName,
75
+ rect: rect,
76
+ previousRect: previousRect,
77
+ visible: visible,
78
+ attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
79
+ oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
80
+ newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
81
+ };
82
+ if (element && _this.isPostInteraction && fg('platform_ufo_enable_late_mutation_label_stacks')) {
83
+ var labelStacks = getLabelStacks(element);
84
+ if (labelStacks) {
85
+ Object.assign(data, {
86
+ labelStacks: labelStacks
87
+ });
88
+ }
89
+ }
71
90
  _this.entriesTimeline.push({
72
91
  time: time,
73
- data: {
74
- type: type,
75
- elementName: elementName,
76
- rect: rect,
77
- previousRect: previousRect,
78
- visible: visible,
79
- attributeName: mutationData === null || mutationData === void 0 ? void 0 : mutationData.attributeName,
80
- oldValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.oldValue,
81
- newValue: mutationData === null || mutationData === void 0 ? void 0 : mutationData.newValue
82
- }
92
+ data: data
83
93
  });
84
94
  },
85
95
  // Pass SSR context to ViewportObserver
@@ -302,4 +312,57 @@ var VCObserverNew = /*#__PURE__*/function () {
302
312
  }
303
313
  }]);
304
314
  }();
305
- export { VCObserverNew as default };
315
+ export { VCObserverNew as default };
316
+ function labelStackFromFiber(fiber) {
317
+ var _fiber$child;
318
+ var value = fiber === null || fiber === void 0 || (_fiber$child = fiber.child) === null || _fiber$child === void 0 || (_fiber$child = _fiber$child.memoizedProps) === null || _fiber$child === void 0 ? void 0 : _fiber$child.value;
319
+ return Array.isArray(value === null || value === void 0 ? void 0 : value.labelStack) ? value.labelStack : [];
320
+ }
321
+ function labelStackToString(labelStack) {
322
+ return labelStack.map(function (label) {
323
+ return label.name;
324
+ }).join('/');
325
+ }
326
+ function labelStackToSegment(labelStack) {
327
+ var segmentIndex = -1;
328
+ for (var i = labelStack.length - 1; i >= 0; i--) {
329
+ if (labelStack[i].segmentId) {
330
+ segmentIndex = i;
331
+ break;
332
+ }
333
+ }
334
+ return labelStack.slice(0, segmentIndex + 1).map(function (label) {
335
+ return label.name;
336
+ }).join('/');
337
+ }
338
+ function traverseFiber(fiber) {
339
+ var segment = 'unknown';
340
+ var labelStackString = 'unknown';
341
+ var currentFiber = fiber;
342
+ while (currentFiber) {
343
+ if (currentFiber.type) {
344
+ var componentName = currentFiber.type.displayName || currentFiber.type.name;
345
+ if (componentName === 'UFOSegment' || componentName === 'UFOLabel') {
346
+ var labelStack = labelStackFromFiber(currentFiber);
347
+ labelStackString = labelStackToString(labelStack) || 'unknown';
348
+ segment = labelStackToSegment(labelStack) || 'unknown';
349
+ break;
350
+ }
351
+ }
352
+ currentFiber = currentFiber.return;
353
+ }
354
+ return {
355
+ segment: segment,
356
+ labelStack: labelStackString
357
+ };
358
+ }
359
+ function getLabelStacks(element) {
360
+ var reactFiberKey = Object.keys(element).find(function (key) {
361
+ return key.startsWith('__reactFiber$');
362
+ });
363
+ if (!reactFiberKey) {
364
+ return null;
365
+ }
366
+ var fiber = element[reactFiberKey];
367
+ return fiber ? traverseFiber(fiber) : null;
368
+ }
@@ -11,6 +11,9 @@ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol
11
11
  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; } }
12
12
  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; }
13
13
  import { fg } from '@atlaskit/platform-feature-flags';
14
+ import getPageVisibilityUpToTTAI from '../../../create-payload/utils/get-page-visibility-up-to-ttai';
15
+ import { getInteractionId } from '../../../interaction-id-context';
16
+ import { interactions } from '../../../interaction-metrics/common/constants';
14
17
  import { cssIssueOccurrence } from '../viewport-observer/utils/track-display-content-occurrence';
15
18
  import { calculateTTVCPercentilesWithDebugInfo } from './percentile-calc';
16
19
  import getViewportHeight from './utils/get-viewport-height';
@@ -76,12 +79,35 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
76
79
  }
77
80
  return ratios;
78
81
  }
82
+ }, {
83
+ key: "getLabelStacks",
84
+ value: function getLabelStacks(filteredEntries) {
85
+ var labelStacks = {};
86
+ var _iterator3 = _createForOfIteratorHelper(filteredEntries),
87
+ _step3;
88
+ try {
89
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
90
+ var _entry2 = _step3.value;
91
+ if ('elementName' in _entry2.data && _entry2.data.labelStacks) {
92
+ labelStacks[_entry2.data.elementName] = {
93
+ segment: _entry2.data.labelStacks.segment,
94
+ labelStack: _entry2.data.labelStacks.labelStack
95
+ };
96
+ }
97
+ }
98
+ } catch (err) {
99
+ _iterator3.e(err);
100
+ } finally {
101
+ _iterator3.f();
102
+ }
103
+ return labelStacks;
104
+ }
79
105
  }, {
80
106
  key: "calculateWithDebugInfo",
81
107
  value: function () {
82
108
  var _calculateWithDebugInfo = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(filteredEntries, startTime, stopTime, isPostInteraction, isVCClean, interactionId, dirtyReason, allEntries, include3p) {
83
109
  var _window, _window2, _window3, _window5;
84
- var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _iterator3, _step3, _entry2, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculate3p, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator4, _step4, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator5, _step5, _entry3, _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou, viewportData, timestamp, additionalVcLogs, _iterator6, _step6, _step6$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _window4, _window4$__ufo_devtoo, _window6, _window6$__on_ufo_vc_;
110
+ var percentiles, viewportEntries, vcLogs, vcDetails, percentileIndex, entryDataBuffer, _iterator4, _step4, _entry3, time, viewportPercentage, entries, elementNames, previousResult, i, percentile, enhancedVcLogs, shouldCalculate3p, shouldCalculateDebugDetails, sortedVcLogs, maxViewportPercentageAtTime, maxSoFar, _iterator5, _step5, log, getBiggestPreviousViewportPercentage, ignoredEntriesByTime, _iterator6, _step6, _entry4, _ignoredEntriesByTime, _viewportData$rect, _viewportData$previou, viewportData, timestamp, additionalVcLogs, _iterator7, _step7, _step7$value, _timestamp, ignoredEntries, _viewportPercentage, v3RevisionDebugDetails, _activeInteractionId$, activeInteractionId, activeInteraction, pageVisibilityUpToTTAI, isBackgrounded, _window4, _window4$__ufo_devtoo, _window6, _window6$__on_ufo_vc_;
85
111
  return _regeneratorRuntime.wrap(function _callee$(_context) {
86
112
  while (1) switch (_context.prev = _context.next) {
87
113
  case 0:
@@ -109,16 +135,16 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
109
135
  _context.next = 29;
110
136
  break;
111
137
  }
112
- _iterator3 = _createForOfIteratorHelper(vcLogs);
138
+ _iterator4 = _createForOfIteratorHelper(vcLogs);
113
139
  _context.prev = 11;
114
- _iterator3.s();
140
+ _iterator4.s();
115
141
  case 13:
116
- if ((_step3 = _iterator3.n()).done) {
142
+ if ((_step4 = _iterator4.n()).done) {
117
143
  _context.next = 21;
118
144
  break;
119
145
  }
120
- _entry2 = _step3.value;
121
- time = _entry2.time, viewportPercentage = _entry2.viewportPercentage, entries = _entry2.entries; // Only process entries if we haven't reached all percentiles
146
+ _entry3 = _step4.value;
147
+ time = _entry3.time, viewportPercentage = _entry3.viewportPercentage, entries = _entry3.entries; // Only process entries if we haven't reached all percentiles
122
148
  if (!(percentileIndex >= percentiles.length)) {
123
149
  _context.next = 18;
124
150
  break;
@@ -155,10 +181,10 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
155
181
  case 23:
156
182
  _context.prev = 23;
157
183
  _context.t0 = _context["catch"](11);
158
- _iterator3.e(_context.t0);
184
+ _iterator4.e(_context.t0);
159
185
  case 26:
160
186
  _context.prev = 26;
161
- _iterator3.f();
187
+ _iterator4.f();
162
188
  return _context.finish(26);
163
189
  case 29:
164
190
  // Fill in any missing percentiles with the last known values
@@ -196,10 +222,10 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
196
222
  }); // Pre-calculate max viewport percentage up to each time for efficient lookups
197
223
  maxViewportPercentageAtTime = new Map();
198
224
  maxSoFar = 0;
199
- _iterator4 = _createForOfIteratorHelper(sortedVcLogs);
225
+ _iterator5 = _createForOfIteratorHelper(sortedVcLogs);
200
226
  try {
201
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
202
- log = _step4.value;
227
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
228
+ log = _step5.value;
203
229
  if (log.viewportPercentage !== null) {
204
230
  maxSoFar = Math.max(maxSoFar, log.viewportPercentage);
205
231
  maxViewportPercentageAtTime.set(log.time, maxSoFar);
@@ -208,9 +234,9 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
208
234
 
209
235
  // Helper function to find the biggest previous viewport percentage
210
236
  } catch (err) {
211
- _iterator4.e(err);
237
+ _iterator5.e(err);
212
238
  } finally {
213
- _iterator4.f();
239
+ _iterator5.f();
214
240
  }
215
241
  getBiggestPreviousViewportPercentage = function getBiggestPreviousViewportPercentage(targetTime) {
216
242
  // Binary search for the largest time <= targetTime
@@ -229,13 +255,13 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
229
255
  return result >= 0 ? maxViewportPercentageAtTime.get(sortedVcLogs[result].time) || null : null;
230
256
  }; // Group ignored entries by timestamp
231
257
  ignoredEntriesByTime = new Map();
232
- _iterator5 = _createForOfIteratorHelper(allEntries);
258
+ _iterator6 = _createForOfIteratorHelper(allEntries);
233
259
  try {
234
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
235
- _entry3 = _step5.value;
236
- if ('rect' in _entry3.data && !this.isEntryIncluded(_entry3, include3p)) {
237
- viewportData = _entry3.data;
238
- timestamp = Math.round(_entry3.time);
260
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
261
+ _entry4 = _step6.value;
262
+ if ('rect' in _entry4.data && !this.isEntryIncluded(_entry4, include3p)) {
263
+ viewportData = _entry4.data;
264
+ timestamp = Math.round(_entry4.time);
239
265
  if (!ignoredEntriesByTime.has(timestamp)) {
240
266
  ignoredEntriesByTime.set(timestamp, []);
241
267
  }
@@ -250,15 +276,15 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
250
276
 
251
277
  // Add ignored entries to vcLogs
252
278
  } catch (err) {
253
- _iterator5.e(err);
279
+ _iterator6.e(err);
254
280
  } finally {
255
- _iterator5.f();
281
+ _iterator6.f();
256
282
  }
257
283
  additionalVcLogs = [];
258
- _iterator6 = _createForOfIteratorHelper(ignoredEntriesByTime);
284
+ _iterator7 = _createForOfIteratorHelper(ignoredEntriesByTime);
259
285
  try {
260
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
261
- _step6$value = _slicedToArray(_step6.value, 2), _timestamp = _step6$value[0], ignoredEntries = _step6$value[1];
286
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
287
+ _step7$value = _slicedToArray(_step7.value, 2), _timestamp = _step7$value[0], ignoredEntries = _step7$value[1];
262
288
  if (ignoredEntries.length > 0) {
263
289
  _viewportPercentage = getBiggestPreviousViewportPercentage(_timestamp);
264
290
  additionalVcLogs.push({
@@ -271,9 +297,9 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
271
297
 
272
298
  // Combine and sort all vcLogs
273
299
  } catch (err) {
274
- _iterator6.e(err);
300
+ _iterator7.e(err);
275
301
  } finally {
276
- _iterator6.f();
302
+ _iterator7.f();
277
303
  }
278
304
  enhancedVcLogs = [].concat(_toConsumableArray(enhancedVcLogs), additionalVcLogs).sort(function (a, b) {
279
305
  return a.time - b.time;
@@ -283,13 +309,28 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
283
309
  // Only create debug details if callbacks exist
284
310
  v3RevisionDebugDetails = null;
285
311
  if (shouldCalculateDebugDetails) {
286
- v3RevisionDebugDetails = {
287
- revision: this.revisionNo,
288
- isClean: isVCClean,
289
- abortReason: dirtyReason,
290
- vcLogs: enhancedVcLogs,
291
- interactionId: interactionId
292
- };
312
+ if (fg('platform_ufo_unify_abort_status_in_ttvc_debug_data')) {
313
+ // NOTE: using this instead of directly calling `getActiveInteraction()` to get around circular dependencies
314
+ activeInteractionId = getInteractionId();
315
+ activeInteraction = interactions.get((_activeInteractionId$ = activeInteractionId.current) !== null && _activeInteractionId$ !== void 0 ? _activeInteractionId$ : '');
316
+ pageVisibilityUpToTTAI = activeInteraction ? getPageVisibilityUpToTTAI(activeInteraction) : null;
317
+ isBackgrounded = pageVisibilityUpToTTAI !== 'visible';
318
+ v3RevisionDebugDetails = {
319
+ revision: this.revisionNo,
320
+ isClean: isVCClean && !(activeInteraction !== null && activeInteraction !== void 0 && activeInteraction.abortReason) && !isBackgrounded,
321
+ abortReason: isBackgrounded ? 'browser_backgrounded' : dirtyReason !== null && dirtyReason !== void 0 ? dirtyReason : activeInteraction === null || activeInteraction === void 0 ? void 0 : activeInteraction.abortReason,
322
+ vcLogs: enhancedVcLogs,
323
+ interactionId: interactionId
324
+ };
325
+ } else {
326
+ v3RevisionDebugDetails = {
327
+ revision: this.revisionNo,
328
+ isClean: isVCClean,
329
+ abortReason: dirtyReason,
330
+ vcLogs: enhancedVcLogs,
331
+ interactionId: interactionId
332
+ };
333
+ }
293
334
  }
294
335
 
295
336
  // Handle devtool callback
@@ -373,11 +414,14 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
373
414
  vcDetails: vcDetails !== null && vcDetails !== void 0 ? vcDetails : undefined
374
415
  };
375
416
  result.ratios = this.calculateRatios(filteredEntries);
417
+ if (isPostInteraction) {
418
+ result.labelStacks = this.getLabelStacks(filteredEntries);
419
+ }
376
420
  if (fg('platform_ufo_display_content_track_occurrence')) {
377
421
  result.displayContentsOccurrence = cssIssueOccurrence;
378
422
  }
379
423
  return _context2.abrupt("return", result);
380
- case 14:
424
+ case 15:
381
425
  case "end":
382
426
  return _context2.stop();
383
427
  }
@@ -201,6 +201,8 @@ export type LateMutation = {
201
201
  time: number;
202
202
  element: string;
203
203
  viewportHeatmapPercentage: number;
204
+ segment?: string;
205
+ labelStack?: string;
204
206
  };
205
207
  export type PostInteractionLogPayload = {
206
208
  actionSubject: 'experience';
@@ -14,6 +14,12 @@ export type VCAbortReasonType = {
14
14
  export type VCRatioType = {
15
15
  [elementName: string]: number;
16
16
  };
17
+ export type VCLabelStacks = {
18
+ [elementName: string]: {
19
+ segment: string;
20
+ labelStack: string;
21
+ };
22
+ };
17
23
  export type VCRawDataType = {
18
24
  abortReasonInfo: string | null;
19
25
  abortReason: VCAbortReasonType;
@@ -114,6 +120,7 @@ export type RevisionPayloadEntry = {
114
120
  clean: boolean;
115
121
  vcDetails?: RevisionPayloadVCDetails;
116
122
  ratios?: VCRatioType;
123
+ labelStacks?: VCLabelStacks;
117
124
  abortReason?: VCAbortReason | null;
118
125
  abortTimestamp?: number;
119
126
  displayContentsOccurrence?: number;
@@ -1,5 +1,5 @@
1
1
  import type { LastInteractionFinishInfo } from '../common';
2
2
  import type { LateMutation } from '../common/react-ufo-payload-schema';
3
- import type { RevisionPayloadVCDetails } from '../common/vc/types';
4
- declare function getLateMutations(vcDetails: RevisionPayloadVCDetails, lastInteractionFinish: LastInteractionFinishInfo, postInteractionFinishVCRatios?: Record<string, number>): LateMutation[];
3
+ import type { RevisionPayloadVCDetails, VCLabelStacks } from '../common/vc/types';
4
+ declare function getLateMutations(vcDetails: RevisionPayloadVCDetails, labelStacks: VCLabelStacks | undefined, lastInteractionFinish: LastInteractionFinishInfo, postInteractionFinishVCRatios?: Record<string, number>): LateMutation[];
5
5
  export default getLateMutations;
@@ -17,7 +17,7 @@ export type VCLogEntry = {
17
17
  export interface VCRevisionDebugDetails {
18
18
  revision: string;
19
19
  isClean: boolean;
20
- abortReason?: VCAbortReason | null;
20
+ abortReason?: string | null;
21
21
  abortTimestamp?: number;
22
22
  vcLogs: VCLogEntry[];
23
23
  interactionId?: string;
@@ -23,6 +23,7 @@ export default abstract class AbstractVCCalculatorBase implements VCCalculator {
23
23
  * Calculate ratios for each element based on their viewport coverage.
24
24
  */
25
25
  private calculateRatios;
26
+ private getLabelStacks;
26
27
  private calculateWithDebugInfo;
27
28
  calculate({ startTime, stopTime, orderedEntries, interactionId, isPostInteraction, include3p, }: VCCalculatorParam): Promise<RevisionPayloadEntry | undefined>;
28
29
  }
@@ -9,6 +9,11 @@ export type ViewportEntryData = {
9
9
  readonly attributeName?: string | null | undefined;
10
10
  readonly oldValue?: string | null | undefined;
11
11
  readonly newValue?: string | null | undefined;
12
+ readonly labelStacks?: VCObserverLabelStacks;
13
+ };
14
+ export type VCObserverLabelStacks = {
15
+ segment: string;
16
+ labelStack: string;
12
17
  };
13
18
  export type WindowEventEntryData = {
14
19
  readonly type: VCObserverEntryType;
@@ -203,6 +203,8 @@ export type LateMutation = {
203
203
  time: number;
204
204
  element: string;
205
205
  viewportHeatmapPercentage: number;
206
+ segment?: string;
207
+ labelStack?: string;
206
208
  };
207
209
  export type PostInteractionLogPayload = {
208
210
  actionSubject: 'experience';
@@ -14,6 +14,12 @@ export type VCAbortReasonType = {
14
14
  export type VCRatioType = {
15
15
  [elementName: string]: number;
16
16
  };
17
+ export type VCLabelStacks = {
18
+ [elementName: string]: {
19
+ segment: string;
20
+ labelStack: string;
21
+ };
22
+ };
17
23
  export type VCRawDataType = {
18
24
  abortReasonInfo: string | null;
19
25
  abortReason: VCAbortReasonType;
@@ -114,6 +120,7 @@ export type RevisionPayloadEntry = {
114
120
  clean: boolean;
115
121
  vcDetails?: RevisionPayloadVCDetails;
116
122
  ratios?: VCRatioType;
123
+ labelStacks?: VCLabelStacks;
117
124
  abortReason?: VCAbortReason | null;
118
125
  abortTimestamp?: number;
119
126
  displayContentsOccurrence?: number;
@@ -1,5 +1,5 @@
1
1
  import type { LastInteractionFinishInfo } from '../common';
2
2
  import type { LateMutation } from '../common/react-ufo-payload-schema';
3
- import type { RevisionPayloadVCDetails } from '../common/vc/types';
4
- declare function getLateMutations(vcDetails: RevisionPayloadVCDetails, lastInteractionFinish: LastInteractionFinishInfo, postInteractionFinishVCRatios?: Record<string, number>): LateMutation[];
3
+ import type { RevisionPayloadVCDetails, VCLabelStacks } from '../common/vc/types';
4
+ declare function getLateMutations(vcDetails: RevisionPayloadVCDetails, labelStacks: VCLabelStacks | undefined, lastInteractionFinish: LastInteractionFinishInfo, postInteractionFinishVCRatios?: Record<string, number>): LateMutation[];
5
5
  export default getLateMutations;
@@ -17,7 +17,7 @@ export type VCLogEntry = {
17
17
  export interface VCRevisionDebugDetails {
18
18
  revision: string;
19
19
  isClean: boolean;
20
- abortReason?: VCAbortReason | null;
20
+ abortReason?: string | null;
21
21
  abortTimestamp?: number;
22
22
  vcLogs: VCLogEntry[];
23
23
  interactionId?: string;
@@ -23,6 +23,7 @@ export default abstract class AbstractVCCalculatorBase implements VCCalculator {
23
23
  * Calculate ratios for each element based on their viewport coverage.
24
24
  */
25
25
  private calculateRatios;
26
+ private getLabelStacks;
26
27
  private calculateWithDebugInfo;
27
28
  calculate({ startTime, stopTime, orderedEntries, interactionId, isPostInteraction, include3p, }: VCCalculatorParam): Promise<RevisionPayloadEntry | undefined>;
28
29
  }
@@ -9,6 +9,11 @@ export type ViewportEntryData = {
9
9
  readonly attributeName?: string | null | undefined;
10
10
  readonly oldValue?: string | null | undefined;
11
11
  readonly newValue?: string | null | undefined;
12
+ readonly labelStacks?: VCObserverLabelStacks;
13
+ };
14
+ export type VCObserverLabelStacks = {
15
+ segment: string;
16
+ labelStack: string;
12
17
  };
13
18
  export type WindowEventEntryData = {
14
19
  readonly type: VCObserverEntryType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/react-ufo",
3
- "version": "4.6.0",
3
+ "version": "4.6.1",
4
4
  "description": "Parts of React UFO that are publicly available",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -120,6 +120,9 @@
120
120
  "platform_ufo_enable_interactivity_jsm": {
121
121
  "type": "boolean"
122
122
  },
123
+ "platform_ufo_unify_abort_status_in_ttvc_debug_data": {
124
+ "type": "boolean"
125
+ },
123
126
  "platform_ufo_exclude_3p_elements_from_ttai": {
124
127
  "type": "boolean"
125
128
  },
@@ -155,6 +158,9 @@
155
158
  },
156
159
  "platform_ufo_display_content_track_occurrence": {
157
160
  "type": "boolean"
161
+ },
162
+ "platform_ufo_enable_late_mutation_label_stacks": {
163
+ "type": "boolean"
158
164
  }
159
165
  }
160
166
  }