@atlaskit/smart-card 23.9.3 → 23.10.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 (41) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/hoverCard.js +13 -0
  3. package/dist/cjs/state/analytics/useSmartLinkAnalytics.js +47 -17
  4. package/dist/cjs/utils/analytics/analytics.js +30 -2
  5. package/dist/cjs/utils/analytics/index.js +6 -0
  6. package/dist/cjs/utils/index.js +65 -2
  7. package/dist/cjs/version.json +1 -1
  8. package/dist/cjs/view/CardWithUrl/loader.js +19 -8
  9. package/dist/cjs/view/HoverCard/components/HoverCardContent.js +6 -0
  10. package/dist/cjs/view/HoverCard/components/views/resolved/index.js +0 -6
  11. package/dist/es2019/hoverCard.js +1 -0
  12. package/dist/es2019/state/analytics/useSmartLinkAnalytics.js +32 -1
  13. package/dist/es2019/utils/analytics/analytics.js +24 -0
  14. package/dist/es2019/utils/analytics/index.js +1 -1
  15. package/dist/es2019/utils/index.js +16 -1
  16. package/dist/es2019/version.json +1 -1
  17. package/dist/es2019/view/CardWithUrl/loader.js +16 -8
  18. package/dist/es2019/view/HoverCard/components/HoverCardContent.js +6 -1
  19. package/dist/es2019/view/HoverCard/components/views/resolved/index.js +0 -5
  20. package/dist/esm/hoverCard.js +1 -0
  21. package/dist/esm/state/analytics/useSmartLinkAnalytics.js +48 -18
  22. package/dist/esm/utils/analytics/analytics.js +25 -0
  23. package/dist/esm/utils/analytics/index.js +1 -1
  24. package/dist/esm/utils/index.js +56 -1
  25. package/dist/esm/version.json +1 -1
  26. package/dist/esm/view/CardWithUrl/loader.js +19 -9
  27. package/dist/esm/view/HoverCard/components/HoverCardContent.js +6 -1
  28. package/dist/esm/view/HoverCard/components/views/resolved/index.js +0 -5
  29. package/dist/types/hoverCard.d.ts +2 -0
  30. package/dist/types/state/analytics/useSmartLinkAnalytics.d.ts +8 -0
  31. package/dist/types/state/flexible-ui-context/index.d.ts +2 -0
  32. package/dist/types/state/hooks/useSmartLink.d.ts +1 -0
  33. package/dist/types/utils/analytics/analytics.d.ts +1 -0
  34. package/dist/types/utils/analytics/index.d.ts +1 -1
  35. package/dist/types/utils/index.d.ts +2 -0
  36. package/dist/types/utils/mocks.d.ts +1 -0
  37. package/dist/types/utils/types.d.ts +1 -1
  38. package/hover-card/package.json +15 -0
  39. package/package.json +2 -1
  40. package/report.api.md +12 -0
  41. package/tmp/api-report-tmp.d.ts +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/smart-card
2
2
 
3
+ ## 23.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`d88eda329c1`](https://bitbucket.org/atlassian/atlassian-frontend/commits/d88eda329c1) - seperate chunk load errors into it's own analytics event and do retries when lazy loading smartcard-urlcardcontent fails
8
+
9
+ ## 23.10.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`aa44d74bf40`](https://bitbucket.org/atlassian/atlassian-frontend/commits/aa44d74bf40) - Expose a new entry point to hover cards at @atlaskit/smart-card/hover-card
14
+
3
15
  ## 23.9.3
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "HoverCard", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _HoverCard.HoverCard;
10
+ }
11
+ });
12
+
13
+ var _HoverCard = require("./view/HoverCard");
@@ -616,6 +616,36 @@ var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchAnalytic
616
616
  if (event) {
617
617
  dispatchAnalytics(applyCommonAttributes(event, commonAttributes));
618
618
  }
619
+ },
620
+
621
+ /**
622
+ * This fires an event that represents when a Smart Link renders unsuccessfuly.
623
+ * @param display Whether the card was an Inline, Block, Embed or Flexible UI.
624
+ * @param id The unique ID for this Smart Link.
625
+ * @param error: An error representing why the Smart Link render failed.
626
+ * @param errorInfo: Additional details about the error including the stack trace.
627
+ */
628
+ chunkloadFailedEvent: function chunkloadFailedEvent(_ref16) {
629
+ var display = _ref16.display,
630
+ error = _ref16.error,
631
+ errorInfo = _ref16.errorInfo,
632
+ extensionKey = _ref16.extensionKey,
633
+ definitionId = _ref16.definitionId,
634
+ resourceType = _ref16.resourceType,
635
+ destinationProduct = _ref16.destinationProduct,
636
+ destinationSubproduct = _ref16.destinationSubproduct,
637
+ location = _ref16.location;
638
+ dispatchAnalytics(applyCommonAttributes((0, _analytics.chunkloadFailedEvent)({
639
+ display: display,
640
+ error: error,
641
+ errorInfo: errorInfo,
642
+ extensionKey: extensionKey,
643
+ definitionId: definitionId,
644
+ resourceType: resourceType,
645
+ destinationProduct: destinationProduct,
646
+ destinationSubproduct: destinationSubproduct,
647
+ location: location
648
+ }), commonAttributes));
619
649
  }
620
650
  };
621
651
  }, [defaultId, commonAttributes, dispatchAnalytics]);
@@ -629,13 +659,13 @@ var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchAnalytic
629
659
  * @param extensionKey The extensionKey of the Smart Link resovler invoked.
630
660
  * @returns
631
661
  */
