@atlaskit/react-ufo 3.6.7 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/ufo-interaction-ignore
2
2
 
3
+ ## 3.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#144155](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/144155)
8
+ [`328fc686d8e34`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/328fc686d8e34) -
9
+ Added inp and input delay to React UFO press interactions
10
+
3
11
  ## 3.6.7
4
12
 
5
13
  ### Patch Changes
@@ -705,7 +705,7 @@ function createInteractionMetricsPayload(_x3, _x4, _x5) {
705
705
  function _createInteractionMetricsPayload() {
706
706
  _createInteractionMetricsPayload = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(interaction, interactionId, experimental) {
707
707
  var _window$location, _config$additionalPay;
708
- var interactionPayloadStart, config, end, start, ufoName, knownSegments, rate, type, abortReason, routeName, featureFlags, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, 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;
708
+ 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;
709
709
  return _regenerator.default.wrap(function _callee2$(_context2) {
710
710
  while (1) switch (_context2.prev = _context2.next) {
711
711
  case 0:
@@ -717,7 +717,7 @@ function _createInteractionMetricsPayload() {
717
717
  }
718
718
  throw Error('UFO Configuration not provided');
719
719
  case 4:
720
- 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;
720
+ 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;
721
721
  pageVisibilityAtTTI = getPageVisibilityUpToTTI(interaction);
722
722
  pageVisibilityAtTTAI = (0, _getPageVisibilityUpToTtai.default)(interaction);
723
723
  segments = config.killswitchNestedSegments ? [] : knownSegments;
@@ -819,7 +819,7 @@ function _createInteractionMetricsPayload() {
819
819
  'experience:key': experimental ? 'custom.experimental-interaction-metrics' : 'custom.interaction-metrics',
820
820
  'experience:name': newUFOName
821
821
  }, 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)), {}, {
822
- interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
822
+ interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
823
823
  namePrefix: config.namePrefix || '',
824
824
  segmentPrefix: config.segmentPrefix || '',
825
825
  interactionId: interactionId,
@@ -850,7 +850,9 @@ function _createInteractionMetricsPayload() {
850
850
  marks: optimizeMarks(interaction.marks, (0, _getReactUfoPayloadVersion.getReactUFOPayloadVersion)(interaction.type)),
851
851
  customData: optimizeCustomData(interaction),
852
852
  reactProfilerTimings: optimizeReactProfilerTimings(interaction.reactProfilerTimings, start, (0, _getReactUfoPayloadVersion.getReactUFOPayloadVersion)(interaction.type))
853
- }, labelStack), pageLoadInteractionMetrics), getDetailedInteractionMetrics(resourceTimings)), getPageLoadDetailedInteractionMetrics()), getBm3TrackerTimings(interaction)), {}, {
853
+ }, responsiveness ? {
854
+ responsiveness: responsiveness
855
+ } : {}), labelStack), pageLoadInteractionMetrics), getDetailedInteractionMetrics(resourceTimings)), getPageLoadDetailedInteractionMetrics()), getBm3TrackerTimings(interaction)), {}, {
854
856
  'metric:ttai': experimental ? regularTTAI || expTTAI : undefined,
855
857
  'metric:experimental:ttai': expTTAI
856
858
  }),
@@ -34,10 +34,11 @@ exports.addSpanToAll = addSpanToAll;
34
34
  exports.extractModuleName = extractModuleName;
35
35
  exports.getActiveInteraction = getActiveInteraction;
36
36
  exports.getCurrentInteractionType = getCurrentInteractionType;
37
- exports.postInteractionLog = exports.interactionSpans = void 0;
37
+ exports.postInteractionLog = exports.interactionSpans = exports.getPerformanceObserver = void 0;
38
38
  exports.remove = remove;
39
39
  exports.removeHoldByID = removeHoldByID;
40
40
  exports.removeSegment = removeSegment;
41
+ exports.setInteractionPerformanceEvent = void 0;
41
42
  exports.sinkInteractionHandler = sinkInteractionHandler;
42
43
  exports.sinkPostInteractionLogHandler = sinkPostInteractionLogHandler;
