@atlaskit/react-ufo 3.13.28 → 3.14.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 (55) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/create-payload/index.js +3 -1
  3. package/dist/cjs/ignore-holds/index.js +62 -0
  4. package/dist/cjs/interaction-ignore/ufo-interaction-ignore.js +7 -49
  5. package/dist/cjs/interaction-metrics-init/index.js +3 -0
  6. package/dist/cjs/machine-utilisation/index.js +82 -9
  7. package/dist/cjs/segment/index.js +7 -0
  8. package/dist/cjs/segment/segment.js +3 -1
  9. package/dist/cjs/segment/third-party-segment.js +25 -0
  10. package/dist/cjs/vc/vc-observer-new/metric-calculator/fy25_03/index.js +11 -2
  11. package/dist/cjs/vc/vc-observer-new/viewport-observer/index.js +30 -6
  12. package/dist/cjs/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js +85 -0
  13. package/dist/es2019/create-payload/index.js +4 -1
  14. package/dist/es2019/ignore-holds/index.js +51 -0
  15. package/dist/es2019/interaction-ignore/ufo-interaction-ignore.js +7 -45
  16. package/dist/es2019/interaction-metrics-init/index.js +4 -1
  17. package/dist/es2019/machine-utilisation/index.js +72 -5
  18. package/dist/es2019/segment/index.js +2 -1
  19. package/dist/es2019/segment/segment.js +2 -1
  20. package/dist/es2019/segment/third-party-segment.js +18 -0
  21. package/dist/es2019/vc/vc-observer-new/metric-calculator/fy25_03/index.js +11 -2
  22. package/dist/es2019/vc/vc-observer-new/viewport-observer/index.js +32 -6
  23. package/dist/es2019/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js +71 -0
  24. package/dist/esm/create-payload/index.js +4 -2
  25. package/dist/esm/ignore-holds/index.js +53 -0
  26. package/dist/esm/interaction-ignore/ufo-interaction-ignore.js +7 -47
  27. package/dist/esm/interaction-metrics-init/index.js +4 -1
  28. package/dist/esm/machine-utilisation/index.js +76 -8
  29. package/dist/esm/segment/index.js +2 -1
  30. package/dist/esm/segment/segment.js +3 -1
  31. package/dist/esm/segment/third-party-segment.js +18 -0
  32. package/dist/esm/vc/vc-observer-new/metric-calculator/fy25_03/index.js +11 -2
  33. package/dist/esm/vc/vc-observer-new/viewport-observer/index.js +30 -6
  34. package/dist/esm/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.js +76 -0
  35. package/dist/types/create-payload/index.d.ts +160 -0
  36. package/dist/types/ignore-holds/index.d.ts +31 -0
  37. package/dist/types/interaction-ignore/ufo-interaction-ignore.d.ts +6 -21
  38. package/dist/types/machine-utilisation/index.d.ts +10 -1
  39. package/dist/types/machine-utilisation/types.d.ts +6 -0
  40. package/dist/types/segment/index.d.ts +1 -0
  41. package/dist/types/segment/segment.d.ts +4 -2
  42. package/dist/types/segment/third-party-segment.d.ts +6 -0
  43. package/dist/types/vc/vc-observer-new/types.d.ts +1 -1
  44. package/dist/types/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.d.ts +15 -0
  45. package/dist/types-ts4.5/create-payload/index.d.ts +160 -0
  46. package/dist/types-ts4.5/ignore-holds/index.d.ts +31 -0
  47. package/dist/types-ts4.5/interaction-ignore/ufo-interaction-ignore.d.ts +6 -21
  48. package/dist/types-ts4.5/machine-utilisation/index.d.ts +10 -1
  49. package/dist/types-ts4.5/machine-utilisation/types.d.ts +6 -0
  50. package/dist/types-ts4.5/segment/index.d.ts +1 -0
  51. package/dist/types-ts4.5/segment/segment.d.ts +4 -2
  52. package/dist/types-ts4.5/segment/third-party-segment.d.ts +6 -0
  53. package/dist/types-ts4.5/vc/vc-observer-new/types.d.ts +1 -1
  54. package/dist/types-ts4.5/vc/vc-observer-new/viewport-observer/utils/get-component-name-and-child-props.d.ts +15 -0
  55. package/package.json +10 -1