632
- appAccountConnected: function appAccountConnected(_ref16) {
633
- var extensionKey = _ref16.extensionKey,
634
- definitionId = _ref16.definitionId,
635
- resourceType = _ref16.resourceType,
636
- destinationProduct = _ref16.destinationProduct,
637
- destinationSubproduct = _ref16.destinationSubproduct,
638
- location = _ref16.location;
662
+ appAccountConnected: function appAccountConnected(_ref17) {
663
+ var extensionKey = _ref17.extensionKey,
664
+ definitionId = _ref17.definitionId,
665
+ resourceType = _ref17.resourceType,
666
+ destinationProduct = _ref17.destinationProduct,
667
+ destinationSubproduct = _ref17.destinationSubproduct,
668
+ location = _ref17.location;
639
669
  return dispatchAnalytics(applyCommonAttributes((0, _analytics.trackAppAccountConnected)(_objectSpread(_objectSpread({}, commonAttributes), {}, {
640
670
  extensionKey: extensionKey,
641
671
  definitionId: definitionId,
@@ -652,9 +682,9 @@ var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchAnalytic
652
682
  * @param extensionKey The extensionKey of the Smart Link resolver invoked.
653
683
  * @returns
654
684
  */
655
- appAccountAuthStarted: function appAccountAuthStarted(_ref17) {
656
- var extensionKey = _ref17.extensionKey,
657
- location = _ref17.location;
685
+ appAccountAuthStarted: function appAccountAuthStarted(_ref18) {
686
+ var extensionKey = _ref18.extensionKey,
687
+ location = _ref18.location;
658
688
  return dispatchAnalytics(applyCommonAttributes((0, _analytics.trackAppAccountAuthStarted)(_objectSpread(_objectSpread({}, commonAttributes), {}, {
659
689
  extensionKey: extensionKey,
660
690
  location: location
@@ -672,13 +702,13 @@ var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchAnalytic
672
702
  * @param extensionKey The extensionKey of the Smart Link resovler invoked.
673
703
  * @returns
674
704
  */
675
- authPopupEvent: function authPopupEvent(_ref18) {
676
- var extensionKey = _ref18.extensionKey,
677
- definitionId = _ref18.definitionId,
678
- resourceType = _ref18.resourceType,
679
- destinationProduct = _ref18.destinationProduct,
680
- destinationSubproduct = _ref18.destinationSubproduct,
681
- location = _ref18.location;
705
+ authPopupEvent: function authPopupEvent(_ref19) {
706
+ var extensionKey = _ref19.extensionKey,
707
+ definitionId = _ref19.definitionId,
708
+ resourceType = _ref19.resourceType,
709
+ destinationProduct = _ref19.destinationProduct,
710
+ destinationSubproduct = _ref19.destinationSubproduct,
711
+ location = _ref19.location;
682
712
  return dispatchAnalytics(applyCommonAttributes((0, _analytics.screenAuthPopupEvent)(_objectSpread(_objectSpread({}, commonAttributes), {}, {
683
713
  extensionKey: extensionKey,
684
714
  definitionId: definitionId,
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.unresolvedEvent = exports.uiRenderSuccessEvent = exports.uiRenderFailedEvent = exports.uiLearnMoreLinkClickedEvent = exports.uiHoverCardViewedEvent = exports.uiHoverCardOpenLinkClickedEvent = exports.uiHoverCardDismissedEvent = exports.uiClosedAuthEvent = exports.uiCardClickedEvent = exports.uiAuthEvent = exports.uiAuthAlternateAccountEvent = exports.uiActionClickedEvent = exports.trackAppAccountConnected = exports.trackAppAccountAuthStarted = exports.screenAuthPopupEvent = exports.resolvedEvent = exports.invokeSucceededEvent = exports.invokeFailedEvent = exports.fireSmartLinkEvent = exports.context = exports.connectSucceededEvent = exports.connectFailedEvent = exports.SmartLinkEvents = exports.ANALYTICS_CHANNEL = void 0;
8
+ exports.unresolvedEvent = exports.uiRenderSuccessEvent = exports.uiRenderFailedEvent = exports.uiLearnMoreLinkClickedEvent = exports.uiHoverCardViewedEvent = exports.uiHoverCardOpenLinkClickedEvent = exports.uiHoverCardDismissedEvent = exports.uiClosedAuthEvent = exports.uiCardClickedEvent = exports.uiAuthEvent = exports.uiAuthAlternateAccountEvent = exports.uiActionClickedEvent = exports.trackAppAccountConnected = exports.trackAppAccountAuthStarted = exports.screenAuthPopupEvent = exports.resolvedEvent = exports.invokeSucceededEvent = exports.invokeFailedEvent = exports.fireSmartLinkEvent = exports.context = exports.connectSucceededEvent = exports.connectFailedEvent = exports.chunkloadFailedEvent = exports.SmartLinkEvents = exports.ANALYTICS_CHANNEL = void 0;
9
9
 
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
 
@@ -584,4 +584,32 @@ var uiLearnMoreLinkClickedEvent = function uiLearnMoreLinkClickedEvent() {
584
584
  };
585
585
  };
586
586
 
587
- exports.uiLearnMoreLinkClickedEvent = uiLearnMoreLinkClickedEvent;
587
+ exports.uiLearnMoreLinkClickedEvent = uiLearnMoreLinkClickedEvent;
588
+
589
+ var chunkloadFailedEvent = function chunkloadFailedEvent(_ref19) {
590
+ var display = _ref19.display,
591
+ error = _ref19.error,
592
+ errorInfo = _ref19.errorInfo,
593
+ extensionKey = _ref19.extensionKey,
594
+ definitionId = _ref19.definitionId,
595
+ destinationProduct = _ref19.destinationProduct,
596
+ destinationSubproduct = _ref19.destinationSubproduct,
597
+ location = _ref19.location;
598
+ return {
599
+ action: 'chunkLoadFailed',
600
+ actionSubject: 'smartLink',
601
+ eventType: 'operational',
602
+ attributes: _objectSpread(_objectSpread({}, context), {}, {
603
+ error: error,
604
+ errorInfo: errorInfo,
605
+ display: display,
606
+ extensionKey: extensionKey,
607
+ definitionId: definitionId,
608
+ destinationProduct: destinationProduct,
609
+ destinationSubproduct: destinationSubproduct,
610
+ location: location
611
+ })
612
+ };
613
+ };
614
+
615
+ exports.chunkloadFailedEvent = chunkloadFailedEvent;
@@ -11,6 +11,12 @@ Object.defineProperty(exports, "ANALYTICS_CHANNEL", {
11
11
  return _analytics.ANALYTICS_CHANNEL;
12
12
  }
13
13
  });
14
+ Object.defineProperty(exports, "chunkloadFailedEvent", {
15
+ enumerable: true,
16
+ get: function get() {
17
+ return _analytics.chunkloadFailedEvent;
18
+ }
19
+ });
14
20
  Object.defineProperty(exports, "connectFailedEvent", {
15
21
  enumerable: true,
16
22
  get: function get() {
@@ -7,7 +7,11 @@ var _typeof = require("@babel/runtime/helpers/typeof");
7
7
  Object.defineProperty(exports, "__esModule", {
8
8
  value: true
9
9
  });
10
- exports.isSpecialKey = exports.isSpecialEvent = exports.isSpecialClick = exports.isIntersectionObserverSupported = exports.isIframe = exports.isCardWithData = exports.handleOnClick = exports.getLabelForFileType = exports.getIframeSandboxAttribute = exports.getIconForFileType = void 0;
10
+ exports.sleep = exports.isSpecialKey = exports.isSpecialEvent = exports.isSpecialClick = exports.isIntersectionObserverSupported = exports.isIframe = exports.isCardWithData = exports.importWithRetry = exports.handleOnClick = exports.getLabelForFileType = exports.getIframeSandboxAttribute = exports.getIconForFileType = void 0;
11
+
12
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
13
+
14
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
15
 
12
16
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
13
17
 
@@ -374,4 +378,63 @@ var isIntersectionObserverSupported = function isIntersectionObserverSupported()
374
378
  return typeof IntersectionObserver !== 'undefined';
375
379
  };
376
380
 
377
- exports.isIntersectionObserverSupported = isIntersectionObserverSupported;
381
+ exports.isIntersectionObserverSupported = isIntersectionObserverSupported;
382
+
383
+ var sleep = function sleep(ms) {
384
+ return new Promise(function (resolve) {
385
+ return setTimeout(resolve, ms);
386
+ });
387
+ };
388
+
389
+ exports.sleep = sleep;
390
+
391
+ var importWithRetry = /*#__PURE__*/function () {
392
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(importFn) {
393
+ var retries,
394
+ interval,
395
+ _args = arguments;
396
+ return _regenerator.default.wrap(function _callee$(_context) {
397
+ while (1) {
398
+ switch (_context.prev = _context.next) {
399
+ case 0:
400
+ retries = _args.length > 1 && _args[1] !== undefined ? _args[1] : 2;
401
+ interval = _args.length > 2 && _args[2] !== undefined ? _args[2] : 500;
402
+ _context.prev = 2;
403
+ _context.next = 5;
404
+ return importFn();
405
+
406
+ case 5:
407
+ return _context.abrupt("return", _context.sent);
408
+
409
+ case 8:
410
+ _context.prev = 8;
411
+ _context.t0 = _context["catch"](2);
412
+
413
+ if (!(_context.t0.name === 'ChunkLoadError' && retries > 0)) {
414
+ _context.next = 16;
415
+ break;
416
+ }
417
+
418
+ _context.next = 13;
419
+ return sleep(interval);
420
+
421
+ case 13:
422
+ return _context.abrupt("return", importWithRetry(importFn, retries - 1, interval));
423
+
424
+ case 16:
425
+ throw _context.t0;
426
+
427
+ case 17:
428
+ case "end":
429
+ return _context.stop();
430
+ }
431
+ }
432
+ }, _callee, null, [[2, 8]]);
433
+ }));
434
+
435
+ return function importWithRetry(_x) {
436
+ return _ref.apply(this, arguments);
437
+ };
438
+ }();
439
+
440
+ exports.importWithRetry = importWithRetry;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "23.9.3",
3
+ "version": "23.10.1",
4
4
  "sideEffects": false
5
5
  }
@@ -25,13 +25,17 @@ var _analytics2 = require("../../state/analytics");
25
25
 
26
26
  var _LazyFallback = require("./component-lazy/LazyFallback");
27
27
 
28
+ var _utils = require("../../utils");
29
+
28
30
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
29
31
 
30
32
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || (0, _typeof2.default)(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
31
33
 
32
34
  var LazyCardWithUrlContent = /*#__PURE__*/(0, _react.lazy)(function () {
33
- return Promise.resolve().then(function () {
34
- return _interopRequireWildcard(require('./component-lazy/index'));
35
+ return (0, _utils.importWithRetry)(function () {
36
+ return Promise.resolve().then(function () {
37
+ return _interopRequireWildcard(require('./component-lazy/index'));
38
+ });
35
39
  });
36
40
  });
37
41
 
@@ -83,15 +87,22 @@ function CardWithURLRenderer(props) {
83
87
  }, [appearance, createAnalyticsEvent]);
84
88
  var analytics = (0, _analytics2.useSmartLinkAnalytics)(url !== null && url !== void 0 ? url : '', dispatchAnalytics, id);
85
89
  var logError = (0, _react.useCallback)(function (error, info) {
86
- var componentStack = info.componentStack; // NB: APIErrors are thrown in response to Object Resolver Service. We do not
90
+ var componentStack = info.componentStack;
91
+ var errorInfo = {
92
+ componentStack: componentStack
93
+ }; // NB: APIErrors are thrown in response to Object Resolver Service. We do not
87
94
  // fire an event for these, as they do not cover failed UI render events.
88
95
  // The rest of the errors caught here are unexpected, and correlate
89
96
  // to the reliability of the smart-card front-end components.
97
+ // Likewise, chunk loading errors are not caused by a failure of smart-card rendering.
90
98
 
91
- if (error.name !== 'APIError') {
92
- var errorInfo = {
93
- componentStack: componentStack
94
- };
99
+ if (error.name === 'ChunkLoadError') {
100
+ analytics.operational.chunkloadFailedEvent({
101
+ display: appearance,
102
+ error: error,
103
+ errorInfo: errorInfo
104
+ });
105
+ } else if (error.name !== 'APIError') {
95
106
  analytics.ui.renderFailedEvent({
96
107
  display: appearance,
97
108
  id: id,
@@ -103,7 +114,7 @@ function CardWithURLRenderer(props) {
103
114
 
104
115
 
105
116
  throw error;
106
- }, [analytics.ui, appearance, id]);
117
+ }, [analytics.operational, analytics.ui, appearance, id]);
107
118
 
108
119
  if (!url) {
109
120
  throw new Error('@atlaskit/smart-card: url property is missing.');
@@ -39,6 +39,8 @@ var _reactIntlNext = require("react-intl-next");
39
39
 
40
40
  var _messages = require("../../../messages");
41
41
 
42
+ var _actions = require("../../../state/actions");
43
+
42
44
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
43
45
 
44
46
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -90,6 +92,10 @@ var HoverCardContent = function HoverCardContent(_ref) {
90
92
  var extensionKey = (0, _react2.useMemo)(function () {
91
93
  return (0, _helpers.getExtensionKey)(cardState.details);
92
94
  }, [cardState.details]);
95
+ var actions = (0, _actions.useSmartCardActions)(id, url, analytics);
96
+ (0, _react2.useEffect)(function () {
97
+ actions.loadMetadata();
98
+ }, [actions]);
93
99
  var onClick = (0, _react2.useCallback)(function (event) {
94
100
  var isModifierKeyPressed = (0, _utils.isSpecialEvent)(event);
95
101
  analytics.ui.cardClickedEvent({
@@ -23,8 +23,6 @@ var _styled = require("./styled");
23
23
 
24
24
  var _FlexibleCard = _interopRequireDefault(require("../../../../FlexibleCard"));
25
25
 
26
- var _actions = require("../../../../../state/actions");
27
-
28
26
  var _utils = require("../../../utils");
29
27
 
30
28
  var _SnippetOrPreview = _interopRequireDefault(require("../../SnippetOrPreview"));
@@ -69,10 +67,6 @@ var HoverCardResolvedView = function HoverCardResolvedView(_ref) {
69
67
  onActionClick = _ref.onActionClick,
70
68
  extensionKey = _ref.extensionKey;
71
69
  var showActionableElement = (0, _linkProvider.useFeatureFlag)('enableActionableElement');
72
- var actions = (0, _actions.useSmartCardActions)(id, url, analytics);
73
- (0, _react.useEffect)(function () {
74
- actions.loadMetadata();
75
- }, [actions]);
76
70
  (0, _react.useEffect)(function () {
77
71
  // Since this hover view is only rendered on resolved status,
78
72
  // there is no need to check for statuses.
@@ -0,0 +1 @@
1
+ export { HoverCard } from './view/HoverCard';
@@ -1,6 +1,6 @@
1
1
  import { useMemo } from 'react';
2
2
  import { getUrl } from '@atlaskit/linking-common';
3
- import { connectFailedEvent, connectSucceededEvent, context, instrumentEvent, invokeFailedEvent, invokeSucceededEvent, screenAuthPopupEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiActionClickedEvent, uiAuthAlternateAccountEvent, uiAuthEvent, uiCardClickedEvent, uiClosedAuthEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiHoverCardViewedEvent, uiLearnMoreLinkClickedEvent, uiRenderFailedEvent, uiRenderSuccessEvent } from '../../utils/analytics';
3
+ import { chunkloadFailedEvent, connectFailedEvent, connectSucceededEvent, context, instrumentEvent, invokeFailedEvent, invokeSucceededEvent, screenAuthPopupEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiActionClickedEvent, uiAuthAlternateAccountEvent, uiAuthEvent, uiCardClickedEvent, uiClosedAuthEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiHoverCardViewedEvent, uiLearnMoreLinkClickedEvent, uiRenderFailedEvent, uiRenderSuccessEvent } from '../../utils/analytics';
4
4
  import { failUfoExperience, startUfoExperience, succeedUfoExperience } from './ufoExperiences';
5
5
  import { getDefinitionId, getExtensionKey, getProduct, getResourceType, getSubproduct } from '../helpers';
6
6
  import { useSmartLinkContext } from '@atlaskit/link-provider';
@@ -586,6 +586,37 @@ export const useSmartLinkAnalytics = (url, dispatchAnalytics, id, defaultLocatio
586
586
  if (event) {
587
587
  dispatchAnalytics(applyCommonAttributes(event, commonAttributes));
588
588
  }
589
+ },
590
+
591
+ /**
592
+ * This fires an event that represents when a Smart Link renders unsuccessfuly.
593
+ * @param display Whether the card was an Inline, Block, Embed or Flexible UI.
594
+ * @param id The unique ID for this Smart Link.
595
+ * @param error: An error representing why the Smart Link render failed.
596
+ * @param errorInfo: Additional details about the error including the stack trace.
597
+ */
598
+ chunkloadFailedEvent: ({
599
+ display,
600
+ error,
601
+ errorInfo,
602
+ extensionKey,
603
+ definitionId,
604
+ resourceType,
605
+ destinationProduct,
606
+ destinationSubproduct,
607
+ location
608
+ }) => {
609
+ dispatchAnalytics(applyCommonAttributes(chunkloadFailedEvent({
610
+ display,
611
+ error,
612
+ errorInfo,
613
+ extensionKey,
614
+ definitionId,
615
+ resourceType,
616
+ destinationProduct,
617
+ destinationSubproduct,
618
+ location
619
+ }), commonAttributes));
589
620
  }
590
621
  }), [defaultId, commonAttributes, dispatchAnalytics]);
591
622
  /** Contains all track analytics events */
@@ -479,4 +479,28 @@ export const uiLearnMoreLinkClickedEvent = () => ({
479
479
  eventType: 'ui',
480
480
  attributes: { ...context
481
481
  }
482
+ });
483
+ export const chunkloadFailedEvent = ({
484
+ display,
485
+ error,
486
+ errorInfo,
487
+ extensionKey,
488
+ definitionId,
489
+ destinationProduct,
490
+ destinationSubproduct,
491
+ location
492
+ }) => ({
493
+ action: 'chunkLoadFailed',
494
+ actionSubject: 'smartLink',
495
+ eventType: 'operational',
496
+ attributes: { ...context,
497
+ error,
498
+ errorInfo,
499
+ display,
500
+ extensionKey,
501
+ definitionId,
502
+ destinationProduct,
503
+ destinationSubproduct,
504
+ location
505
+ }
482
506
  });
@@ -1,6 +1,6 @@
1
1
  import { getMeasure } from '../performance';
2
2
  import { resolvedEvent, unresolvedEvent } from './analytics';
3
- export { ANALYTICS_CHANNEL, context, fireSmartLinkEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, screenAuthPopupEvent, uiRenderSuccessEvent, uiRenderFailedEvent, uiHoverCardViewedEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiLearnMoreLinkClickedEvent } from './analytics';
3
+ export { ANALYTICS_CHANNEL, context, fireSmartLinkEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, chunkloadFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, screenAuthPopupEvent, uiRenderSuccessEvent, uiRenderFailedEvent, uiHoverCardViewedEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiLearnMoreLinkClickedEvent } from './analytics';
4
4
  export const instrumentEvent = ({
5
5
  id,
6
6
  status,
@@ -100,4 +100,19 @@ export const handleOnClick = handler => e => {
100
100
  e.stopPropagation();
101
101
  handler();
102
102
  };
103
- export const isIntersectionObserverSupported = () => typeof IntersectionObserver !== 'undefined';
103
+ export const isIntersectionObserverSupported = () => typeof IntersectionObserver !== 'undefined';
104
+ export const sleep = ms => {
105
+ return new Promise(resolve => setTimeout(resolve, ms));
106
+ };
107
+ export const importWithRetry = async (importFn, retries = 2, interval = 500) => {
108
+ try {
109
+ return await importFn();
110
+ } catch (error) {
111
+ if (error.name === 'ChunkLoadError' && retries > 0) {
112
+ await sleep(interval);
113
+ return importWithRetry(importFn, retries - 1, interval);
114
+ } else {
115
+ throw error;
116
+ }
117
+ }
118
+ };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "23.9.3",
3
+ "version": "23.10.1",
4
4
  "sideEffects": false
5
5
  }
@@ -5,9 +5,10 @@ import { clearMarks, clearMeasures } from '../../utils/performance';
5
5
  import { ErrorBoundary } from 'react-error-boundary';
6
6
  import { useSmartLinkAnalytics } from '../../state/analytics';
7
7
  import { LoadingCardLink } from './component-lazy/LazyFallback';
8
- const LazyCardWithUrlContent = /*#__PURE__*/lazy(() => import(
8
+ import { importWithRetry } from '../../utils';
9
+ const LazyCardWithUrlContent = /*#__PURE__*/lazy(() => importWithRetry(() => import(
9
10
  /* webpackChunkName: "@atlaskit-internal_smartcard-urlcardcontent" */
10
- './component-lazy/index'));
11
+ './component-lazy/index')));
11
12
  export function CardWithURLRenderer(props) {
12
13
  const [id] = useState(() => props.id ? props.id : uuid());
13
14
  useEffect(() => {
@@ -55,15 +56,22 @@ export function CardWithURLRenderer(props) {
55
56
  const logError = useCallback((error, info) => {
56
57
  const {
57
58
  componentStack
58
- } = info; // NB: APIErrors are thrown in response to Object Resolver Service. We do not
59
+ } = info;
60
+ const errorInfo = {
61
+ componentStack
62
+ }; // NB: APIErrors are thrown in response to Object Resolver Service. We do not
59
63
  // fire an event for these, as they do not cover failed UI render events.
60
64
  // The rest of the errors caught here are unexpected, and correlate
61
65
  // to the reliability of the smart-card front-end components.
66
+ // Likewise, chunk loading errors are not caused by a failure of smart-card rendering.
62
67
 
63
- if (error.name !== 'APIError') {
64
- const errorInfo = {
65
- componentStack
66
- };
68
+ if (error.name === 'ChunkLoadError') {
69
+ analytics.operational.chunkloadFailedEvent({
70
+ display: appearance,
71
+ error,
72
+ errorInfo
73
+ });
74
+ } else if (error.name !== 'APIError') {
67
75
  analytics.ui.renderFailedEvent({
68
76
  display: appearance,
69
77
  id,
@@ -75,7 +83,7 @@ export function CardWithURLRenderer(props) {
75
83
 
76
84
 
77
85
  throw error;
78
- }, [analytics.ui, appearance, id]);
86
+ }, [analytics.operational, analytics.ui, appearance, id]);
79
87
 
80
88
  if (!url) {
81
89
  throw new Error('@atlaskit/smart-card: url property is missing.');
@@ -2,7 +2,7 @@
2
2
  import { jsx } from '@emotion/react';
3
3
  import ShortcutIcon from '@atlaskit/icon/glyph/shortcut';
4
4
  import { extractType } from '@atlaskit/linking-common/extractors';
5
- import React, { useCallback, useMemo } from 'react';
5
+ import React, { useCallback, useEffect, useMemo } from 'react';
6
6
  import { ActionName, CardDisplay, SmartLinkPosition, SmartLinkSize } from '../../../constants';
7
7
  import { extractMetadata } from '../../../extractors/hover/extractMetadata';
8
8
  import { getExtensionKey } from '../../../state/helpers';
@@ -14,6 +14,7 @@ import HoverCardUnauthorisedView from './views/unauthorised';
14
14
  import HoverCardResolvedView from './views/resolved';
15
15
  import { FormattedMessage } from 'react-intl-next';
16
16
  import { messages } from '../../../messages';
17
+ import { useSmartCardActions } from '../../../state/actions';
17
18
  export const hoverCardClassName = 'smart-links-hover-preview';
18
19
  export const getOpenAction = (url, analytics, onActionClick) => ({
19
20
  name: ActionName.CustomAction,
@@ -51,6 +52,10 @@ const HoverCardContent = ({
51
52
  var _cardState$details;
52
53
 
53
54
  const extensionKey = useMemo(() => getExtensionKey(cardState.details), [cardState.details]);
55
+ const actions = useSmartCardActions(id, url, analytics);
56
+ useEffect(() => {
57
+ actions.loadMetadata();
58
+ }, [actions]);
54
59
  const onClick = useCallback(event => {
55
60
  const isModifierKeyPressed = isSpecialEvent(event);
56
61
  analytics.ui.cardClickedEvent({
@@ -5,7 +5,6 @@ import { ActionName, CardDisplay, SmartLinkSize } from '../../../../../constants
5
5
  import { FooterBlock, MetadataBlock, SnippetBlock, TitleBlock } from '../../../../FlexibleCard/components/blocks';
6
6
  import { footerBlockCss, hiddenSnippetStyles, metadataBlockCss } from './styled';
7
7
  import FlexibleCard from '../../../../FlexibleCard';
8
- import { useSmartCardActions } from '../../../../../state/actions';
9
8
  import { getSimulatedMetadata, toActionableMetadata } from '../../../utils';
10
9
  import SnippetOrPreview from '../../SnippetOrPreview';
11
10
  import { extractMetadata } from '../../../../../extractors/hover/extractMetadata';
@@ -36,10 +35,6 @@ const HoverCardResolvedView = ({
36
35
  var _cardState$details;
37
36
 
38
37
  const showActionableElement = useFeatureFlag('enableActionableElement');
39
- const actions = useSmartCardActions(id, url, analytics);
40
- useEffect(() => {
41
- actions.loadMetadata();
42
- }, [actions]);
43
38
  useEffect(() => {
44
39
  // Since this hover view is only rendered on resolved status,
45
40
  // there is no need to check for statuses.
@@ -0,0 +1 @@
1
+ export { HoverCard } from './view/HoverCard';
@@ -7,7 +7,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
7
7
 
8
8
  import { useMemo } from 'react';
9
9
  import { getUrl } from '@atlaskit/linking-common';
10
- import { connectFailedEvent as _connectFailedEvent, connectSucceededEvent as _connectSucceededEvent, context, instrumentEvent, invokeFailedEvent as _invokeFailedEvent, invokeSucceededEvent as _invokeSucceededEvent, screenAuthPopupEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiActionClickedEvent, uiAuthAlternateAccountEvent, uiAuthEvent, uiCardClickedEvent, uiClosedAuthEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiHoverCardViewedEvent, uiLearnMoreLinkClickedEvent, uiRenderFailedEvent, uiRenderSuccessEvent } from '../../utils/analytics';
10
+ import { chunkloadFailedEvent as _chunkloadFailedEvent, connectFailedEvent as _connectFailedEvent, connectSucceededEvent as _connectSucceededEvent, context, instrumentEvent, invokeFailedEvent as _invokeFailedEvent, invokeSucceededEvent as _invokeSucceededEvent, screenAuthPopupEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiActionClickedEvent, uiAuthAlternateAccountEvent, uiAuthEvent, uiCardClickedEvent, uiClosedAuthEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiHoverCardViewedEvent, uiLearnMoreLinkClickedEvent, uiRenderFailedEvent, uiRenderSuccessEvent } from '../../utils/analytics';
11
11
  import { failUfoExperience, startUfoExperience, succeedUfoExperience } from './ufoExperiences';
12
12
  import { getDefinitionId, getExtensionKey, getProduct, getResourceType, getSubproduct } from '../helpers';
13
13
  import { useSmartLinkContext } from '@atlaskit/link-provider';
@@ -601,6 +601,36 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchA
601
601
  if (event) {
602
602
  dispatchAnalytics(applyCommonAttributes(event, commonAttributes));
603
603
  }
604
+ },
605
+
606
+ /**
607
+ * This fires an event that represents when a Smart Link renders unsuccessfuly.
608
+ * @param display Whether the card was an Inline, Block, Embed or Flexible UI.
609
+ * @param id The unique ID for this Smart Link.
610
+ * @param error: An error representing why the Smart Link render failed.
611
+ * @param errorInfo: Additional details about the error including the stack trace.
612
+ */
613
+ chunkloadFailedEvent: function chunkloadFailedEvent(_ref16) {
614
+ var display = _ref16.display,
615
+ error = _ref16.error,
616
+ errorInfo = _ref16.errorInfo,
617
+ extensionKey = _ref16.extensionKey,
618
+ definitionId = _ref16.definitionId,
619
+ resourceType = _ref16.resourceType,
620
+ destinationProduct = _ref16.destinationProduct,
621
+ destinationSubproduct = _ref16.destinationSubproduct,
622
+ location = _ref16.location;
623
+ dispatchAnalytics(applyCommonAttributes(_chunkloadFailedEvent({
624
+ display: display,
625
+ error: error,
626
+ errorInfo: errorInfo,
627
+ extensionKey: extensionKey,
628
+ definitionId: definitionId,
629
+ resourceType: resourceType,
630
+ destinationProduct: destinationProduct,
631
+ destinationSubproduct: destinationSubproduct,
632
+ location: location
633
+ }), commonAttributes));
604
634
  }
605
635
  };
606
636
  }, [defaultId, commonAttributes, dispatchAnalytics]);
@@ -614,13 +644,13 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchA
614
644
  * @param extensionKey The extensionKey of the Smart Link resovler invoked.
615
645
  * @returns
616
646
  */
617
- appAccountConnected: function appAccountConnected(_ref16) {
618
- var extensionKey = _ref16.extensionKey,
619
- definitionId = _ref16.definitionId,
620
- resourceType = _ref16.resourceType,
621
- destinationProduct = _ref16.destinationProduct,
622
- destinationSubproduct = _ref16.destinationSubproduct,
623
- location = _ref16.location;
647
+ appAccountConnected: function appAccountConnected(_ref17) {
648
+ var extensionKey = _ref17.extensionKey,
649
+ definitionId = _ref17.definitionId,
650
+ resourceType = _ref17.resourceType,
651
+ destinationProduct = _ref17.destinationProduct,
652
+ destinationSubproduct = _ref17.destinationSubproduct,
653
+ location = _ref17.location;
624
654
  return dispatchAnalytics(applyCommonAttributes(trackAppAccountConnected(_objectSpread(_objectSpread({}, commonAttributes), {}, {
625
655
  extensionKey: extensionKey,
626
656
  definitionId: definitionId,
@@ -637,9 +667,9 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchA
637
667
  * @param extensionKey The extensionKey of the Smart Link resolver invoked.
638
668
  * @returns
639
669
  */
640
- appAccountAuthStarted: function appAccountAuthStarted(_ref17) {
641
- var extensionKey = _ref17.extensionKey,
642
- location = _ref17.location;
670
+ appAccountAuthStarted: function appAccountAuthStarted(_ref18) {
671
+ var extensionKey = _ref18.extensionKey,
672
+ location = _ref18.location;
643
673
  return dispatchAnalytics(applyCommonAttributes(trackAppAccountAuthStarted(_objectSpread(_objectSpread({}, commonAttributes), {}, {
644
674
  extensionKey: extensionKey,
645
675
  location: location
@@ -657,13 +687,13 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, dispatchA
657
687
  * @param extensionKey The extensionKey of the Smart Link resovler invoked.
658
688
  * @returns
659
689
  */
660
- authPopupEvent: function authPopupEvent(_ref18) {
661
- var extensionKey = _ref18.extensionKey,
662
- definitionId = _ref18.definitionId,
663
- resourceType = _ref18.resourceType,
664
- destinationProduct = _ref18.destinationProduct,
665
- destinationSubproduct = _ref18.destinationSubproduct,
666
- location = _ref18.location;
690
+ authPopupEvent: function authPopupEvent(_ref19) {
691
+ var extensionKey = _ref19.extensionKey,
692
+ definitionId = _ref19.definitionId,
693
+ resourceType = _ref19.resourceType,
694
+ destinationProduct = _ref19.destinationProduct,
695
+ destinationSubproduct = _ref19.destinationSubproduct,
696
+ location = _ref19.location;
667
697
  return dispatchAnalytics(applyCommonAttributes(screenAuthPopupEvent(_objectSpread(_objectSpread({}, commonAttributes), {}, {
668
698
  extensionKey: extensionKey,
669
699
  definitionId: definitionId,
@@ -504,4 +504,29 @@ export var uiLearnMoreLinkClickedEvent = function uiLearnMoreLinkClickedEvent()
504
504
  eventType: 'ui',
505
505
  attributes: _objectSpread({}, context)
506
506
  };
507
+ };
508
+ export var chunkloadFailedEvent = function chunkloadFailedEvent(_ref19) {
509
+ var display = _ref19.display,
510
+ error = _ref19.error,
511
+ errorInfo = _ref19.errorInfo,
512
+ extensionKey = _ref19.extensionKey,
513
+ definitionId = _ref19.definitionId,
514
+ destinationProduct = _ref19.destinationProduct,
515
+ destinationSubproduct = _ref19.destinationSubproduct,
516
+ location = _ref19.location;
517
+ return {
518
+ action: 'chunkLoadFailed',
519
+ actionSubject: 'smartLink',
520
+ eventType: 'operational',
521
+ attributes: _objectSpread(_objectSpread({}, context), {}, {
522
+ error: error,
523
+ errorInfo: errorInfo,
524
+ display: display,
525
+ extensionKey: extensionKey,
526
+ definitionId: definitionId,
527
+ destinationProduct: destinationProduct,
528
+ destinationSubproduct: destinationSubproduct,
529
+ location: location
530
+ })
531
+ };
507
532
  };
@@ -6,7 +6,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
6
6
 
7
7
  import { getMeasure } from '../performance';
8
8
  import { resolvedEvent, unresolvedEvent } from './analytics';
9
- export { ANALYTICS_CHANNEL, context, fireSmartLinkEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, screenAuthPopupEvent, uiRenderSuccessEvent, uiRenderFailedEvent, uiHoverCardViewedEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiLearnMoreLinkClickedEvent } from './analytics';
9
+ export { ANALYTICS_CHANNEL, context, fireSmartLinkEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, chunkloadFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, screenAuthPopupEvent, uiRenderSuccessEvent, uiRenderFailedEvent, uiHoverCardViewedEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiLearnMoreLinkClickedEvent } from './analytics';
10
10
  export var instrumentEvent = function instrumentEvent(_ref) {
11
11
  var id = _ref.id,
12
12
  status = _ref.status,
@@ -1,4 +1,6 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
1
2
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
2
4
  import React from 'react';
3
5
  import Loadable from 'react-loadable';
4
6
  export var isCardWithData = function isCardWithData(props) {
@@ -227,4 +229,57 @@ export var handleOnClick = function handleOnClick(handler) {
227
229
  };
228
230
  export var isIntersectionObserverSupported = function isIntersectionObserverSupported() {
229
231
  return typeof IntersectionObserver !== 'undefined';
230
- };
232
+ };
233
+ export var sleep = function sleep(ms) {
234
+ return new Promise(function (resolve) {
235
+ return setTimeout(resolve, ms);
236
+ });
237
+ };
238
+ export var importWithRetry = /*#__PURE__*/function () {
239
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(importFn) {
240
+ var retries,
241
+ interval,
242
+ _args = arguments;
243
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
244
+ while (1) {
245
+ switch (_context.prev = _context.next) {
246
+ case 0:
247
+ retries = _args.length > 1 && _args[1] !== undefined ? _args[1] : 2;
248
+ interval = _args.length > 2 && _args[2] !== undefined ? _args[2] : 500;
249
+ _context.prev = 2;
250
+ _context.next = 5;
251
+ return importFn();
252
+
253
+ case 5:
254
+ return _context.abrupt("return", _context.sent);
255
+
256
+ case 8:
257
+ _context.prev = 8;
258
+ _context.t0 = _context["catch"](2);
259
+
260
+ if (!(_context.t0.name === 'ChunkLoadError' && retries > 0)) {
261
+ _context.next = 16;
262
+ break;
263
+ }
264
+
265
+ _context.next = 13;
266
+ return sleep(interval);
267
+
268
+ case 13:
269
+ return _context.abrupt("return", importWithRetry(importFn, retries - 1, interval));
270
+
271
+ case 16:
272
+ throw _context.t0;
273
+
274
+ case 17:
275
+ case "end":
276
+ return _context.stop();
277
+ }
278
+ }
279
+ }, _callee, null, [[2, 8]]);
280
+ }));
281
+
282
+ return function importWithRetry(_x) {
283
+ return _ref.apply(this, arguments);
284
+ };
285
+ }();
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "23.9.3",
3
+ "version": "23.10.1",
4
4
  "sideEffects": false
5
5
  }
@@ -6,10 +6,13 @@ import { clearMarks, clearMeasures } from '../../utils/performance';
6
6
  import { ErrorBoundary } from 'react-error-boundary';
7
7
  import { useSmartLinkAnalytics } from '../../state/analytics';
8
8
  import { LoadingCardLink } from './component-lazy/LazyFallback';
9
+ import { importWithRetry } from '../../utils';
9
10
  var LazyCardWithUrlContent = /*#__PURE__*/lazy(function () {
10
- return import(
11
- /* webpackChunkName: "@atlaskit-internal_smartcard-urlcardcontent" */
12
- './component-lazy/index');
11
+ return importWithRetry(function () {
12
+ return import(
13
+ /* webpackChunkName: "@atlaskit-internal_smartcard-urlcardcontent" */
14
+ './component-lazy/index');
15
+ });
13
16
  });
14
17
  export function CardWithURLRenderer(props) {
15
18
  var _useState = useState(function () {
@@ -59,15 +62,22 @@ export function CardWithURLRenderer(props) {
59
62
  }, [appearance, createAnalyticsEvent]);
60
63
  var analytics = useSmartLinkAnalytics(url !== null && url !== void 0 ? url : '', dispatchAnalytics, id);
61
64
  var logError = useCallback(function (error, info) {
62
- var componentStack = info.componentStack; // NB: APIErrors are thrown in response to Object Resolver Service. We do not
65
+ var componentStack = info.componentStack;
66
+ var errorInfo = {
67
+ componentStack: componentStack
68
+ }; // NB: APIErrors are thrown in response to Object Resolver Service. We do not
63
69
  // fire an event for these, as they do not cover failed UI render events.
64
70
  // The rest of the errors caught here are unexpected, and correlate
65
71
  // to the reliability of the smart-card front-end components.
72
+ // Likewise, chunk loading errors are not caused by a failure of smart-card rendering.
66
73
 
67
- if (error.name !== 'APIError') {
68
- var errorInfo = {
69
- componentStack: componentStack
70
- };
74
+ if (error.name === 'ChunkLoadError') {
75
+ analytics.operational.chunkloadFailedEvent({
76
+ display: appearance,
77
+ error: error,
78
+ errorInfo: errorInfo
79
+ });
80
+ } else if (error.name !== 'APIError') {
71
81
  analytics.ui.renderFailedEvent({
72
82
  display: appearance,
73
83
  id: id,
@@ -79,7 +89,7 @@ export function CardWithURLRenderer(props) {
79
89
 
80
90
 
81
91
  throw error;
82
- }, [analytics.ui, appearance, id]);
92
+ }, [analytics.operational, analytics.ui, appearance, id]);
83
93
 
84
94
  if (!url) {
85
95
  throw new Error('@atlaskit/smart-card: url property is missing.');
@@ -2,7 +2,7 @@
2
2
  import { jsx } from '@emotion/react';
3
3
  import ShortcutIcon from '@atlaskit/icon/glyph/shortcut';
4
4
  import { extractType } from '@atlaskit/linking-common/extractors';
5
- import React, { useCallback, useMemo } from 'react';
5
+ import React, { useCallback, useEffect, useMemo } from 'react';
6
6
  import { ActionName, CardDisplay, SmartLinkPosition, SmartLinkSize } from '../../../constants';
7
7
  import { extractMetadata } from '../../../extractors/hover/extractMetadata';
8
8
  import { getExtensionKey } from '../../../state/helpers';
@@ -14,6 +14,7 @@ import HoverCardUnauthorisedView from './views/unauthorised';
14
14
  import HoverCardResolvedView from './views/resolved';
15
15
  import { FormattedMessage } from 'react-intl-next';
16
16
  import { messages } from '../../../messages';
17
+ import { useSmartCardActions } from '../../../state/actions';
17
18
  export var hoverCardClassName = 'smart-links-hover-preview';
18
19
  export var getOpenAction = function getOpenAction(url, analytics, onActionClick) {
19
20
  return {
@@ -56,6 +57,10 @@ var HoverCardContent = function HoverCardContent(_ref) {
56
57
  var extensionKey = useMemo(function () {
57
58
  return getExtensionKey(cardState.details);
58
59
  }, [cardState.details]);
60
+ var actions = useSmartCardActions(id, url, analytics);
61
+ useEffect(function () {
62
+ actions.loadMetadata();
63
+ }, [actions]);
59
64
  var onClick = useCallback(function (event) {
60
65
  var isModifierKeyPressed = isSpecialEvent(event);
61
66
  analytics.ui.cardClickedEvent({
@@ -5,7 +5,6 @@ import { ActionName, CardDisplay, SmartLinkSize } from '../../../../../constants
5
5
  import { FooterBlock, MetadataBlock, SnippetBlock, TitleBlock } from '../../../../FlexibleCard/components/blocks';
6
6
  import { footerBlockCss, hiddenSnippetStyles, metadataBlockCss } from './styled';
7
7
  import FlexibleCard from '../../../../FlexibleCard';
8
- import { useSmartCardActions } from '../../../../../state/actions';
9
8
  import { getSimulatedMetadata, toActionableMetadata } from '../../../utils';
10
9
  import SnippetOrPreview from '../../SnippetOrPreview';
11
10
  import { extractMetadata } from '../../../../../extractors/hover/extractMetadata';
@@ -41,10 +40,6 @@ var HoverCardResolvedView = function HoverCardResolvedView(_ref) {
41
40
  onActionClick = _ref.onActionClick,
42
41
  extensionKey = _ref.extensionKey;
43
42
  var showActionableElement = useFeatureFlag('enableActionableElement');
44
- var actions = useSmartCardActions(id, url, analytics);
45
- useEffect(function () {
46
- actions.loadMetadata();
47
- }, [actions]);
48
43
  useEffect(function () {
49
44
  // Since this hover view is only rendered on resolved status,
50
45
  // there is no need to check for statuses.
@@ -0,0 +1,2 @@
1
+ export { HoverCard } from './view/HoverCard';
2
+ export type { HoverCardProps } from './view/HoverCard/types';
@@ -171,6 +171,14 @@ export declare const useSmartLinkAnalytics: (url: string, dispatchAnalytics: Ana
171
171
  * @param error An error representing why the Smart Link request failed.
172
172
  */
173
173
  instrument: ({ id, status, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, error, }: InstrumentEventProps) => void;
174
+ /**
175
+ * This fires an event that represents when a Smart Link renders unsuccessfuly.
176
+ * @param display Whether the card was an Inline, Block, Embed or Flexible UI.
177
+ * @param id The unique ID for this Smart Link.
178
+ * @param error: An error representing why the Smart Link render failed.
179
+ * @param errorInfo: Additional details about the error including the stack trace.
180
+ */
181
+ chunkloadFailedEvent: ({ display, error, errorInfo, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: UiRenderFailedEventProps) => void;
174
182
  };
175
183
  track: {
176
184
  /**
@@ -36,6 +36,7 @@ export declare const FlexibleUiAnalyticsContext: import("react").Context<{
36
36
  connectSucceededEvent: ({ id, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").ConnectSucceededEventProps) => void;
37
37
  connectFailedEvent: ({ id, reason, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").ConnectFailedEventProps) => void;
38
38
  instrument: ({ id, status, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, error, }: import("../../utils/analytics/types").InstrumentEventProps) => void;
39
+ chunkloadFailedEvent: ({ display, error, errorInfo, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").UiRenderFailedEventProps) => void;
39
40
  };
40
41
  track: {
41
42
  appAccountConnected: ({ extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").CommonEventProps) => void;
@@ -74,6 +75,7 @@ export declare const useFlexibleUiAnalyticsContext: () => {
74
75
  connectSucceededEvent: ({ id, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").ConnectSucceededEventProps) => void;
75
76
  connectFailedEvent: ({ id, reason, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").ConnectFailedEventProps) => void;
76
77
  instrument: ({ id, status, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, error, }: import("../../utils/analytics/types").InstrumentEventProps) => void;
78
+ chunkloadFailedEvent: ({ display, error, errorInfo, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").UiRenderFailedEventProps) => void;
77
79
  };
78
80
  track: {
79
81
  appAccountConnected: ({ extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").CommonEventProps) => void;
@@ -35,6 +35,7 @@ export declare function useSmartLink(id: string, url: string, dispatchAnalytics:
35
35
  connectSucceededEvent: ({ id, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").ConnectSucceededEventProps) => void;
36
36
  connectFailedEvent: ({ id, reason, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").ConnectFailedEventProps) => void;
37
37
  instrument: ({ id, status, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, error, }: import("../../utils/analytics/types").InstrumentEventProps) => void;
38
+ chunkloadFailedEvent: ({ display, error, errorInfo, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").UiRenderFailedEventProps) => void;
38
39
  };
39
40
  track: {
40
41
  appAccountConnected: ({ extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("../../utils/analytics/types").CommonEventProps) => void;
@@ -32,3 +32,4 @@ export declare const uiHoverCardViewedEvent: ({ id, previewDisplay, extensionKey
32
32
  export declare const uiHoverCardDismissedEvent: ({ id, previewDisplay, hoverTime, extensionKey, definitionId, destinationProduct, destinationSubproduct, location, previewInvokeMethod, status, }: UiHoverCardDismissedEventProps) => AnalyticsPayload;
33
33
  export declare const uiHoverCardOpenLinkClickedEvent: ({ id, previewDisplay, extensionKey, definitionId, destinationProduct, destinationSubproduct, location, previewInvokeMethod, }: UiHoverCardOpenLinkClickedEventProps) => AnalyticsPayload;
34
34
  export declare const uiLearnMoreLinkClickedEvent: () => AnalyticsPayload;
35
+ export declare const chunkloadFailedEvent: ({ display, error, errorInfo, extensionKey, definitionId, destinationProduct, destinationSubproduct, location, }: UiRenderFailedEventProps) => AnalyticsPayload;
@@ -1,4 +1,4 @@
1
1
  import { AnalyticsPayload } from '../types';
2
2
  import { InstrumentEventProps } from './types';
3
- export { ANALYTICS_CHANNEL, context, fireSmartLinkEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, screenAuthPopupEvent, uiRenderSuccessEvent, uiRenderFailedEvent, uiHoverCardViewedEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiLearnMoreLinkClickedEvent, } from './analytics';
3
+ export { ANALYTICS_CHANNEL, context, fireSmartLinkEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, chunkloadFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountAuthStarted, trackAppAccountConnected, uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, screenAuthPopupEvent, uiRenderSuccessEvent, uiRenderFailedEvent, uiHoverCardViewedEvent, uiHoverCardDismissedEvent, uiHoverCardOpenLinkClickedEvent, uiLearnMoreLinkClickedEvent, } from './analytics';
4
4
  export declare const instrumentEvent: ({ id, status, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, error, }: InstrumentEventProps) => AnalyticsPayload | undefined;
@@ -10,3 +10,5 @@ export declare const getLabelForFileType: (fileMimeType: string) => React.ReactN
10
10
  export declare const getIframeSandboxAttribute: (isTrusted: boolean) => "allow-downloads allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts" | undefined;
11
11
  export declare const handleOnClick: (handler: Function) => (e: React.BaseSyntheticEvent) => void;
12
12
  export declare const isIntersectionObserverSupported: () => boolean;
13
+ export declare const sleep: (ms: number) => Promise<void>;
14
+ export declare const importWithRetry: <T>(importFn: () => Promise<T>, retries?: number, interval?: number) => Promise<T>;
@@ -65,6 +65,7 @@ export declare const mockAnalytics: {
65
65
  connectSucceededEvent: ({ id, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("./analytics/types").ConnectSucceededEventProps) => void;
66
66
  connectFailedEvent: ({ id, reason, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("./analytics/types").ConnectFailedEventProps) => void;
67
67
  instrument: ({ id, status, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, error, }: import("./analytics/types").InstrumentEventProps) => void;
68
+ chunkloadFailedEvent: ({ display, error, errorInfo, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("./analytics/types").UiRenderFailedEventProps) => void;
68
69
  };
69
70
  track: {
70
71
  appAccountConnected: ({ extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: import("./analytics/types").CommonEventProps) => void;
@@ -1,6 +1,6 @@
1
1
  import { GasPayload } from '@atlaskit/analytics-gas-types';
2
2
  import { CardInnerAppearance } from '../view/Card/types';
3
- export declare type AnalyticsAction = 'authStarted' | 'clicked' | 'closed' | 'connected' | 'connectFailed' | 'connectSucceeded' | 'created' | 'dismissed' | 'inserted' | 'renderFailed' | 'renderSuccess' | 'renderWithStatus' | 'resolved' | 'viewed' | 'unresolved';
3
+ export declare type AnalyticsAction = 'authStarted' | 'clicked' | 'closed' | 'connected' | 'connectFailed' | 'connectSucceeded' | 'created' | 'dismissed' | 'inserted' | 'renderFailed' | 'renderSuccess' | 'renderWithStatus' | 'resolved' | 'viewed' | 'unresolved' | 'chunkLoadFailed';
4
4
  export declare type AnalyticsActionSubject = 'smartLink' | 'smartLinkAction' | 'applicationAccount' | 'button' | 'consentModal' | 'hoverCard' | 'modal' | 'embedPreviewModal';
5
5
  export declare type AnalyticsName = 'embedPreviewModal';
6
6
  export declare type AnalyticsOrigin = 'smartLinkCard' | 'smartLinkEmbed' | 'smartLinkInline' | 'smartLinkPreviewHoverCard';
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@atlaskit/smart-card/hover-card",
3
+ "main": "../dist/cjs/hoverCard.js",
4
+ "module": "../dist/esm/hoverCard.js",
5
+ "module:es2019": "../dist/es2019/hoverCard.js",
6
+ "sideEffects": false,
7
+ "types": "../dist/types/hoverCard.d.ts",
8
+ "typesVersions": {
9
+ ">=4.0 <4.5": {
10
+ "*": [
11
+ "../dist/types-ts4.0/hoverCard.d.ts"
12
+ ]
13
+ }
14
+ }
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "23.9.3",
3
+ "version": "23.10.1",
4
4
  "description": "Smart card component",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -119,6 +119,7 @@
119
119
  "./client": "./src/client/index.ts",
120
120
  "./types": "./src/types.ts",
121
121
  "./hooks": "./src/hooks.ts",
122
+ "./hover-card": "./src/hoverCard.ts",
122
123
  ".": "./src/index.ts"
123
124
  },
124
125
  "prettier": "@atlassian/atlassian-frontend-prettier-config-1.0.1",
package/report.api.md CHANGED
@@ -86,6 +86,7 @@ type ActionProps = {
86
86
  // @public (undocumented)
87
87
  export type AnalyticsAction =
88
88
  | 'authStarted'
89
+ | 'chunkLoadFailed'
89
90
  | 'clicked'
90
91
  | 'closed'
91
92
  | 'connectFailed'
@@ -1097,6 +1098,17 @@ export const useSmartLinkAnalytics: (
1097
1098
  location,
1098
1099
  error,
1099
1100
  }: InstrumentEventProps) => void;
1101
+ chunkloadFailedEvent: ({
1102
+ display,
1103
+ error,
1104
+ errorInfo,
1105
+ extensionKey,
1106
+ definitionId,
1107
+ resourceType,
1108
+ destinationProduct,
1109
+ destinationSubproduct,
1110
+ location,
1111
+ }: UiRenderFailedEventProps) => void;
1100
1112
  };
1101
1113
  track: {
1102
1114
  appAccountConnected: ({
@@ -70,7 +70,7 @@ type ActionProps = {
70
70
  };
71
71
 
72
72
  // @public (undocumented)
73
- export type AnalyticsAction = 'authStarted' | 'clicked' | 'closed' | 'connectFailed' | 'connectSucceeded' | 'connected' | 'created' | 'dismissed' | 'inserted' | 'renderFailed' | 'renderSuccess' | 'renderWithStatus' | 'resolved' | 'unresolved' | 'viewed';
73
+ export type AnalyticsAction = 'authStarted' | 'chunkLoadFailed' | 'clicked' | 'closed' | 'connectFailed' | 'connectSucceeded' | 'connected' | 'created' | 'dismissed' | 'inserted' | 'renderFailed' | 'renderSuccess' | 'renderWithStatus' | 'resolved' | 'unresolved' | 'viewed';
74
74
 
75
75
  // @public (undocumented)
76
76
  export type AnalyticsActionSubject = 'applicationAccount' | 'button' | 'consentModal' | 'embedPreviewModal' | 'hoverCard' | 'modal' | 'smartLink' | 'smartLinkAction';
@@ -815,6 +815,7 @@ export const useSmartLinkAnalytics: (url: string, dispatchAnalytics: AnalyticsHa
815
815
  connectSucceededEvent: ({ id, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: ConnectSucceededEventProps) => void;
816
816
  connectFailedEvent: ({ id, reason, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: ConnectFailedEventProps) => void;
817
817
  instrument: ({ id, status, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, error, }: InstrumentEventProps) => void;
818
+ chunkloadFailedEvent: ({ display, error, errorInfo, extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: UiRenderFailedEventProps) => void;
818
819
  };
819
820
  track: {
820
821
  appAccountConnected: ({ extensionKey, definitionId, resourceType, destinationProduct, destinationSubproduct, location, }: TrackAppAccountConnectedProps) => void;