43
44
  exports.tryComplete = tryComplete;
@@ -83,6 +84,45 @@ function isPerformanceTracingEnabled() {
83
84
  var _getConfig;
84
85
  return ((_getConfig = (0, _config.getConfig)()) === null || _getConfig === void 0 ? void 0 : _getConfig.enableAdditionalPerformanceMarks) || window.__REACT_UFO_ENABLE_PERF_TRACING || process.env.NODE_ENV !== 'production';
85
86
  }
87
+ var performanceEventObserver;
88
+ var getPerformanceObserver = exports.getPerformanceObserver = function getPerformanceObserver() {
89
+ performanceEventObserver = performanceEventObserver || new PerformanceObserver(function (entries) {
90
+ var list = entries.getEntries();
91
+ var _iterator = _createForOfIteratorHelper(list),
92
+ _step;
93
+ try {
94
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
95
+ var entry = _step.value;
96
+ if (entry.name === 'click') {
97
+ setInteractionPerformanceEvent(entry);
98
+ }
99
+ }
100
+ } catch (err) {
101
+ _iterator.e(err);
102
+ } finally {
103
+ _iterator.f();
104
+ }
105
+ });
106
+ return performanceEventObserver;
107
+ };
108
+ var setInteractionPerformanceEvent = exports.setInteractionPerformanceEvent = function setInteractionPerformanceEvent(entry) {
109
+ var interaction = getActiveInteraction();
110
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
111
+ var responsiveness = interaction.responsiveness || {};
112
+ // if happens there is another event interaction that has started after
113
+ // the initial one, we don't want to replace the values if they have already
114
+ // been set up
115
+ responsiveness.experimentalInputToNextPaint = responsiveness.experimentalInputToNextPaint || entry.duration;
116
+ responsiveness.inputDelay = responsiveness.experimentalInputToNextPaint || entry.processingStart - entry.startTime;
117
+ interaction.responsiveness = responsiveness;
118
+ // if the entry start time is lower than the one in the interaction
119
+ // it means the interaction start time is not accurate, we assign
120
+ // this value which will match the timestamp in the event
121
+ if (entry.startTime < interaction.start) {
122
+ interaction.start = entry.startTime;
123
+ }
124
+ }
125
+ };
86
126
  function labelStackToString(labelStack, name) {
87
127
  var _stack$map;
88
128
  var stack = (0, _toConsumableArray2.default)(labelStack !== null && labelStack !== void 0 ? labelStack : []);
@@ -103,17 +143,17 @@ function labelStackToIdString(labelStack) {
103
143
  }
104
144
  function addSegmentObserver(observer) {
105
145
  segmentObservers.push(observer);
106
- var _iterator = _createForOfIteratorHelper(segmentCache.values()),
107
- _step;
146
+ var _iterator2 = _createForOfIteratorHelper(segmentCache.values()),
147
+ _step2;
108
148
  try {
109
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
110
- var segmentInfo = _step.value;
149
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
150
+ var segmentInfo = _step2.value;
111
151
  observer.onAdd(segmentInfo);
112
152
  }
113
153
  } catch (err) {
114
- _iterator.e(err);
154
+ _iterator2.e(err);
115
155
  } finally {
116
- _iterator.f();
156
+ _iterator2.f();
117
157
  }
118
158
  }
119
159
  function removeSegmentObserver(observer) {
@@ -530,24 +570,24 @@ function finishInteraction(id, data) {
530
570
  });
531
571
  try {
532
572
  // for Firefox 102 and older
533
- var _iterator2 = _createForOfIteratorHelper(profilerTimingMap.entries()),
534
- _step2;
573
+ var _iterator3 = _createForOfIteratorHelper(profilerTimingMap.entries()),
574
+ _step3;
535
575
  try {
536
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
537
- var _step2$value = (0, _slicedToArray2.default)(_step2.value, 2),
538
- _step2$value$ = _step2$value[1],
539
- labelStack = _step2$value$.labelStack,
540
- start = _step2$value$.start,
541
- end = _step2$value$.end;
576
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
577
+ var _step3$value = (0, _slicedToArray2.default)(_step3.value, 2),
578
+ _step3$value$ = _step3$value[1],
579
+ labelStack = _step3$value$.labelStack,
580
+ start = _step3$value$.start,
581
+ end = _step3$value$.end;
542
582
  performance.measure("\uD83D\uDEF8 ".concat(labelStackToString(labelStack), " [segment_ttai]"), {
543
583
  start: start,
544
584
  end: end
545
585
  });
546
586
  }
547
587
  } catch (err) {
548
- _iterator2.e(err);
588
+ _iterator3.e(err);
549
589
  } finally {
550
- _iterator2.f();
590
+ _iterator3.f();
551
591
  }