@@ -1,49 +1,11 @@
1
- import React, { useContext, useMemo } from 'react';
2
- import InteractionContext from '@atlaskit/interaction-context';
1
+ import React from 'react';
2
+ import UFOIgnoreHolds from '../ignore-holds';
3
3
 
4
4
  /**
5
- * Prevent a subtree from holding up an interaction
6
- * Use this when you have a component which loads in late, but
7
- * isn't considered to be a breach of SLO
8
- *
9
- * ```js
10
- * <App>
11
- * <Main />
12
- * <Sidebar>
13
- * <UFOInteractionIgnore>
14
- * <InsightsButton />
15
- * </UFOInteractionIgnore>
16
- * </Sidebar>
17
- * </App>
18
- * ```
19
- *
20
- * Has an `ignore` prop, to allow you to use it conditionally
5
+ * Legacy wrapper component that delegates to `UFOIgnoreHolds`.
6
+ * Use `UFOIgnoreHolds` instead for new implementations.
7
+ * This component is maintained for backward compatibility only.
21
8
  */
22
- export default function UFOInteractionIgnore({
23
- children,
24
- ignore = true
25
- }) {
26
- const parentContext = useContext(InteractionContext);
27
- const ignoredInteractionContext = useMemo(() => {
28
- if (!parentContext) {
29
- return null;
30
- }
31
- return {
32
- ...parentContext,
33
- hold(...args) {
34
- if (!ignore) {
35
- return parentContext.hold(...args);
36
- }
37
- }
38
- };
39
- }, [parentContext, ignore]);
40
-
41
- // react-18: Use children directly
42
- const kids = children != null ? children : null;
43
- if (!ignoredInteractionContext) {
44
- return /*#__PURE__*/React.createElement(React.Fragment, null, kids);
45
- }
46
- return /*#__PURE__*/React.createElement(InteractionContext.Provider, {
47
- value: ignoredInteractionContext
48
- }, kids);
9
+ export default function UFOInteractionIgnore(props) {
10
+ return /*#__PURE__*/React.createElement(UFOIgnoreHolds, props);
49
11
  }
@@ -5,7 +5,7 @@ import { experimentalVC, sinkExperimentalHandler } from '../create-experimental-
5
5
  import { setupHiddenTimingCapture } from '../hidden-timing';
6
6
  import { postInteractionLog, sinkInteractionHandler, sinkPostInteractionLogHandler } from '../interaction-metrics';
7
7
  import { getPerformanceObserver } from '../interactions-performance-observer';
8
- import { initialisePressureObserver } from '../machine-utilisation';
8
+ import { initialiseMemoryObserver, initialisePressureObserver } from '../machine-utilisation';
9
9
  import { getVCObserver } from '../vc';
10
10
  import scheduleIdleCallback from './schedule-idle-callback';
11
11
  let initialized = false;
@@ -77,6 +77,9 @@ export function init(analyticsWebClientAsync, config) {
77
77
  if (fg('platform_ufo_report_cpu_usage')) {
78
78
  initialisePressureObserver();
79
79
  }
80
+ if (fg('platform_ufo_report_memory_usage')) {
81
+ initialiseMemoryObserver();
82
+ }
80
83
  setUFOConfig(config);
81
84
  if ((_config$vc = config.vc) !== null && _config$vc !== void 0 && _config$vc.enabled) {
82
85
  var _config$experimentalI;
@@ -1,14 +1,24 @@
1
1
  const BUFFER_MAX_LENGTH = 1000; // ensure we don't blow up this buffer
2
2
  let pressureRecordBuffer = [];
3
3
  let pressureObserver = null;
4
+ let memoryRecordBuffer = [];
5
+ let memoryInterval;
4
6
  export function resetPressureRecordBuffer() {
5
7
  pressureRecordBuffer.length = 0;
6
8
  }
7
- export function removeOldBufferRecords(filter) {
9
+ export function resetMemoryRecordBuffer() {
10
+ memoryRecordBuffer.length = 0;
11
+ }
12
+ export function removeOldPressureBufferRecords(filter) {
8
13
  pressureRecordBuffer = pressureRecordBuffer.filter(({
9
14
  time
10
15
  }) => time > filter);
11
16
  }
17
+ export function removeOldMemoryBufferRecords(filter) {
18
+ memoryRecordBuffer = memoryRecordBuffer.filter(({
19
+ time
20
+ }) => time > filter);
21
+ }
12
22
  export function createPressureStateReport(start, end) {
13
23
  try {
14
24
  // To differentiate between the API not available, vs no PressureRecords added
@@ -30,7 +40,7 @@ export function createPressureStateReport(start, end) {
30
40
  critical: 0
31
41
  });
32
42
  const pressureStateTotal = Object.values(pressureStateCount).reduce((total, count) => total + count) || 1;
33
- removeOldBufferRecords(end);
43
+ removeOldPressureBufferRecords(end);
34
44
  return {
35
45
  count: pressureStateCount,
36
46
  percentage: {
@@ -44,23 +54,80 @@ export function createPressureStateReport(start, end) {
44
54
  return null;
45
55
  }
46
56
  }
57
+ function convertBytesToMegabytes(bytes) {
58
+ return Math.round(Math.round(bytes / (1024 * 1024) * 100) / 100);
59
+ }
60
+ export function createMemoryStateReport(start, end) {
61
+ try {
62
+ if (!('memory' in performance)) {
63
+ return null;
64
+ }
65
+ const accumulatedMemoryUsage = memoryRecordBuffer.reduce((acc, snapshot) => {
66
+ if (snapshot.time >= start && snapshot.time <= end) {
67
+ acc.totalJSHeapSize += snapshot.totalJSHeapSize;
68
+ acc.usedJSHeapSize += snapshot.usedJSHeapSize;
69
+ acc.snapshotCount += 1;
70
+ }
71
+ return acc;
72
+ }, {
73
+ totalJSHeapSize: 0,
74
+ usedJSHeapSize: 0,
75
+ snapshotCount: 0
76
+ });
77
+ const memoryStateReport = {
78
+ jsHeapSizeLimitInMB: convertBytesToMegabytes(memoryRecordBuffer[0].jsHeapSizeLimit),
79
+ // just use the first record, since this value always remains the same over time
80
+ avgTotalJSHeapSizeInMB: convertBytesToMegabytes(accumulatedMemoryUsage.totalJSHeapSize / accumulatedMemoryUsage.snapshotCount),
81
+ avgUsedJSHeapSizeInMB: convertBytesToMegabytes(accumulatedMemoryUsage.usedJSHeapSize / accumulatedMemoryUsage.snapshotCount)
82
+ };
83
+ removeOldMemoryBufferRecords(end);
84
+ return memoryStateReport;
85
+ } catch {
86
+ return null;
87
+ }
88
+ }
47
89
  export function initialisePressureObserver() {
48
90
  try {
49
91
  if ('PressureObserver' in globalThis) {
50
- var _pressureObserver$obs;
51
92
  pressureObserver = new PressureObserver(records => {
52
93
  if (pressureRecordBuffer.length + records.length <= BUFFER_MAX_LENGTH) {
53
94
  pressureRecordBuffer.push(...records);
54
95
  }
55
96
  });
56
- (_pressureObserver$obs = pressureObserver.observe('cpu', {
97
+ pressureObserver.observe('cpu', {
57
98
  sampleInterval: 100
58
- })) === null || _pressureObserver$obs === void 0 ? void 0 : _pressureObserver$obs.catch();
99
+ }).catch();
59
100
  }
60
101
  } catch (err) {
61
102
  /* do nothing, this is a best efforts metric */
62
103
  }
63
104
  }
105
+ export function initialiseMemoryObserver() {
106
+ try {
107
+ // only set up the interval if `performance.memory` is available in the browser
108
+ if ('memory' in performance) {
109
+ memoryInterval = setInterval(() => {
110
+ // another check of `performance.memory` availability to satisfy typescript
111
+ if ('memory' in performance) {
112
+ const memory = performance.memory;
113
+ if (memoryRecordBuffer.length <= BUFFER_MAX_LENGTH) {
114
+ memoryRecordBuffer.push({
115
+ time: performance.now(),
116
+ jsHeapSizeLimit: memory.jsHeapSizeLimit,
117
+ totalJSHeapSize: memory.totalJSHeapSize,
118
+ usedJSHeapSize: memory.usedJSHeapSize
119
+ });
120
+ }
121
+ }
122
+ }, 100);
123
+ }
124
+ } catch {
125
+ /* do nothing, this is a best efforts metric */
126
+ }
127
+ }
128
+ export function disconnectMemoryObserver() {
129
+ clearInterval(memoryInterval);
130
+ }
64
131
  export function disconnectPressureObserver() {
65
132
  var _pressureObserver;
66
133
  (_pressureObserver = pressureObserver) === null || _pressureObserver === void 0 ? void 0 : _pressureObserver.disconnect();
@@ -1,2 +1,3 @@
1
1
  import UFOSegment from './segment';
2
- export default UFOSegment;
2
+ export default UFOSegment;
3
+ export { UFOThirdPartySegment } from './third-party-segment';
@@ -20,7 +20,8 @@ const AsyncSegmentHighlight = /*#__PURE__*/lazy(() => import( /* webpackChunkNam
20
20
  export default function UFOSegment({
21
21
  name: segmentName,
22
22
  children,
23
- mode = 'single'
23
+ mode = 'single',
24
+ type = 'first-party'
24
25
  }) {
25
26
  var _getConfig2;
26
27
  const parentContext = useContext(UFOInteractionContext);
@@ -0,0 +1,18 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import React from 'react';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ import UFOIgnoreHolds from '../ignore-holds';
5
+ import UFOSegment from './segment';
6
+ export function UFOThirdPartySegment(props) {
7
+ const {
8
+ children,
9
+ ...otherProps
10
+ } = props;
11
+ return /*#__PURE__*/React.createElement(UFOSegment, _extends({
12
+ type: "third-party"
13
+ }, otherProps), /*#__PURE__*/React.createElement(UFOIgnoreHolds, {
14
+ ignore: fg('platform_ufo_exclude_3p_elements_from_ttai'),
15
+ reason: "third-party-element"
16
+ }, children));
17
+ }
18
+ UFOThirdPartySegment.displayName = 'UFOThirdPartySegment';
@@ -3,7 +3,16 @@ import AbstractVCCalculatorBase from '../abstract-base-vc-calculator';
3
3
  import isViewportEntryData from '../utils/is-viewport-entry-data';
4
4
  const ABORTING_WINDOW_EVENT = ['wheel', 'scroll', 'keydown', 'resize'];
5
5
  const REVISION_NO = 'fy25.03';
6
- const CONSIDERED_ENTRY_TYPE = ['mutation:child-element', 'mutation:element', 'mutation:attribute', 'layout-shift', 'window:event'];
6
+ const getConsideredEntryTypes = () => {
7
+ const entryTypes = ['mutation:child-element', 'mutation:element', 'mutation:attribute', 'layout-shift', 'window:event'];
8
+
9
+ // If not exclude 3p elements from ttvc,
10
+ // including the tags into the ConsideredEntryTypes so that it won't be ignored for TTVC calculation
11
+ if (!fg('platform_ufo_exclude_3p_elements_from_ttvc')) {
12
+ entryTypes.push('mutation:third-party-element');
13
+ }
14
+ return entryTypes;
15
+ };
7
16
 
8
17
  // TODO: AFO-3523
9
18
  // Those are the attributes we have found when testing the 'fy25.03' manually.
@@ -17,7 +26,7 @@ export default class VCCalculator_FY25_03 extends AbstractVCCalculatorBase {
17
26
  super(REVISION_NO);
18
27
  }
19
28
  isEntryIncluded(entry) {
20
- if (!CONSIDERED_ENTRY_TYPE.includes(entry.data.type)) {
29
+ if (!getConsideredEntryTypes().includes(entry.data.type)) {
21
30
  return false;
22
31
  }
23
32
  if (entry.data.type === 'mutation:attribute') {
@@ -5,6 +5,7 @@ import { RLLPlaceholderHandlers } from '../../vc-observer/observers/rll-placehol
5
5
  import { createIntersectionObserver } from './intersection-observer';
6
6
  import createMutationObserver from './mutation-observer';
7
7
  import createPerformanceObserver from './performance-observer';
8
+ import { checkThirdPartySegmentWithIgnoreReason, createMutationTypeWithIgnoredReason } from './utils/get-component-name-and-child-props';
8
9
  function isElementVisible(element) {
9
10
  if (!(element instanceof HTMLElement)) {
10
11
  return true;
@@ -86,7 +87,7 @@ export default class ViewportObserver {
86
87
  return this.mapVisibleNodeRects.get(n);
87
88
  });
88
89
  addedNodes.forEach(addedNodeRef => {
89
- var _this$intersectionObs3;
90
+ var _this$intersectionObs4;
90
91
  const addedNode = addedNodeRef.deref();
91
92
  if (!addedNode) {
92
93
  return;
@@ -108,7 +109,17 @@ export default class ViewportObserver {
108
109
  (_this$intersectionObs2 = this.intersectionObserver) === null || _this$intersectionObs2 === void 0 ? void 0 : _this$intersectionObs2.watchAndTag(addedNode, 'mutation:media');
109
110
  return;
110
111
  }
111
- (_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(addedNode, createElementMutationsWatcher(removedNodeRects));
112
+ const {
113
+ isWithinThirdPartySegment,
114
+ ignoredReason
115
+ } = checkThirdPartySegmentWithIgnoreReason(addedNode);
116
+ if (isWithinThirdPartySegment) {
117
+ var _this$intersectionObs3;
118
+ const assignedReason = createMutationTypeWithIgnoredReason(ignoredReason || 'third-party-element');
119
+ (_this$intersectionObs3 = this.intersectionObserver) === null || _this$intersectionObs3 === void 0 ? void 0 : _this$intersectionObs3.watchAndTag(addedNode, assignedReason);
120
+ return;
121
+ }
122
+ (_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(addedNode, createElementMutationsWatcher(removedNodeRects));
112
123
  });
113
124
  });
114
125
  _defineProperty(this, "handleAttributeMutation", ({
@@ -117,8 +128,8 @@ export default class ViewportObserver {
117
128
  oldValue,
118
129
  newValue
119
130
  }) => {
120
- var _this$intersectionObs4;
121
- (_this$intersectionObs4 = this.intersectionObserver) === null || _this$intersectionObs4 === void 0 ? void 0 : _this$intersectionObs4.watchAndTag(target, ({
131
+ var _this$intersectionObs5;
132
+ (_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.watchAndTag(target, ({
122
133
  target,
123
134
  rect
124
135
  }) => {
@@ -157,6 +168,21 @@ export default class ViewportObserver {
157
168
  }
158
169
  };
159
170
  }
171
+ const {
172
+ isWithinThirdPartySegment,
173
+ ignoredReason
174
+ } = checkThirdPartySegmentWithIgnoreReason(target);
175
+ if (isWithinThirdPartySegment) {
176
+ const assignedReason = createMutationTypeWithIgnoredReason(ignoredReason || 'third-party-element');
177
+ return {
178
+ type: assignedReason,
179
+ mutationData: {
180
+ attributeName,
181
+ oldValue,
182
+ newValue
183
+ }
184
+ };
185
+ }
160
186
  const lastElementRect = this.mapVisibleNodeRects.get(target);
161
187
  if (lastElementRect && sameRectSize(rect, lastElementRect)) {
162
188
  return {
@@ -239,12 +265,12 @@ export default class ViewportObserver {
239
265
  this.isStarted = true;
240
266
  }
241
267
  stop() {
242
- var _this$mutationObserve2, _this$intersectionObs5, _this$performanceObse2;
268
+ var _this$mutationObserve2, _this$intersectionObs6, _this$performanceObse2;
243
269
  if (!this.isStarted) {
244
270
  return;
245
271
  }
246
272
  (_this$mutationObserve2 = this.mutationObserver) === null || _this$mutationObserve2 === void 0 ? void 0 : _this$mutationObserve2.disconnect();
247
- (_this$intersectionObs5 = this.intersectionObserver) === null || _this$intersectionObs5 === void 0 ? void 0 : _this$intersectionObs5.disconnect();
273
+ (_this$intersectionObs6 = this.intersectionObserver) === null || _this$intersectionObs6 === void 0 ? void 0 : _this$intersectionObs6.disconnect();
248
274
  (_this$performanceObse2 = this.performanceObserver) === null || _this$performanceObse2 === void 0 ? void 0 : _this$performanceObse2.disconnect();
249
275
  this.isStarted = false;
250
276
  }
@@ -0,0 +1,71 @@
1
+ // Using the React Fiber tree to traverse up the DOM and check if a node is within a specific component
2
+ // and extract child component props if needed.
3
+ export function checkWithinComponentAndExtractChildProps(node, targetComponentName, childComponentConfig) {
4
+ // Get the React fiber from the DOM node
5
+ const key = Object.keys(node).find(key => key.startsWith('__reactFiber$') || key.startsWith('__reactInternalInstance$'));
6
+ if (!key) {
7
+ return {
8
+ isWithin: false
9
+ };
10
+ }
11
+ const fiber = node[key];
12
+ if (!fiber) {
13
+ return {
14
+ isWithin: false
15
+ };
16
+ }
17
+
18
+ // Traverse up the fiber tree
19
+ let currentFiber = fiber;
20
+ let childProp;
21
+ while (currentFiber) {
22
+ let componentName;
23
+ if (currentFiber.type) {
24
+ if (typeof currentFiber.type === 'function') {
25
+ componentName = currentFiber.type.displayName || currentFiber.type.name;
26
+ } else if (typeof currentFiber.type === 'object' && (currentFiber.type.displayName || currentFiber.type.name)) {
27
+ componentName = currentFiber.type.displayName || currentFiber.type.name;
28
+ }
29
+ }
30
+
31
+ // Check if this is a child component we're looking for
32
+ if (childComponentConfig && componentName === childComponentConfig.componentName) {
33
+ const props = currentFiber.memoizedProps || currentFiber.pendingProps;
34
+ if (props && props[childComponentConfig.propName] !== undefined) {
35
+ // Overwrite with the nearest child prop (closest to the target component)
36
+ childProp = childComponentConfig.extractValue ? childComponentConfig.extractValue(props) : props[childComponentConfig.propName];
37
+ }
38
+ }
39
+
40
+ // Check if we found the target component
41
+ if (componentName === targetComponentName) {
42
+ return {
43
+ isWithin: true,
44
+ ...(childComponentConfig && {
45
+ childProp: childProp
46
+ })
47
+ };
48
+ }
49
+ currentFiber = currentFiber.return;
50
+ }
51
+ return {
52
+ isWithin: false
53
+ };
54
+ }
55
+
56
+ // Check if the node is within a UFOThirdPartySegment and extract any UFOIgnoreHolds reason
57
+ export function checkThirdPartySegmentWithIgnoreReason(node) {
58
+ const result = checkWithinComponentAndExtractChildProps(node, 'UFOThirdPartySegment', {
59
+ componentName: 'UFOIgnoreHolds',
60
+ propName: 'reason'
61
+ });
62
+ return {
63
+ isWithinThirdPartySegment: result.isWithin,
64
+ ignoredReason: result.childProp
65
+ };
66
+ }
67
+
68
+ // Helper function to create mutation type from UFOIgnoreHoldsReason
69
+ export function createMutationTypeWithIgnoredReason(reason) {
70
+ return `mutation:${reason}`;
71
+ }
@@ -23,7 +23,7 @@ import { getGlobalErrorCount } from '../global-error-handler';
23
23
  import { getPageVisibilityState } from '../hidden-timing';
24
24
  import * as initialPageLoadExtraTiming from '../initial-page-load-extra-timing';
25
25
  import { interactionSpans as atlaskitInteractionSpans } from '../interaction-metrics';
26
- import { createPressureStateReport } from '../machine-utilisation';
26
+ import { createMemoryStateReport, createPressureStateReport } from '../machine-utilisation';
27
27
  import * as resourceTiming from '../resource-timing';
28
28
  import { filterResourceTimings } from '../resource-timing/common/utils/resource-timing-buffer';
29
29
  import { roundEpsilon } from '../round-number';
@@ -799,7 +799,7 @@ function _createInteractionMetricsPayload() {
799
799
  source: 'measured',
800
800
  tags: ['observability'],
801
801
  attributes: {
802
- properties: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
802
+ properties: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
803
803
  // basic
804
804
  'event:hostname': ((_window$location = window.location) === null || _window$location === void 0 ? void 0 : _window$location.hostname) || 'unknown',
805
805
  'event:product': config.product,
@@ -814,6 +814,8 @@ function _createInteractionMetricsPayload() {
814
814
  'experience:name': newUFOName
815
815
  }, fg('platform_ufo_report_cpu_usage') ? {
816
816
  'event:cpu:usage': createPressureStateReport(interaction.start, interaction.end)
817
+ } : {}), fg('platform_ufo_report_memory_usage') ? {
818
+ 'event:memory:usage': createMemoryStateReport(interaction.start, interaction.end)
817
819
  } : {}), 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
820
  interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
819
821
  namePrefix: config.namePrefix || '',
@@ -0,0 +1,53 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import React, { useContext, useMemo } from 'react';
5
+ import InteractionContext from '@atlaskit/interaction-context';
6
+ /**
7
+ * Prevent a subtree from holding up an interaction
8
+ * Use this when you have a component which loads in late, but
9
+ * isn't considered to be a breach of SLO
10
+ *
11
+ * ```js
12
+ * <App>
13
+ * <Main />
14
+ * <Sidebar>
15
+ * <UFOIgnoreHolds>
16
+ * <InsightsButton />
17
+ * </UFOIgnoreHolds>
18
+ * </Sidebar>
19
+ * </App>
20
+ * ```
21
+ *
22
+ * Has an `ignore` prop, to allow you to use it conditionally
23
+ * Has a `reason` prop, to specify why the hold is being ignored
24
+ */
25
+ export default function UFOIgnoreHolds(_ref) {
26
+ var children = _ref.children,
27
+ _ref$ignore = _ref.ignore,
28
+ ignore = _ref$ignore === void 0 ? true : _ref$ignore,
29
+ reason = _ref.reason;
30
+ var parentContext = useContext(InteractionContext);
31
+ var ignoredInteractionContext = useMemo(function () {
32
+ if (!parentContext) {
33
+ return null;
34
+ }
35
+ return _objectSpread(_objectSpread({}, parentContext), {}, {
36
+ hold: function hold() {
37
+ if (!ignore) {
38
+ return parentContext.hold.apply(parentContext, arguments);
39
+ }
40
+ }
41
+ });
42
+ }, [parentContext, ignore]);
43
+
44
+ // react-18: Use children directly
45
+ var kids = children != null ? children : null;
46
+ if (!ignoredInteractionContext) {
47
+ return /*#__PURE__*/React.createElement(React.Fragment, null, kids);
48
+ }
49
+ return /*#__PURE__*/React.createElement(InteractionContext.Provider, {
50
+ value: ignoredInteractionContext
51
+ }, kids);
52
+ }
53
+ UFOIgnoreHolds.displayName = 'UFOIgnoreHolds';
@@ -1,51 +1,11 @@
1
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
- import React, { useContext, useMemo } from 'react';
5
- import InteractionContext from '@atlaskit/interaction-context';
1
+ import React from 'react';
2
+ import UFOIgnoreHolds from '../ignore-holds';
6
3
 
7
4
  /**
8
- * Prevent a subtree from holding up an interaction
9
- * Use this when you have a component which loads in late, but
10
- * isn't considered to be a breach of SLO
11
- *
12
- * ```js
13
- * <App>
14
- * <Main />
15
- * <Sidebar>
16
- * <UFOInteractionIgnore>
17
- * <InsightsButton />
18
- * </UFOInteractionIgnore>
19
- * </Sidebar>
20
- * </App>
21
- * ```
22
- *
23
- * Has an `ignore` prop, to allow you to use it conditionally
5
+ * Legacy wrapper component that delegates to `UFOIgnoreHolds`.
6
+ * Use `UFOIgnoreHolds` instead for new implementations.
7
+ * This component is maintained for backward compatibility only.
24
8
  */
25
- export default function UFOInteractionIgnore(_ref) {
26
- var children = _ref.children,
27
- _ref$ignore = _ref.ignore,
28
- ignore = _ref$ignore === void 0 ? true : _ref$ignore;
29
- var parentContext = useContext(InteractionContext);
30
- var ignoredInteractionContext = useMemo(function () {
31
- if (!parentContext) {
32
- return null;
33
- }
34
- return _objectSpread(_objectSpread({}, parentContext), {}, {
35
- hold: function hold() {
36
- if (!ignore) {
37
- return parentContext.hold.apply(parentContext, arguments);
38
- }
39
- }
40
- });
41
- }, [parentContext, ignore]);
42
-
43
- // react-18: Use children directly
44
- var kids = children != null ? children : null;
45
- if (!ignoredInteractionContext) {
46
- return /*#__PURE__*/React.createElement(React.Fragment, null, kids);
47
- }
48
- return /*#__PURE__*/React.createElement(InteractionContext.Provider, {
49
- value: ignoredInteractionContext
50
- }, kids);
9
+ export default function UFOInteractionIgnore(props) {
10
+ return /*#__PURE__*/React.createElement(UFOIgnoreHolds, props);
51
11
  }
@@ -6,7 +6,7 @@ import { experimentalVC, sinkExperimentalHandler } from '../create-experimental-
6
6
  import { setupHiddenTimingCapture } from '../hidden-timing';
7
7
  import { postInteractionLog, sinkInteractionHandler, sinkPostInteractionLogHandler } from '../interaction-metrics';
8
8
  import { getPerformanceObserver } from '../interactions-performance-observer';
9
- import { initialisePressureObserver } from '../machine-utilisation';
9
+ import { initialiseMemoryObserver, initialisePressureObserver } from '../machine-utilisation';
10
10
  import { getVCObserver } from '../vc';
11
11
  import scheduleIdleCallback from './schedule-idle-callback';
12
12
  var initialized = false;
@@ -78,6 +78,9 @@ export function init(analyticsWebClientAsync, config) {
78
78
  if (fg('platform_ufo_report_cpu_usage')) {
79
79
  initialisePressureObserver();
80
80
  }
81
+ if (fg('platform_ufo_report_memory_usage')) {
82
+ initialiseMemoryObserver();
83
+ }
81
84
  setUFOConfig(config);
82
85
  if ((_config$vc = config.vc) !== null && _config$vc !== void 0 && _config$vc.enabled) {
83
86
  var _config$experimentalI;