@atlaskit/react-ufo 3.13.26 → 3.13.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @atlaskit/ufo-interaction-ignore
2
2
 
3
+ ## 3.13.28
4
+
5
+ ### Patch Changes
6
+
7
+ - [#173121](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/173121)
8
+ [`0d5a766d0f501`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0d5a766d0f501) -
9
+ Track unknown interactions elements
10
+
11
+ ## 3.13.27
12
+
13
+ ### Patch Changes
14
+
15
+ - [#175316](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/175316)
16
+ [`a2a93696df1b8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a2a93696df1b8) -
17
+ Add extra non-visual attributes to UFO ignore list
18
+ - [#173438](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/173438)
19
+ [`03117ec2ea74c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/03117ec2ea74c) -
20
+ Update README
21
+
3
22
  ## 3.13.26
4
23
 
5
24
  ### Patch Changes
package/README.md CHANGED
@@ -10,7 +10,7 @@ Parts of React UFO that need to be scoped within @atlaskit
10
10
 
11
11
  In one terminal:
12
12
 
13
- ```
13
+ ```shell
14
14
  cd platform && nvm use && yarn
15
15
  yarn start:rspack react-ufo
16
16
  ```
@@ -19,7 +19,7 @@ This will start the dev server, accessible via http://localhost:9000.
19
19
 
20
20
  Then in a separate terminal:
21
21
 
22
- ```
22
+ ```shell
23
23
  cd platform && nvm use
24
24
  yarn test:integration packages/react-ufo/atlaskit/__tests__/ --retries 0 --reporter list --reuse-dev-server --project=desktop-chromium --max-failures=0
25
25
  ```
@@ -35,6 +35,6 @@ increase the following:
35
35
 
36
36
  Example:
37
37
 
38
- ```
38
+ ```shell
39
39
  yarn test:integration packages/react-ufo/atlaskit/__tests__/playwright/base.spec.ts --retries 0 --reporter list --reuse-dev-server --project=desktop-chromium --max-failures=0 --repeat-each 50 --workers 50
40
40
  ```
@@ -709,7 +709,7 @@ function createInteractionMetricsPayload(_x3, _x4, _x5) {
709
709
  function _createInteractionMetricsPayload() {
710
710
  _createInteractionMetricsPayload = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(interaction, interactionId, experimental) {
711
711
  var _window$location, _config$additionalPay;
712
- var interactionPayloadStart, config, end, start, ufoName, knownSegments, rate, type, abortReason, routeName, featureFlags, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, responsiveness, pageVisibilityAtTTI, pageVisibilityAtTTAI, segments, segmentTree, isDetailedPayload, isPageLoad, calculatePageVisibilityFromTheStartOfPageLoad, moreAccuratePageVisibilityAtTTI, moreAccuratePageVisibilityAtTTAI, labelStack, getInitialPageLoadSSRMetrics, pageLoadInteractionMetrics, getDetailedInteractionMetrics, getPageLoadDetailedInteractionMetrics, newUFOName, resourceTimings, _yield$Promise$all, _yield$Promise$all2, vcMetrics, experimentalMetrics, paintMetrics, payload;
712
+ var interactionPayloadStart, config, end, start, ufoName, knownSegments, rate, type, abortReason, routeName, featureFlags, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, responsiveness, unknownElementName, unknownElementHierarchy, pageVisibilityAtTTI, pageVisibilityAtTTAI, segments, segmentTree, isDetailedPayload, isPageLoad, calculatePageVisibilityFromTheStartOfPageLoad, moreAccuratePageVisibilityAtTTI, moreAccuratePageVisibilityAtTTAI, labelStack, getInitialPageLoadSSRMetrics, pageLoadInteractionMetrics, getDetailedInteractionMetrics, getPageLoadDetailedInteractionMetrics, newUFOName, resourceTimings, _yield$Promise$all, _yield$Promise$all2, vcMetrics, experimentalMetrics, paintMetrics, payload;
713
713
  return _regenerator.default.wrap(function _callee2$(_context2) {
714
714
  while (1) switch (_context2.prev = _context2.next) {
715
715
  case 0:
@@ -721,7 +721,7 @@ function _createInteractionMetricsPayload() {
721
721
  }
722
722
  throw Error('UFO Configuration not provided');
723
723
  case 4:
724
- end = interaction.end, start = interaction.start, ufoName = interaction.ufoName, knownSegments = interaction.knownSegments, rate = interaction.rate, type = interaction.type, abortReason = interaction.abortReason, routeName = interaction.routeName, featureFlags = interaction.featureFlags, previousInteractionName = interaction.previousInteractionName, isPreviousInteractionAborted = interaction.isPreviousInteractionAborted, abortedByInteractionName = interaction.abortedByInteractionName, responsiveness = interaction.responsiveness;
724
+ end = interaction.end, start = interaction.start, ufoName = interaction.ufoName, knownSegments = interaction.knownSegments, rate = interaction.rate, type = interaction.type, abortReason = interaction.abortReason, routeName = interaction.routeName, featureFlags = interaction.featureFlags, previousInteractionName = interaction.previousInteractionName, isPreviousInteractionAborted = interaction.isPreviousInteractionAborted, abortedByInteractionName = interaction.abortedByInteractionName, responsiveness = interaction.responsiveness, unknownElementName = interaction.unknownElementName, unknownElementHierarchy = interaction.unknownElementHierarchy;
725
725
  pageVisibilityAtTTI = getPageVisibilityUpToTTI(interaction);
726
726
  pageVisibilityAtTTAI = (0, _getPageVisibilityUpToTtai.default)(interaction);
727
727
  segments = config.killswitchNestedSegments ? [] : knownSegments;
@@ -825,7 +825,7 @@ function _createInteractionMetricsPayload() {
825
825
  }, (0, _platformFeatureFlags.fg)('platform_ufo_report_cpu_usage') ? {
826
826
  'event:cpu:usage': (0, _machineUtilisation.createPressureStateReport)(interaction.start, interaction.end)
827
827
  } : {}), getBrowserMetadata()), getSSRProperties(type)), getAssetsMetrics(interaction, pageLoadInteractionMetrics === null || pageLoadInteractionMetrics === void 0 ? void 0 : pageLoadInteractionMetrics.SSRDoneTime)), getPPSMetrics(interaction)), paintMetrics), getNavigationMetrics(type)), vcMetrics), experimentalMetrics), (_config$additionalPay = config.additionalPayloadData) === null || _config$additionalPay === void 0 ? void 0 : _config$additionalPay.call(config, interaction)), getTracingContextData(interaction)), getStylesheetMetrics()), getErrorCounts(interaction)), {}, {
828
- interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
828
+ interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
829
829
  namePrefix: config.namePrefix || '',
830
830
  segmentPrefix: config.segmentPrefix || '',
831
831
  interactionId: interactionId,
@@ -861,7 +861,11 @@ function _createInteractionMetricsPayload() {
861
861
  } : {}), labelStack), pageLoadInteractionMetrics), getDetailedInteractionMetrics(resourceTimings)), getPageLoadDetailedInteractionMetrics()), getBm3TrackerTimings(interaction)), {}, {
862
862
  'metric:ttai': experimental ? regularTTAI || expTTAI : undefined,
863
863
  'metric:experimental:ttai': expTTAI
864
- }),
864
+ }, unknownElementName ? {
865
+ unknownElementName: unknownElementName
866
+ } : {}), unknownElementHierarchy ? {
867
+ unknownElementHierarchy: unknownElementHierarchy
868
+ } : {}),
865
869
  'ufo:payloadTime': (0, _roundNumber.roundEpsilon)(performance.now() - interactionPayloadStart)
866
870
  })
867
871
  }
@@ -6,13 +6,67 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.setInteractionPerformanceEvent = exports.getPerformanceObserver = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
9
10
  var _interactionMetrics = require("../interaction-metrics");
11
+ var _getUniqueElementName = _interopRequireDefault(require("../vc/vc-observer-new/get-unique-element-name"));
10
12
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
11
13
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
12
14
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
13
15
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
14
16
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
15
17
  var performanceEventObserver;
18
+ var selectorConfig = {
19
+ id: true,
20
+ testId: true,
21
+ role: true,
22
+ className: true
23
+ };
24
+ function getTestIdName(memoizedProps) {
25
+ if (memoizedProps['data-testid']) {
26
+ return "[data-testid=".concat(memoizedProps['data-testid'], "]");
27
+ } else if (memoizedProps['data-test-id']) {
28
+ return "[data-test-id=".concat(memoizedProps['data-testid'], "]");
29
+ }
30
+ return null;
31
+ }
32
+ function getReactComponentHierarchy(element) {
33
+ var componentHierarchy = [];
34
+ // Function to traverse up the fiber tree
35
+ function traverseFiber(fiber) {
36
+ var currentFiber = fiber;
37
+ while (currentFiber) {
38
+ if (currentFiber.type) {
39
+ // Check if there's a display name or a function name
40
+ var componentName = currentFiber.type.displayName || currentFiber.type.name;
41
+ // checking when component name is bigger than the minimized name produced by react
42
+ if (componentName && componentName.length > 2 && !componentName.includes('Listener') && !componentName.includes('Provider')) {
43
+ componentHierarchy.push(componentName);
44
+ }
45
+ if (componentName === 'UFOSegment') {
46
+ break;
47
+ }
48
+ }
49
+ if (currentFiber.memoizedProps) {
50
+ var dataIdInfo = getTestIdName(currentFiber.memoizedProps);
51
+ if (dataIdInfo) {
52
+ componentHierarchy.push(dataIdInfo);
53
+ currentFiber = null;
54
+ continue;
55
+ }
56
+ }
57
+ currentFiber = currentFiber.return;
58
+ }
59
+ }
60
+ // Access the reactFiber node from the HTML element
61
+ var reactFiberKey = Object.keys(element).find(function (key) {
62
+ return key.startsWith('__reactFiber$');
63
+ });
64
+ if (reactFiberKey) {
65
+ var fiber = element[reactFiberKey];
66
+ traverseFiber(fiber);
67
+ }
68
+ return componentHierarchy.reverse().join(' > ');
69
+ }
16
70
  var getPerformanceObserver = exports.getPerformanceObserver = function getPerformanceObserver() {
17
71
  performanceEventObserver = performanceEventObserver || new PerformanceObserver(function (entries) {
18
72
  var list = entries.getEntries();
@@ -47,5 +101,12 @@ var setInteractionPerformanceEvent = exports.setInteractionPerformanceEvent = fu
47
101
  // it means the interaction start time is not accurate, we assign
48
102
  // this value which will match the timestamp in the event
49
103
  interaction.start = Math.min(interaction.start, entry.startTime);
104
+ if (interaction.ufoName === 'unknown' && (0, _platformFeatureFlags.fg)('platform_ufo_enable_unknown_interactions_elements')) {
105
+ if (entry.target) {
106
+ var componentHierarchy = getReactComponentHierarchy(entry.target);
107
+ interaction.unknownElementHierarchy = componentHierarchy;
108
+ }
109
+ interaction.unknownElementName = (0, _getUniqueElementName.default)(selectorConfig, entry.target);
110
+ }
50
111
  }
51
112
  };
@@ -25,7 +25,7 @@ var CONSIDERED_ENTRY_TYPE = ['mutation:child-element', 'mutation:element', 'muta
25
25
  var KNOWN_ATTRIBUTES_THAT_DOES_NOT_CAUSE_LAYOUT_SHIFTS = exports.KNOWN_ATTRIBUTES_THAT_DOES_NOT_CAUSE_LAYOUT_SHIFTS = ['data-drop-target-for-element', 'draggable'];
26
26
 
27
27
  // Common aria attributes that don't cause visual layout shifts
28
- var NON_VISUAL_ARIA_ATTRIBUTES = exports.NON_VISUAL_ARIA_ATTRIBUTES = ['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-selected', 'aria-checked', 'aria-disabled', 'aria-required', 'aria-current', 'aria-haspopup', 'aria-pressed', 'aria-live'];
28
+ var NON_VISUAL_ARIA_ATTRIBUTES = exports.NON_VISUAL_ARIA_ATTRIBUTES = ['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-selected', 'aria-checked', 'aria-disabled', 'aria-required', 'aria-current', 'aria-haspopup', 'aria-pressed', 'aria-atomic', 'aria-live'];
29
29
  var VCCalculator_FY25_03 = exports.default = /*#__PURE__*/function (_AbstractVCCalculator) {
30
30
  function VCCalculator_FY25_03() {
31
31
  (0, _classCallCheck2.default)(this, VCCalculator_FY25_03);
@@ -47,7 +47,7 @@ var VCCalculator_FY25_03 = exports.default = /*#__PURE__*/function (_AbstractVCC
47
47
  if (attributeName === 'data-aui-version' && (0, _platformFeatureFlags.fg)('platform_ufo_filter_out_aui_attribute_changes')) {
48
48
  return false;
49
49
  }
50
- if (attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
50
+ if (attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || (attributeName === 'data-renderer-start-pos' || attributeName === 'data-table-local-id' || attributeName === 'spellcheck') && (0, _platformFeatureFlags.fg)('platform_ufo_ignore_extra_attributes') || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
51
51
  return false;
52
52
  }
53
53
  return true;
@@ -700,7 +700,9 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
700
700
  previousInteractionName,
701
701
  isPreviousInteractionAborted,
702
702
  abortedByInteractionName,
703
- responsiveness
703
+ responsiveness,
704
+ unknownElementName,
705
+ unknownElementHierarchy
704
706
  } = interaction;
705
707
  const pageVisibilityAtTTI = getPageVisibilityUpToTTI(interaction);
706
708
  const pageVisibilityAtTTAI = getPageVisibilityUpToTTAI(interaction);
@@ -854,7 +856,13 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
854
856
  ...getPageLoadDetailedInteractionMetrics(),
855
857
  ...getBm3TrackerTimings(interaction),
856
858
  'metric:ttai': experimental ? regularTTAI || expTTAI : undefined,
857
- 'metric:experimental:ttai': expTTAI
859
+ 'metric:experimental:ttai': expTTAI,
860
+ ...(unknownElementName ? {
861
+ unknownElementName
862
+ } : {}),
863
+ ...(unknownElementHierarchy ? {
864
+ unknownElementHierarchy
865
+ } : {})
858
866
  },
859
867
  'ufo:payloadTime': roundEpsilon(performance.now() - interactionPayloadStart)
860
868
  }
@@ -1,5 +1,57 @@
1
+ import { fg } from '@atlaskit/platform-feature-flags';
1
2
  import { getActiveInteraction } from '../interaction-metrics';
3
+ import getElementName from '../vc/vc-observer-new/get-unique-element-name';
2
4
  let performanceEventObserver;
5
+ const selectorConfig = {
6
+ id: true,
7
+ testId: true,
8
+ role: true,
9
+ className: true
10
+ };
11
+ function getTestIdName(memoizedProps) {
12
+ if (memoizedProps['data-testid']) {
13
+ return `[data-testid=${memoizedProps['data-testid']}]`;
14
+ } else if (memoizedProps['data-test-id']) {
15
+ return `[data-test-id=${memoizedProps['data-testid']}]`;
16
+ }
17
+ return null;
18
+ }
19
+ function getReactComponentHierarchy(element) {
20
+ const componentHierarchy = [];
21
+ // Function to traverse up the fiber tree
22
+ function traverseFiber(fiber) {
23
+ let currentFiber = fiber;
24
+ while (currentFiber) {
25
+ if (currentFiber.type) {
26
+ // Check if there's a display name or a function name
27
+ const componentName = currentFiber.type.displayName || currentFiber.type.name;
28
+ // checking when component name is bigger than the minimized name produced by react
29
+ if (componentName && componentName.length > 2 && !componentName.includes('Listener') && !componentName.includes('Provider')) {
30
+ componentHierarchy.push(componentName);
31
+ }
32
+ if (componentName === 'UFOSegment') {
33
+ break;
34
+ }
35
+ }
36
+ if (currentFiber.memoizedProps) {
37
+ const dataIdInfo = getTestIdName(currentFiber.memoizedProps);
38
+ if (dataIdInfo) {
39
+ componentHierarchy.push(dataIdInfo);
40
+ currentFiber = null;
41
+ continue;
42
+ }
43
+ }
44
+ currentFiber = currentFiber.return;
45
+ }
46
+ }
47
+ // Access the reactFiber node from the HTML element
48
+ const reactFiberKey = Object.keys(element).find(key => key.startsWith('__reactFiber$'));
49
+ if (reactFiberKey) {
50
+ const fiber = element[reactFiberKey];
51
+ traverseFiber(fiber);
52
+ }
53
+ return componentHierarchy.reverse().join(' > ');
54
+ }
3
55
  export const getPerformanceObserver = () => {
4
56
  performanceEventObserver = performanceEventObserver || new PerformanceObserver(entries => {
5
57
  const list = entries.getEntries();
@@ -26,5 +78,12 @@ export const setInteractionPerformanceEvent = entry => {
26
78
  // it means the interaction start time is not accurate, we assign
27
79
  // this value which will match the timestamp in the event
28
80
  interaction.start = Math.min(interaction.start, entry.startTime);
81
+ if (interaction.ufoName === 'unknown' && fg('platform_ufo_enable_unknown_interactions_elements')) {
82
+ if (entry.target) {
83
+ const componentHierarchy = getReactComponentHierarchy(entry.target);
84
+ interaction.unknownElementHierarchy = componentHierarchy;
85
+ }
86
+ interaction.unknownElementName = getElementName(selectorConfig, entry.target);
87
+ }
29
88
  }
30
89
  };
@@ -11,7 +11,7 @@ const CONSIDERED_ENTRY_TYPE = ['mutation:child-element', 'mutation:element', 'mu
11
11
  export const KNOWN_ATTRIBUTES_THAT_DOES_NOT_CAUSE_LAYOUT_SHIFTS = ['data-drop-target-for-element', 'draggable'];
12
12
 
13
13
  // Common aria attributes that don't cause visual layout shifts
14
- export const NON_VISUAL_ARIA_ATTRIBUTES = ['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-selected', 'aria-checked', 'aria-disabled', 'aria-required', 'aria-current', 'aria-haspopup', 'aria-pressed', 'aria-live'];
14
+ export const NON_VISUAL_ARIA_ATTRIBUTES = ['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-selected', 'aria-checked', 'aria-disabled', 'aria-required', 'aria-current', 'aria-haspopup', 'aria-pressed', 'aria-atomic', 'aria-live'];
15
15
  export default class VCCalculator_FY25_03 extends AbstractVCCalculatorBase {
16
16
  constructor() {
17
17
  super(REVISION_NO);
@@ -29,7 +29,7 @@ export default class VCCalculator_FY25_03 extends AbstractVCCalculatorBase {
29
29
  if (attributeName === 'data-aui-version' && fg('platform_ufo_filter_out_aui_attribute_changes')) {
30
30
  return false;
31
31
  }
32
- if (attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
32
+ if (attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || (attributeName === 'data-renderer-start-pos' || attributeName === 'data-table-local-id' || attributeName === 'spellcheck') && fg('platform_ufo_ignore_extra_attributes') || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
33
33
  return false;
34
34
  }
35
35
  return true;
@@ -699,7 +699,7 @@ function createInteractionMetricsPayload(_x3, _x4, _x5) {
699
699
  function _createInteractionMetricsPayload() {
700
700
  _createInteractionMetricsPayload = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(interaction, interactionId, experimental) {
701
701
  var _window$location, _config$additionalPay;
702
- var interactionPayloadStart, config, end, start, ufoName, knownSegments, rate, type, abortReason, routeName, featureFlags, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, responsiveness, pageVisibilityAtTTI, pageVisibilityAtTTAI, segments, segmentTree, isDetailedPayload, isPageLoad, calculatePageVisibilityFromTheStartOfPageLoad, moreAccuratePageVisibilityAtTTI, moreAccuratePageVisibilityAtTTAI, labelStack, getInitialPageLoadSSRMetrics, pageLoadInteractionMetrics, getDetailedInteractionMetrics, getPageLoadDetailedInteractionMetrics, newUFOName, resourceTimings, _yield$Promise$all, _yield$Promise$all2, vcMetrics, experimentalMetrics, paintMetrics, payload;
702
+ var interactionPayloadStart, config, end, start, ufoName, knownSegments, rate, type, abortReason, routeName, featureFlags, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, responsiveness, unknownElementName, unknownElementHierarchy, pageVisibilityAtTTI, pageVisibilityAtTTAI, segments, segmentTree, isDetailedPayload, isPageLoad, calculatePageVisibilityFromTheStartOfPageLoad, moreAccuratePageVisibilityAtTTI, moreAccuratePageVisibilityAtTTAI, labelStack, getInitialPageLoadSSRMetrics, pageLoadInteractionMetrics, getDetailedInteractionMetrics, getPageLoadDetailedInteractionMetrics, newUFOName, resourceTimings, _yield$Promise$all, _yield$Promise$all2, vcMetrics, experimentalMetrics, paintMetrics, payload;
703
703
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
704
704
  while (1) switch (_context2.prev = _context2.next) {
705
705
  case 0:
@@ -711,7 +711,7 @@ function _createInteractionMetricsPayload() {
711
711
  }
712
712
  throw Error('UFO Configuration not provided');
713
713
  case 4:
714
- end = interaction.end, start = interaction.start, ufoName = interaction.ufoName, knownSegments = interaction.knownSegments, rate = interaction.rate, type = interaction.type, abortReason = interaction.abortReason, routeName = interaction.routeName, featureFlags = interaction.featureFlags, previousInteractionName = interaction.previousInteractionName, isPreviousInteractionAborted = interaction.isPreviousInteractionAborted, abortedByInteractionName = interaction.abortedByInteractionName, responsiveness = interaction.responsiveness;
714
+ end = interaction.end, start = interaction.start, ufoName = interaction.ufoName, knownSegments = interaction.knownSegments, rate = interaction.rate, type = interaction.type, abortReason = interaction.abortReason, routeName = interaction.routeName, featureFlags = interaction.featureFlags, previousInteractionName = interaction.previousInteractionName, isPreviousInteractionAborted = interaction.isPreviousInteractionAborted, abortedByInteractionName = interaction.abortedByInteractionName, responsiveness = interaction.responsiveness, unknownElementName = interaction.unknownElementName, unknownElementHierarchy = interaction.unknownElementHierarchy;
715
715
  pageVisibilityAtTTI = getPageVisibilityUpToTTI(interaction);
716
716
  pageVisibilityAtTTAI = getPageVisibilityUpToTTAI(interaction);
717
717
  segments = config.killswitchNestedSegments ? [] : knownSegments;
@@ -815,7 +815,7 @@ function _createInteractionMetricsPayload() {
815
815
  }, fg('platform_ufo_report_cpu_usage') ? {
816
816
  'event:cpu:usage': createPressureStateReport(interaction.start, interaction.end)
817
817
  } : {}), getBrowserMetadata()), getSSRProperties(type)), getAssetsMetrics(interaction, pageLoadInteractionMetrics === null || pageLoadInteractionMetrics === void 0 ? void 0 : pageLoadInteractionMetrics.SSRDoneTime)), getPPSMetrics(interaction)), paintMetrics), getNavigationMetrics(type)), vcMetrics), experimentalMetrics), (_config$additionalPay = config.additionalPayloadData) === null || _config$additionalPay === void 0 ? void 0 : _config$additionalPay.call(config, interaction)), getTracingContextData(interaction)), getStylesheetMetrics()), getErrorCounts(interaction)), {}, {
818
- interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
818
+ interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
819
819
  namePrefix: config.namePrefix || '',
820
820
  segmentPrefix: config.segmentPrefix || '',
821
821
  interactionId: interactionId,
@@ -851,7 +851,11 @@ function _createInteractionMetricsPayload() {
851
851
  } : {}), labelStack), pageLoadInteractionMetrics), getDetailedInteractionMetrics(resourceTimings)), getPageLoadDetailedInteractionMetrics()), getBm3TrackerTimings(interaction)), {}, {
852
852
  'metric:ttai': experimental ? regularTTAI || expTTAI : undefined,
853
853
  'metric:experimental:ttai': expTTAI
854
- }),
854
+ }, unknownElementName ? {
855
+ unknownElementName: unknownElementName
856
+ } : {}), unknownElementHierarchy ? {
857
+ unknownElementHierarchy: unknownElementHierarchy
858
+ } : {}),
855
859
  'ufo:payloadTime': roundEpsilon(performance.now() - interactionPayloadStart)
856
860
  })
857
861
  }
@@ -4,8 +4,62 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  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; } } }; }
5
5
  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; } }
6
6
  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; }
7
+ import { fg } from '@atlaskit/platform-feature-flags';
7
8
  import { getActiveInteraction } from '../interaction-metrics';
9
+ import getElementName from '../vc/vc-observer-new/get-unique-element-name';
8
10
  var performanceEventObserver;
11
+ var selectorConfig = {
12
+ id: true,
13
+ testId: true,
14
+ role: true,
15
+ className: true
16
+ };
17
+ function getTestIdName(memoizedProps) {
18
+ if (memoizedProps['data-testid']) {
19
+ return "[data-testid=".concat(memoizedProps['data-testid'], "]");
20
+ } else if (memoizedProps['data-test-id']) {
21
+ return "[data-test-id=".concat(memoizedProps['data-testid'], "]");
22
+ }
23
+ return null;
24
+ }
25
+ function getReactComponentHierarchy(element) {
26
+ var componentHierarchy = [];
27
+ // Function to traverse up the fiber tree
28
+ function traverseFiber(fiber) {
29
+ var currentFiber = fiber;
30
+ while (currentFiber) {
31
+ if (currentFiber.type) {
32
+ // Check if there's a display name or a function name
33
+ var componentName = currentFiber.type.displayName || currentFiber.type.name;
34
+ // checking when component name is bigger than the minimized name produced by react
35
+ if (componentName && componentName.length > 2 && !componentName.includes('Listener') && !componentName.includes('Provider')) {
36
+ componentHierarchy.push(componentName);
37
+ }
38
+ if (componentName === 'UFOSegment') {
39
+ break;
40
+ }
41
+ }
42
+ if (currentFiber.memoizedProps) {
43
+ var dataIdInfo = getTestIdName(currentFiber.memoizedProps);
44
+ if (dataIdInfo) {
45
+ componentHierarchy.push(dataIdInfo);
46
+ currentFiber = null;
47
+ continue;
48
+ }
49
+ }
50
+ currentFiber = currentFiber.return;
51
+ }
52
+ }
53
+ // Access the reactFiber node from the HTML element
54
+ var reactFiberKey = Object.keys(element).find(function (key) {
55
+ return key.startsWith('__reactFiber$');
56
+ });
57
+ if (reactFiberKey) {
58
+ var fiber = element[reactFiberKey];
59
+ traverseFiber(fiber);
60
+ }
61
+ return componentHierarchy.reverse().join(' > ');
62
+ }
9
63
  export var getPerformanceObserver = function getPerformanceObserver() {
10
64
  performanceEventObserver = performanceEventObserver || new PerformanceObserver(function (entries) {
11
65
  var list = entries.getEntries();
@@ -40,5 +94,12 @@ export var setInteractionPerformanceEvent = function setInteractionPerformanceEv
40
94
  // it means the interaction start time is not accurate, we assign
41
95
  // this value which will match the timestamp in the event
42
96
  interaction.start = Math.min(interaction.start, entry.startTime);
97
+ if (interaction.ufoName === 'unknown' && fg('platform_ufo_enable_unknown_interactions_elements')) {
98
+ if (entry.target) {
99
+ var componentHierarchy = getReactComponentHierarchy(entry.target);
100
+ interaction.unknownElementHierarchy = componentHierarchy;
101
+ }
102
+ interaction.unknownElementName = getElementName(selectorConfig, entry.target);
103
+ }
43
104
  }
44
105
  };
@@ -18,7 +18,7 @@ var CONSIDERED_ENTRY_TYPE = ['mutation:child-element', 'mutation:element', 'muta
18
18
  export var KNOWN_ATTRIBUTES_THAT_DOES_NOT_CAUSE_LAYOUT_SHIFTS = ['data-drop-target-for-element', 'draggable'];
19
19
 
20
20
  // Common aria attributes that don't cause visual layout shifts
21
- export var NON_VISUAL_ARIA_ATTRIBUTES = ['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-selected', 'aria-checked', 'aria-disabled', 'aria-required', 'aria-current', 'aria-haspopup', 'aria-pressed', 'aria-live'];
21
+ export var NON_VISUAL_ARIA_ATTRIBUTES = ['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-selected', 'aria-checked', 'aria-disabled', 'aria-required', 'aria-current', 'aria-haspopup', 'aria-pressed', 'aria-atomic', 'aria-live'];
22
22
  var VCCalculator_FY25_03 = /*#__PURE__*/function (_AbstractVCCalculator) {
23
23
  function VCCalculator_FY25_03() {
24
24
  _classCallCheck(this, VCCalculator_FY25_03);
@@ -40,7 +40,7 @@ var VCCalculator_FY25_03 = /*#__PURE__*/function (_AbstractVCCalculator) {
40
40
  if (attributeName === 'data-aui-version' && fg('platform_ufo_filter_out_aui_attribute_changes')) {
41
41
  return false;
42
42
  }
43
- if (attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
43
+ if (attributeName === 'data-testid' || attributeName === 'data-vc' || attributeName === 'data-ssr-placeholder' || attributeName === 'data-ssr-placeholder-replace' || attributeName === 'data-vc-nvs' || attributeName === 'data-media-vc-wrapper' || (attributeName === 'data-renderer-start-pos' || attributeName === 'data-table-local-id' || attributeName === 'spellcheck') && fg('platform_ufo_ignore_extra_attributes') || attributeName === 'data-auto-scrollable' || attributeName === 'id' || attributeName === 'tabindex' || NON_VISUAL_ARIA_ATTRIBUTES.includes(attributeName)) {
44
44
  return false;
45
45
  }
46
46
  return true;
@@ -161,6 +161,8 @@ export interface InteractionMetrics {
161
161
  vc?: VCRawDataType | null;
162
162
  experimentalTTAI?: number;
163
163
  experimentalVC90?: number;
164
+ unknownElementName?: string;
165
+ unknownElementHierarchy?: string;
164
166
  }
165
167
  export type LoadProfilerEventInfo = {
166
168
  identifier: string;