552
592
  } catch (e) {
553
593
  // do nothing
@@ -13,6 +13,7 @@ var _config = require("../config");
13
13
  var _createExperimentalInteractionMetricsPayload = require("../create-experimental-interaction-metrics-payload");
14
14
  var _hiddenTiming = require("../hidden-timing");
15
15
  var _interactionMetrics = require("../interaction-metrics");
16
+ var _interactionsPerformanceObserver = require("../interactions-performance-observer");
16
17
  var _vc = require("../vc");
17
18
  var _scheduleIdleCallback = _interopRequireDefault(require("./schedule-idle-callback"));
18
19
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
@@ -108,6 +109,16 @@ function init(analyticsWebClientAsync, config) {
108
109
  (0, _hiddenTiming.setupHiddenTimingCapture)();
109
110
  (0, _additionalPayload.startLighthouseObserver)();
110
111
  initialized = true;
112
+ if ((0, _platformFeatureFlags.fg)('platform_ufo_enable_events_observer')) {
113
+ if (typeof PerformanceObserver !== 'undefined') {
114
+ var observer = (0, _interactionsPerformanceObserver.getPerformanceObserver)();
115
+ observer.observe({
116
+ type: 'event',
117
+ buffered: true,
118
+ durationThreshold: 16
119
+ });
120
+ }
121
+ }
111
122
  Promise.all([analyticsWebClientAsync, Promise.resolve().then(function () {
112
123
  return _interopRequireWildcard(require( /* webpackChunkName: "create-payloads" */'../create-payload'));
113
124
  }), Promise.resolve().then(function () {
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.setInteractionPerformanceEvent = exports.getPerformanceObserver = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _interactionMetrics = require("../interaction-metrics");
10
+ 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
+ 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
+ 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
+ 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
+ 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
+ var performanceEventObserver;
16
+ var getPerformanceObserver = exports.getPerformanceObserver = function getPerformanceObserver() {
17
+ performanceEventObserver = performanceEventObserver || new PerformanceObserver(function (entries) {
18
+ var list = entries.getEntries();
19
+ var _iterator = _createForOfIteratorHelper(list),
20
+ _step;
21
+ try {
22
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
23
+ var entry = _step.value;
24
+ if (entry.name === 'click') {
25
+ setInteractionPerformanceEvent(entry);
26
+ }
27
+ }
28
+ } catch (err) {
29
+ _iterator.e(err);
30
+ } finally {
31
+ _iterator.f();
32
+ }
33
+ });
34
+ return performanceEventObserver;
35
+ };
36
+ var setInteractionPerformanceEvent = exports.setInteractionPerformanceEvent = function setInteractionPerformanceEvent(entry) {
37
+ var interaction = (0, _interactionMetrics.getActiveInteraction)();
38
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
39
+ var _interaction$responsi, _interaction$responsi2;
40
+ // if happens there is another event interaction that has started after
41
+ // the initial one, we don't want to replace the values if they have already been set up
42
+ interaction.responsiveness = _objectSpread(_objectSpread({}, interaction.responsiveness), {}, {
43
+ experimentalInputToNextPaint: ((_interaction$responsi = interaction.responsiveness) === null || _interaction$responsi === void 0 ? void 0 : _interaction$responsi.experimentalInputToNextPaint) || entry.duration,
44
+ inputDelay: ((_interaction$responsi2 = interaction.responsiveness) === null || _interaction$responsi2 === void 0 ? void 0 : _interaction$responsi2.inputDelay) || entry.processingStart - entry.startTime
45
+ });
46
+ // if the entry start time is lower than the one in the interaction
47
+ // it means the interaction start time is not accurate, we assign
48
+ // this value which will match the timestamp in the event
49
+ interaction.start = Math.min(interaction.start, entry.startTime);
50
+ }
51
+ };
@@ -35,7 +35,6 @@ var AsyncSegmentHighlight = /*#__PURE__*/(0, _react.lazy)(function () {
35
35
  };
36
36
  });
37
37
  });
38
- var noopIdMap = new Map();
39
38
 
40
39
  // KARL TODO: finish self profiling
41
40
  /** A portion of the page we apply measurement to */
@@ -47,19 +46,12 @@ function UFOSegment(_ref) {
47
46
  mode = _ref$mode === void 0 ? 'single' : _ref$mode;
48
47
  var parentContext = (0, _react.useContext)(_interactionContext.default);
49
48
  var segmentIdMap = (0, _react.useMemo)(function () {
50
- if (!(0, _platformFeatureFlags.fg)('platform_ufo_segment_list_mode')) {
51
- // just in case we cause rerender issues, use noop map
52
- return noopIdMap;
53
- }
54
49
  if (!(parentContext !== null && parentContext !== void 0 && parentContext.segmentIdMap)) {
55
50
  return new Map();
56
51
  }
57
52
  return parentContext.segmentIdMap;
58
53
  }, [parentContext]);
59
54
  var segmentId = (0, _react.useMemo)(function () {
60
- if (!(0, _platformFeatureFlags.fg)('platform_ufo_segment_list_mode')) {
61
- return (0, _shortId.default)();
62
- }
63
55
  if (mode === 'single') {
64
56
  return (0, _shortId.default)();
65
57
  }
@@ -692,7 +692,8 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
692
692
  featureFlags,
693
693
  previousInteractionName,
694
694
  isPreviousInteractionAborted,
695
- abortedByInteractionName
695
+ abortedByInteractionName,
696
+ responsiveness
696
697
  } = interaction;
697
698
  const pageVisibilityAtTTI = getPageVisibilityUpToTTI(interaction);
698
699
  const pageVisibilityAtTTAI = getPageVisibilityUpToTTAI(interaction);
@@ -834,6 +835,9 @@ async function createInteractionMetricsPayload(interaction, interactionId, exper
834
835
  marks: optimizeMarks(interaction.marks, getReactUFOPayloadVersion(interaction.type)),
835
836
  customData: optimizeCustomData(interaction),
836
837
  reactProfilerTimings: optimizeReactProfilerTimings(interaction.reactProfilerTimings, start, getReactUFOPayloadVersion(interaction.type)),
838
+ ...(responsiveness ? {
839
+ responsiveness
840
+ } : {}),
837
841
  ...labelStack,
838
842
  ...pageLoadInteractionMetrics,
839
843
  ...getDetailedInteractionMetrics(resourceTimings),
@@ -29,6 +29,36 @@ function isPerformanceTracingEnabled() {
29
29
  var _getConfig;
30
30
  return ((_getConfig = getConfig()) === null || _getConfig === void 0 ? void 0 : _getConfig.enableAdditionalPerformanceMarks) || window.__REACT_UFO_ENABLE_PERF_TRACING || process.env.NODE_ENV !== 'production';
31
31
  }
32
+ let performanceEventObserver;
33
+ export const getPerformanceObserver = () => {
34
+ performanceEventObserver = performanceEventObserver || new PerformanceObserver(entries => {
35
+ const list = entries.getEntries();
36
+ for (let entry of list) {
37
+ if (entry.name === 'click') {
38
+ setInteractionPerformanceEvent(entry);
39
+ }
40
+ }
41
+ });
42
+ return performanceEventObserver;
43
+ };
44
+ export const setInteractionPerformanceEvent = entry => {
45
+ const interaction = getActiveInteraction();
46
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
47
+ const responsiveness = interaction.responsiveness || {};
48
+ // if happens there is another event interaction that has started after
49
+ // the initial one, we don't want to replace the values if they have already
50
+ // been set up
51
+ responsiveness.experimentalInputToNextPaint = responsiveness.experimentalInputToNextPaint || entry.duration;
52
+ responsiveness.inputDelay = responsiveness.experimentalInputToNextPaint || entry.processingStart - entry.startTime;
53
+ interaction.responsiveness = responsiveness;
54
+ // if the entry start time is lower than the one in the interaction
55
+ // it means the interaction start time is not accurate, we assign
56
+ // this value which will match the timestamp in the event
57
+ if (entry.startTime < interaction.start) {
58
+ interaction.start = entry.startTime;
59
+ }
60
+ }
61
+ };
32
62
  function labelStackToString(labelStack, name) {
33
63
  var _stack$map;
34
64
  const stack = [...(labelStack !== null && labelStack !== void 0 ? labelStack : [])];
@@ -4,6 +4,7 @@ import { setUFOConfig } from '../config';
4
4
  import { experimentalVC, sinkExperimentalHandler } from '../create-experimental-interaction-metrics-payload';
5
5
  import { setupHiddenTimingCapture } from '../hidden-timing';
6
6
  import { postInteractionLog, sinkInteractionHandler, sinkPostInteractionLogHandler } from '../interaction-metrics';
7
+ import { getPerformanceObserver } from '../interactions-performance-observer';
7
8
  import { getVCObserver } from '../vc';
8
9
  import scheduleIdleCallback from './schedule-idle-callback';
9
10
  let initialized = false;
@@ -97,6 +98,16 @@ export function init(analyticsWebClientAsync, config) {
97
98
  setupHiddenTimingCapture();
98
99
  startLighthouseObserver();
99
100
  initialized = true;
101
+ if (fg('platform_ufo_enable_events_observer')) {
102
+ if (typeof PerformanceObserver !== 'undefined') {
103
+ const observer = getPerformanceObserver();
104
+ observer.observe({
105
+ type: 'event',
106
+ buffered: true,
107
+ durationThreshold: 16
108
+ });
109
+ }
110
+ }
100
111
  Promise.all([analyticsWebClientAsync, import( /* webpackChunkName: "create-payloads" */'../create-payload'), import( /* webpackChunkName: "create-post-interaction-log-payload" */'../create-post-interaction-log-payload')]).then(([awc, payloadPackage, createPostInteractionLogPayloadPackage]) => {
101
112
  if (awc.getAnalyticsWebClientPromise) {
102
113
  awc.getAnalyticsWebClientPromise().then(client => {
@@ -0,0 +1,30 @@
1
+ import { getActiveInteraction } from '../interaction-metrics';
2
+ let performanceEventObserver;
3
+ export const getPerformanceObserver = () => {
4
+ performanceEventObserver = performanceEventObserver || new PerformanceObserver(entries => {
5
+ const list = entries.getEntries();
6
+ for (let entry of list) {
7
+ if (entry.name === 'click') {
8
+ setInteractionPerformanceEvent(entry);
9
+ }
10
+ }
11
+ });
12
+ return performanceEventObserver;
13
+ };
14
+ export const setInteractionPerformanceEvent = entry => {
15
+ const interaction = getActiveInteraction();
16
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
17
+ var _interaction$responsi, _interaction$responsi2;
18
+ // if happens there is another event interaction that has started after
19
+ // the initial one, we don't want to replace the values if they have already been set up
20
+ interaction.responsiveness = {
21
+ ...interaction.responsiveness,
22
+ experimentalInputToNextPaint: ((_interaction$responsi = interaction.responsiveness) === null || _interaction$responsi === void 0 ? void 0 : _interaction$responsi.experimentalInputToNextPaint) || entry.duration,
23
+ inputDelay: ((_interaction$responsi2 = interaction.responsiveness) === null || _interaction$responsi2 === void 0 ? void 0 : _interaction$responsi2.inputDelay) || entry.processingStart - entry.startTime
24
+ };
25
+ // if the entry start time is lower than the one in the interaction
26
+ // it means the interaction start time is not accurate, we assign
27
+ // this value which will match the timestamp in the event
28
+ interaction.start = Math.min(interaction.start, entry.startTime);
29
+ }
30
+ };
@@ -15,7 +15,6 @@ let tryCompleteHandle;
15
15
  const AsyncSegmentHighlight = /*#__PURE__*/lazy(() => import( /* webpackChunkName: "@atlaskit-internal_ufo-segment-highlight" */'./segment-highlight').then(module => ({
16
16
  default: module.SegmentHighlight
17
17
  })));
18
- const noopIdMap = new Map();
19
18
 
20
19
  // KARL TODO: finish self profiling
21
20
  /** A portion of the page we apply measurement to */
@@ -27,19 +26,12 @@ export default function UFOSegment({
27
26
  var _getConfig2;
28
27
  const parentContext = useContext(UFOInteractionContext);
29
28
  const segmentIdMap = useMemo(() => {
30
- if (!fg('platform_ufo_segment_list_mode')) {
31
- // just in case we cause rerender issues, use noop map
32
- return noopIdMap;
33
- }
34
29
  if (!(parentContext !== null && parentContext !== void 0 && parentContext.segmentIdMap)) {
35
30
  return new Map();
36
31
  }
37
32
  return parentContext.segmentIdMap;
38
33
  }, [parentContext]);
39
34
  const segmentId = useMemo(() => {
40
- if (!fg('platform_ufo_segment_list_mode')) {
41
- return generateId();
42
- }
43
35
  if (mode === 'single') {
44
36
  return generateId();
45
37
  }
@@ -694,7 +694,7 @@ function createInteractionMetricsPayload(_x3, _x4, _x5) {
694
694
  function _createInteractionMetricsPayload() {
695
695
  _createInteractionMetricsPayload = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(interaction, interactionId, experimental) {
696
696
  var _window$location, _config$additionalPay;
697
- var interactionPayloadStart, config, end, start, ufoName, knownSegments, rate, type, abortReason, routeName, featureFlags, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, 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;
697
+ 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;
698
698
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
699
699
  while (1) switch (_context2.prev = _context2.next) {
700
700
  case 0:
@@ -706,7 +706,7 @@ function _createInteractionMetricsPayload() {
706
706
  }
707
707
  throw Error('UFO Configuration not provided');
708
708
  case 4:
709
- 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;
709
+ 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;
710
710
  pageVisibilityAtTTI = getPageVisibilityUpToTTI(interaction);
711
711
  pageVisibilityAtTTAI = getPageVisibilityUpToTTAI(interaction);
712
712
  segments = config.killswitchNestedSegments ? [] : knownSegments;
@@ -808,7 +808,7 @@ function _createInteractionMetricsPayload() {
808
808
  'experience:key': experimental ? 'custom.experimental-interaction-metrics' : 'custom.interaction-metrics',
809
809
  'experience:name': newUFOName
810
810
  }, 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)), {}, {
811
- interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
811
+ interactionMetrics: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
812
812
  namePrefix: config.namePrefix || '',
813
813
  segmentPrefix: config.segmentPrefix || '',
814
814
  interactionId: interactionId,
@@ -839,7 +839,9 @@ function _createInteractionMetricsPayload() {
839
839
  marks: optimizeMarks(interaction.marks, getReactUFOPayloadVersion(interaction.type)),
840
840
  customData: optimizeCustomData(interaction),
841
841
  reactProfilerTimings: optimizeReactProfilerTimings(interaction.reactProfilerTimings, start, getReactUFOPayloadVersion(interaction.type))
842
- }, labelStack), pageLoadInteractionMetrics), getDetailedInteractionMetrics(resourceTimings)), getPageLoadDetailedInteractionMetrics()), getBm3TrackerTimings(interaction)), {}, {
842
+ }, responsiveness ? {
843
+ responsiveness: responsiveness
844
+ } : {}), labelStack), pageLoadInteractionMetrics), getDetailedInteractionMetrics(resourceTimings)), getPageLoadDetailedInteractionMetrics()), getBm3TrackerTimings(interaction)), {}, {
843
845
  'metric:ttai': experimental ? regularTTAI || expTTAI : undefined,
844
846
  'metric:experimental:ttai': expTTAI
845
847
  }),
@@ -39,6 +39,45 @@ function isPerformanceTracingEnabled() {
39
39
  var _getConfig;
40
40
  return ((_getConfig = getConfig()) === null || _getConfig === void 0 ? void 0 : _getConfig.enableAdditionalPerformanceMarks) || window.__REACT_UFO_ENABLE_PERF_TRACING || process.env.NODE_ENV !== 'production';
41
41
  }
42
+ var performanceEventObserver;
43
+ export var getPerformanceObserver = function getPerformanceObserver() {
44
+ performanceEventObserver = performanceEventObserver || new PerformanceObserver(function (entries) {
45
+ var list = entries.getEntries();
46
+ var _iterator = _createForOfIteratorHelper(list),
47
+ _step;
48
+ try {
49
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
50
+ var entry = _step.value;
51
+ if (entry.name === 'click') {
52
+ setInteractionPerformanceEvent(entry);
53
+ }
54
+ }
55
+ } catch (err) {
56
+ _iterator.e(err);
57
+ } finally {
58
+ _iterator.f();
59
+ }
60
+ });
61
+ return performanceEventObserver;
62
+ };
63
+ export var setInteractionPerformanceEvent = function setInteractionPerformanceEvent(entry) {
64
+ var interaction = getActiveInteraction();
65
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
66
+ var responsiveness = interaction.responsiveness || {};
67
+ // if happens there is another event interaction that has started after
68
+ // the initial one, we don't want to replace the values if they have already
69
+ // been set up
70
+ responsiveness.experimentalInputToNextPaint = responsiveness.experimentalInputToNextPaint || entry.duration;
71
+ responsiveness.inputDelay = responsiveness.experimentalInputToNextPaint || entry.processingStart - entry.startTime;
72
+ interaction.responsiveness = responsiveness;
73
+ // if the entry start time is lower than the one in the interaction
74
+ // it means the interaction start time is not accurate, we assign
75
+ // this value which will match the timestamp in the event
76
+ if (entry.startTime < interaction.start) {
77
+ interaction.start = entry.startTime;
78
+ }
79
+ }
80
+ };
42
81
  function labelStackToString(labelStack, name) {
43
82
  var _stack$map;
44
83
  var stack = _toConsumableArray(labelStack !== null && labelStack !== void 0 ? labelStack : []);
@@ -59,17 +98,17 @@ function labelStackToIdString(labelStack) {
59
98
  }
60
99
  function addSegmentObserver(observer) {
61
100
  segmentObservers.push(observer);
62
- var _iterator = _createForOfIteratorHelper(segmentCache.values()),
63
- _step;
101
+ var _iterator2 = _createForOfIteratorHelper(segmentCache.values()),
102
+ _step2;
64
103
  try {
65
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
66
- var segmentInfo = _step.value;
104
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
105
+ var segmentInfo = _step2.value;
67
106
  observer.onAdd(segmentInfo);
68
107
  }
69
108
  } catch (err) {
70
- _iterator.e(err);
109
+ _iterator2.e(err);
71
110
  } finally {
72
- _iterator.f();
111
+ _iterator2.f();
73
112
  }
74
113
  }
75
114
  function removeSegmentObserver(observer) {
@@ -486,24 +525,24 @@ function finishInteraction(id, data) {
486
525
  });
487
526
  try {
488
527
  // for Firefox 102 and older
489
- var _iterator2 = _createForOfIteratorHelper(profilerTimingMap.entries()),
490
- _step2;
528
+ var _iterator3 = _createForOfIteratorHelper(profilerTimingMap.entries()),
529
+ _step3;
491
530
  try {
492
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
493
- var _step2$value = _slicedToArray(_step2.value, 2),
494
- _step2$value$ = _step2$value[1],
495
- labelStack = _step2$value$.labelStack,
496
- start = _step2$value$.start,
497
- end = _step2$value$.end;
531
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
532
+ var _step3$value = _slicedToArray(_step3.value, 2),
533
+ _step3$value$ = _step3$value[1],
534
+ labelStack = _step3$value$.labelStack,
535
+ start = _step3$value$.start,
536
+ end = _step3$value$.end;
498
537
  performance.measure("\uD83D\uDEF8 ".concat(labelStackToString(labelStack), " [segment_ttai]"), {
499
538
  start: start,
500
539
  end: end
501
540
  });
502
541
  }
503
542
  } catch (err) {
504
- _iterator2.e(err);
543
+ _iterator3.e(err);
505
544
  } finally {
506
- _iterator2.f();
545
+ _iterator3.f();
507
546
  }
508
547
  } catch (e) {
509
548
  // do nothing
@@ -5,6 +5,7 @@ import { setUFOConfig } from '../config';
5
5
  import { experimentalVC, sinkExperimentalHandler } from '../create-experimental-interaction-metrics-payload';
6
6
  import { setupHiddenTimingCapture } from '../hidden-timing';
7
7
  import { postInteractionLog, sinkInteractionHandler, sinkPostInteractionLogHandler } from '../interaction-metrics';
8
+ import { getPerformanceObserver } from '../interactions-performance-observer';
8
9
  import { getVCObserver } from '../vc';
9
10
  import scheduleIdleCallback from './schedule-idle-callback';
10
11
  var initialized = false;
@@ -98,6 +99,16 @@ export function init(analyticsWebClientAsync, config) {
98
99
  setupHiddenTimingCapture();
99
100
  startLighthouseObserver();
100
101
  initialized = true;
102
+ if (fg('platform_ufo_enable_events_observer')) {
103
+ if (typeof PerformanceObserver !== 'undefined') {
104
+ var observer = getPerformanceObserver();
105
+ observer.observe({
106
+ type: 'event',
107
+ buffered: true,
108
+ durationThreshold: 16
109
+ });
110
+ }
111
+ }
101
112
  Promise.all([analyticsWebClientAsync, import( /* webpackChunkName: "create-payloads" */'../create-payload'), import( /* webpackChunkName: "create-post-interaction-log-payload" */'../create-post-interaction-log-payload')]).then(function (_ref) {
102
113
  var _ref2 = _slicedToArray(_ref, 3),
103
114
  awc = _ref2[0],
@@ -0,0 +1,44 @@
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
+ 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
+ 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
+ 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 { getActiveInteraction } from '../interaction-metrics';
8
+ var performanceEventObserver;
9
+ export var getPerformanceObserver = function getPerformanceObserver() {
10
+ performanceEventObserver = performanceEventObserver || new PerformanceObserver(function (entries) {
11
+ var list = entries.getEntries();
12
+ var _iterator = _createForOfIteratorHelper(list),
13
+ _step;
14
+ try {
15
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
16
+ var entry = _step.value;
17
+ if (entry.name === 'click') {
18
+ setInteractionPerformanceEvent(entry);
19
+ }
20
+ }
21
+ } catch (err) {
22
+ _iterator.e(err);
23
+ } finally {
24
+ _iterator.f();
25
+ }
26
+ });
27
+ return performanceEventObserver;
28
+ };
29
+ export var setInteractionPerformanceEvent = function setInteractionPerformanceEvent(entry) {
30
+ var interaction = getActiveInteraction();
31
+ if ((interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'press') {
32
+ var _interaction$responsi, _interaction$responsi2;
33
+ // if happens there is another event interaction that has started after
34
+ // the initial one, we don't want to replace the values if they have already been set up
35
+ interaction.responsiveness = _objectSpread(_objectSpread({}, interaction.responsiveness), {}, {
36
+ experimentalInputToNextPaint: ((_interaction$responsi = interaction.responsiveness) === null || _interaction$responsi === void 0 ? void 0 : _interaction$responsi.experimentalInputToNextPaint) || entry.duration,
37
+ inputDelay: ((_interaction$responsi2 = interaction.responsiveness) === null || _interaction$responsi2 === void 0 ? void 0 : _interaction$responsi2.inputDelay) || entry.processingStart - entry.startTime
38
+ });
39
+ // if the entry start time is lower than the one in the interaction
40
+ // it means the interaction start time is not accurate, we assign
41
+ // this value which will match the timestamp in the event
42
+ interaction.start = Math.min(interaction.start, entry.startTime);
43
+ }
44
+ };