@atlaskit/smart-card 16.0.0 → 16.2.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 (54) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/cjs/client/utils/environments.js +1 -1
  3. package/dist/cjs/extractors/block/index.js +4 -4
  4. package/dist/cjs/extractors/common/actions/extractPreviewAction.js +4 -3
  5. package/dist/cjs/providers/editor/transformer.js +1 -1
  6. package/dist/cjs/state/actions/index.js +13 -6
  7. package/dist/cjs/state/analytics/index.js +32 -84
  8. package/dist/cjs/state/analytics/ufoExperiences.js +60 -0
  9. package/dist/cjs/state/analytics/useSmartLinkAnalytics.js +106 -0
  10. package/dist/cjs/state/hooks/useSmartLink.js +6 -6
  11. package/dist/cjs/version.json +1 -1
  12. package/dist/cjs/view/BlockCard/index.js +3 -2
  13. package/dist/cjs/view/CardWithUrl/component-lazy/index.js +1 -1
  14. package/dist/cjs/view/CardWithUrl/component.js +10 -4
  15. package/dist/cjs/view/CardWithUrl/loader.js +106 -134
  16. package/dist/es2019/client/utils/environments.js +1 -1
  17. package/dist/es2019/extractors/block/index.js +4 -4
  18. package/dist/es2019/extractors/common/actions/extractPreviewAction.js +4 -4
  19. package/dist/es2019/providers/editor/transformer.js +1 -1
  20. package/dist/es2019/state/actions/index.js +9 -4
  21. package/dist/es2019/state/analytics/index.js +2 -40
  22. package/dist/es2019/state/analytics/ufoExperiences.js +40 -0
  23. package/dist/es2019/state/analytics/useSmartLinkAnalytics.js +62 -0
  24. package/dist/es2019/state/hooks/useSmartLink.js +4 -5
  25. package/dist/es2019/version.json +1 -1
  26. package/dist/es2019/view/BlockCard/index.js +3 -2
  27. package/dist/es2019/view/CardWithUrl/component-lazy/index.js +1 -1
  28. package/dist/es2019/view/CardWithUrl/component.js +10 -4
  29. package/dist/es2019/view/CardWithUrl/loader.js +83 -92
  30. package/dist/esm/client/utils/environments.js +1 -1
  31. package/dist/esm/extractors/block/index.js +4 -4
  32. package/dist/esm/extractors/common/actions/extractPreviewAction.js +4 -3
  33. package/dist/esm/providers/editor/transformer.js +1 -1
  34. package/dist/esm/state/actions/index.js +12 -6
  35. package/dist/esm/state/analytics/index.js +2 -80
  36. package/dist/esm/state/analytics/ufoExperiences.js +40 -0
  37. package/dist/esm/state/analytics/useSmartLinkAnalytics.js +94 -0
  38. package/dist/esm/state/hooks/useSmartLink.js +6 -6
  39. package/dist/esm/version.json +1 -1
  40. package/dist/esm/view/BlockCard/index.js +3 -2
  41. package/dist/esm/view/CardWithUrl/component-lazy/index.js +1 -1
  42. package/dist/esm/view/CardWithUrl/component.js +10 -4
  43. package/dist/esm/view/CardWithUrl/loader.js +101 -130
  44. package/dist/types/extractors/block/index.d.ts +2 -2
  45. package/dist/types/extractors/common/__mocks__/jsonld.d.ts +61 -0
  46. package/dist/types/extractors/common/actions/extractPreviewAction.d.ts +1 -1
  47. package/dist/types/state/analytics/index.d.ts +3 -32
  48. package/dist/types/state/analytics/ufoExperiences.d.ts +7 -0
  49. package/dist/types/state/analytics/useSmartLinkAnalytics.d.ts +30 -0
  50. package/dist/types/state/hooks/useSmartLink.d.ts +4 -5
  51. package/dist/types/view/BlockCard/types.d.ts +2 -1
  52. package/dist/types/view/CardWithUrl/component-lazy/index.d.ts +1 -1
  53. package/dist/types/view/CardWithUrl/loader.d.ts +1 -15
  54. package/package.json +13 -11
@@ -2,28 +2,16 @@
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
- var _typeof = require("@babel/runtime/helpers/typeof");
6
-
7
5
  Object.defineProperty(exports, "__esModule", {
8
6
  value: true
9
7
  });
10
- exports.CardWithURLRenderer = void 0;
11
-
12
- var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13
-
14
- var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
15
-
16
- var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
17
-
18
- var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
19
-
20
- var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
8
+ exports.CardWithURLRenderer = CardWithURLRenderer;
21
9
 
22
- var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
10
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
23
11
 
24
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
12
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
25
13
 
26
- var _react = _interopRequireDefault(require("react"));
14
+ var _react = _interopRequireWildcard(require("react"));
27
15
 
28
16
  var _uuid = _interopRequireDefault(require("uuid"));
29
17
 
@@ -33,132 +21,116 @@ var _analytics = require("../../utils/analytics");
33
21
 
34
22
  var _performance = require("../../utils/performance");
35
23
 
36
- 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); }
37
-
38
- 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; }
39
-
40
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
41
-
42
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
24
+ var _reactErrorBoundary = require("react-error-boundary");
43
25
 
44
- var CardWithURLRenderer = /*#__PURE__*/function (_React$PureComponent) {
45
- (0, _inherits2.default)(CardWithURLRenderer, _React$PureComponent);
26
+ var _ufoExperiences = require("../../state/analytics/ufoExperiences");
46
27
 
47
- var _super = _createSuper(CardWithURLRenderer);
48
-
49
- function CardWithURLRenderer(props) {
50
- var _this;
28
+ 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); }
51
29
 
52
- (0, _classCallCheck2.default)(this, CardWithURLRenderer);
53
- _this = _super.call(this, props);
54
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "dispatchAnalytics", function (analyticsPayload) {
55
- var _this$props = _this.props,
56
- appearance = _this$props.appearance,
57
- createAnalyticsEvent = _this$props.createAnalyticsEvent;
30
+ 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; }
58
31
 
59
- if (analyticsPayload && analyticsPayload.attributes) {
60
- // Update if we haven't already set the display - possible
61
- // in the case of `preview` which is rendered differently.
62
- if (!analyticsPayload.attributes.display) {
63
- analyticsPayload.attributes.display = appearance;
64
- }
65
- }
66
-
67
- (0, _analytics.fireSmartLinkEvent)(analyticsPayload, createAnalyticsEvent);
68
- });
69
- _this.state = {
70
- id: (0, _uuid.default)()
71
- };
72
- return _this;
73
- }
32
+ var LazyCardWithUrlContent = /*#__PURE__*/(0, _react.lazy)(function () {
33
+ return Promise.resolve().then(function () {
34
+ return _interopRequireWildcard(require('./component-lazy/index'));
35
+ });
36
+ });
74
37
 
75
- (0, _createClass2.default)(CardWithURLRenderer, [{
76
- key: "componentDidMount",
77
- value: function componentDidMount() {
78
- if (CardWithURLRenderer.CardContent === null) {
79
- (this.props.importer || CardWithURLRenderer.moduleImporter)(this);
80
- }
81
- }
82
- }, {
83
- key: "componentWillUnmount",
84
- value: function componentWillUnmount() {
85
- var id = this.state.id;
38
+ function CardWithURLRenderer(props) {
39
+ var _useState = (0, _react.useState)(function () {
40
+ return (0, _uuid.default)();
41
+ }),
42
+ _useState2 = (0, _slicedToArray2.default)(_useState, 1),
43
+ id = _useState2[0]; // Equivalent to ComponentWillMount
44
+
45
+
46
+ (0, _react.useState)(function () {
47
+ // We want to start timing of render event only once and right at the start
48
+ (0, _ufoExperiences.startUfoExperience)('smart-link-rendered', id);
49
+ });
50
+ (0, _react.useEffect)(function () {
51
+ // ComponentWillUnmount
52
+ return function () {
86
53
  (0, _performance.clearMarks)(id);
87
54
  (0, _performance.clearMeasures)(id);
88
- }
89
- }, {
90
- key: "componentDidCatch",
91
- value: function componentDidCatch(error, errorInfo) {
92
- var appearance = this.props.appearance; // NB: APIErrors are thrown in response to Object Resolver Service.
93
- // In these cases, control is handed back to the Editor. We do not
94
- // fire an event for these, as they do not cover failed UI render events.
95
-
96
- if (error.name === 'APIError') {
97
- throw error;
98
- } // NB: the rest of the errors caught here are unexpected, and correlate
99
- // to the reliability of the smart-card front-end components. We instrument
100
- // these in order to measure our front-end reliability.
101
- else {
102
- this.dispatchAnalytics((0, _analytics.uiRenderFailedEvent)(appearance, error, errorInfo));
103
- }
104
- } // Wrapper around analytics.
105
-
106
- }, {
107
- key: "render",
108
- value: function render() {
109
- var _this$props2 = this.props,
110
- url = _this$props2.url,
111
- appearance = _this$props2.appearance,
112
- isSelected = _this$props2.isSelected,
113
- isFrameVisible = _this$props2.isFrameVisible,
114
- onClick = _this$props2.onClick,
115
- container = _this$props2.container,
116
- onResolve = _this$props2.onResolve,
117
- testId = _this$props2.testId,
118
- showActions = _this$props2.showActions,
119
- inheritDimensions = _this$props2.inheritDimensions,
120
- platform = _this$props2.platform,
121
- embedIframeRef = _this$props2.embedIframeRef,
122
- inlinePreloaderStyle = _this$props2.inlinePreloaderStyle;
123
-
124
- if (!url) {
125
- throw new Error('@atlaskit/smart-card: url property is missing.');
55
+ };
56
+ }, [id]);
57
+ var url = props.url,
58
+ appearance = props.appearance,
59
+ isSelected = props.isSelected,
60
+ isFrameVisible = props.isFrameVisible,
61
+ onClick = props.onClick,
62
+ container = props.container,
63
+ onResolve = props.onResolve,
64
+ testId = props.testId,
65
+ showActions = props.showActions,
66
+ inheritDimensions = props.inheritDimensions,
67
+ platform = props.platform,
68
+ embedIframeRef = props.embedIframeRef,
69
+ inlinePreloaderStyle = props.inlinePreloaderStyle,
70
+ createAnalyticsEvent = props.createAnalyticsEvent; // Wrapper around analytics.
71
+
72
+ var dispatchAnalytics = (0, _react.useCallback)(function (analyticsPayload) {
73
+ if (analyticsPayload && analyticsPayload.attributes) {
74
+ // Update if we haven't already set the display - possible
75
+ // in the case of `preview` which is rendered differently.
76
+ if (!analyticsPayload.attributes.display) {
77
+ analyticsPayload.attributes.display = appearance;
126
78
  }
127
-
128
- return CardWithURLRenderer.CardContent !== null ? /*#__PURE__*/_react.default.createElement(CardWithURLRenderer.CardContent, {
129
- id: this.state.id,
130
- url: url,
131
- appearance: appearance,
132
- onClick: onClick,
133
- isSelected: isSelected,
134
- isFrameVisible: isFrameVisible,
135
- dispatchAnalytics: this.dispatchAnalytics,
136
- container: container,
137
- onResolve: onResolve,
138
- testId: testId,
139
- showActions: showActions,
140
- inheritDimensions: inheritDimensions,
141
- platform: platform,
142
- embedIframeRef: embedIframeRef,
143
- inlinePreloaderStyle: inlinePreloaderStyle
144
- }) : /*#__PURE__*/_react.default.createElement(_mediaUi.CardLinkView, {
145
- key: 'chunk-placeholder',
146
- link: url
147
- });
148
79
  }
149
- }], [{
150
- key: "moduleImporter",
151
- value: function moduleImporter(target) {
152
- Promise.resolve().then(function () {
153
- return _interopRequireWildcard(require('./component-lazy/index'));
154
- }).then(function (module) {
155
- CardWithURLRenderer.CardContent = module.LazyCardWithUrlContent;
156
- target.forceUpdate();
157
- });
80
+
81
+ (0, _analytics.fireSmartLinkEvent)(analyticsPayload, createAnalyticsEvent);
82
+ }, [appearance, createAnalyticsEvent]);
83
+ var logError = (0, _react.useCallback)(function (error, info) {
84
+ var componentStack = info.componentStack; // NB: APIErrors are thrown in response to Object Resolver Service.
85
+ // In these cases, control is handed back to the Editor. We do not
86
+ // fire an event for these, as they do not cover failed UI render events.
87
+
88
+ if (error.name === 'APIError') {
89
+ throw error;
90
+ } // NB: the rest of the errors caught here are unexpected, and correlate
91
+ // to the reliability of the smart-card front-end components. We instrument
92
+ // these in order to measure our front-end reliability.
93
+ else {
94
+ var errorInfo = {
95
+ componentStack: componentStack
96
+ };
97
+ (0, _ufoExperiences.failUfoExperience)('smart-link-rendered', id);
98
+ (0, _ufoExperiences.failUfoExperience)('smart-link-authenticated', id);
99
+ dispatchAnalytics((0, _analytics.uiRenderFailedEvent)(appearance, error, errorInfo));
158
100
  }
159
- }]);
160
- return CardWithURLRenderer;
161
- }(_react.default.PureComponent);
101
+ }, [appearance, dispatchAnalytics, id]);
162
102
 
163
- exports.CardWithURLRenderer = CardWithURLRenderer;
164
- (0, _defineProperty2.default)(CardWithURLRenderer, "CardContent", null);
103
+ if (!url) {
104
+ throw new Error('@atlaskit/smart-card: url property is missing.');
105
+ }
106
+
107
+ return /*#__PURE__*/_react.default.createElement(_reactErrorBoundary.ErrorBoundary, {
108
+ FallbackComponent: ErrorFallback,
109
+ onError: logError
110
+ }, /*#__PURE__*/_react.default.createElement(_react.Suspense, {
111
+ fallback: /*#__PURE__*/_react.default.createElement(_mediaUi.CardLinkView, {
112
+ key: 'chunk-placeholder',
113
+ link: url
114
+ })
115
+ }, /*#__PURE__*/_react.default.createElement(LazyCardWithUrlContent, {
116
+ id: id,
117
+ url: url,
118
+ appearance: appearance,
119
+ onClick: onClick,
120
+ isSelected: isSelected,
121
+ isFrameVisible: isFrameVisible,
122
+ dispatchAnalytics: dispatchAnalytics,
123
+ container: container,
124
+ onResolve: onResolve,
125
+ testId: testId,
126
+ showActions: showActions,
127
+ inheritDimensions: inheritDimensions,
128
+ platform: platform,
129
+ embedIframeRef: embedIframeRef,
130
+ inlinePreloaderStyle: inlinePreloaderStyle
131
+ })));
132
+ }
133
+
134
+ var ErrorFallback = function ErrorFallback() {
135
+ return /*#__PURE__*/_react.default.createElement("span", null);
136
+ };
@@ -1,5 +1,5 @@
1
1
  const devBaseUrl = 'https://api-private.dev.atlassian.com';
2
- const stgBaseUrl = 'https://api-private.stg.atlassian.com';
2
+ const stgBaseUrl = 'https://commerce-components-preview.dev.atlassian.com/gateway/api';
3
3
  const prodBaseUrl = 'https://api-private.atlassian.com';
4
4
  export const BaseUrls = {
5
5
  dev: devBaseUrl,
@@ -30,7 +30,7 @@ const extractBlockIcon = jsonLd => {
30
30
 
31
31
  const extractBlockDetails = jsonLd => [extractCommentCount(jsonLd), extractProgrammingLanguage(jsonLd), extractSubscriberCount(jsonLd)].filter(detail => !!detail);
32
32
 
33
- export const extractBlockActions = (props, jsonLd, opts) => {
33
+ export const extractBlockActions = (props, jsonLd, opts, platform) => {
34
34
  if (opts) {
35
35
  const {
36
36
  handleInvoke,
@@ -39,7 +39,7 @@ export const extractBlockActions = (props, jsonLd, opts) => {
39
39
  testId
40
40
  } = opts;
41
41
  const actions = extractActions(jsonLd, handleInvoke);
42
- const previewAction = extractPreviewAction(definitionId, props, jsonLd, handleInvoke, handleAnalytics, testId); // The previewAction should always be the last action
42
+ const previewAction = extractPreviewAction(definitionId, props, jsonLd, handleInvoke, handleAnalytics, testId, platform); // The previewAction should always be the last action
43
43
 
44
44
  if (previewAction) {
45
45
  actions.push(previewAction);
@@ -71,7 +71,7 @@ export const extractBlockUsers = jsonLd => {
71
71
  return updatedByMembers || createdByMembers;
72
72
  }
73
73
  };
74
- export const extractBlockProps = (jsonLd, meta, opts, renderers) => {
74
+ export const extractBlockProps = (jsonLd, meta, opts, renderers, platform) => {
75
75
  const props = {
76
76
  link: extractLink(jsonLd),
77
77
  title: extractTitle(jsonLd),
@@ -87,6 +87,6 @@ export const extractBlockProps = (jsonLd, meta, opts, renderers) => {
87
87
  isTrusted: extractIsTrusted(meta)
88
88
  };
89
89
  return { ...props,
90
- actions: extractBlockActions(props, jsonLd, opts)
90
+ actions: extractBlockActions(props, jsonLd, opts, platform)
91
91
  };
92
92
  };
@@ -4,10 +4,10 @@ import { extractDownloadUrl } from '../detail';
4
4
  import { extractProvider } from '../context';
5
5
  import { extractPreview } from '../preview';
6
6
 
7
- const getMetadataFromJsonLd = jsonLd => {
7
+ const getMetadataFromJsonLd = (jsonLd, platform) => {
8
8
  const download = extractDownloadUrl(jsonLd);
9
9
  const provider = extractProvider(jsonLd);
10
- const preview = extractPreview(jsonLd);
10
+ const preview = extractPreview(jsonLd, platform);
11
11
  return {
12
12
  download,
13
13
  providerName: provider && provider.text,
@@ -40,9 +40,9 @@ const getInvokeOpts = (key, action, source) => ({
40
40
  }
41
41
  });
42
42
 
43
- export const extractPreviewAction = (definitionId = 'empty-object-provider', viewProps, jsonLd, handleInvoke, handleAnalytics, testId) => {
43
+ export const extractPreviewAction = (definitionId = 'empty-object-provider', viewProps, jsonLd, handleInvoke, handleAnalytics, testId, platform) => {
44
44
  // Extract metadata from view props & raw JSON-LD.
45
- const metadataFromJsonLd = getMetadataFromJsonLd(jsonLd);
45
+ const metadataFromJsonLd = getMetadataFromJsonLd(jsonLd, platform);
46
46
  const metadataFromViewProps = getMetadataFromResolvedProps(viewProps);
47
47
  const metadata = { ...metadataFromJsonLd,
48
48
  ...metadataFromViewProps
@@ -1,6 +1,6 @@
1
1
  const isJiraRoadMap = url => url.match(/^https:\/\/.*?\/jira\/software\/(c\/)?projects\/[^\/]+?\/boards\/.*?\/roadmap\/?/);
2
2
 
3
- const isPolarisView = url => url.match(/^https:\/\/.*?\/jira\/polaris\/projects\/[^\/]+?\/ideas\/view\/\d+$/);
3
+ const isPolarisView = url => url.match(/^https:\/\/.*?\/jira\/polaris\/projects\/[^\/]+?\/ideas\/view\/\d+$|^https:\/\/.*?\/secure\/JiraProductDiscoveryAnonymous\.jspa\?hash=\w+|^https:\/\/.*?\/jira\/polaris\/share\/\w+/);
4
4
 
5
5
  const isSlackMessage = url => url.match(/^https:\/\/.+?\.slack\.com\/archives\/[CG][A-Z0-9]+\/p[0-9]+(\?.*)?$/);
6
6
 
@@ -7,6 +7,7 @@ import { useSmartLinkContext } from '../context';
7
7
  import * as measure from '../../utils/performance';
8
8
  import { APIError } from '../../client/errors';
9
9
  import { getUnauthorizedJsonLd } from '../../utils/jsonld';
10
+ import { addMetadataToExperience } from '../analytics';
10
11
  export const useSmartCardActions = (id, url, analytics) => {
11
12
  const {
12
13
  store,
@@ -91,8 +92,12 @@ export const useSmartCardActions = (id, url, analytics) => {
91
92
  // has come back asynchronously, dispatch the resolved action for the card.
92
93
  if (isReloading || !hasData) {
93
94
  return connections.client.fetchData(resourceUrl).then(response => handleResolvedLinkResponse(resourceUrl, response)).catch(error => handleResolvedLinkError(resourceUrl, error));
95
+ } else {
96
+ addMetadataToExperience('smart-link-rendered', id, {
97
+ cached: true
98
+ });
94
99
  }
95
- }, [url, hasData, connections.client, handleResolvedLinkResponse, handleResolvedLinkError]);
100
+ }, [url, hasData, connections.client, handleResolvedLinkResponse, handleResolvedLinkError, id]);
96
101
  const register = useCallback(() => {
97
102
  if (!details) {
98
103
  dispatch(cardAction(ACTION_PENDING, {
@@ -128,10 +133,10 @@ export const useSmartCardActions = (id, url, analytics) => {
128
133
  analytics.screen.authPopupEvent(definitionId, extensionKey);
129
134
  auth(services[0].url).then(() => {
130
135
  analytics.track.appAccountConnected(definitionId, extensionKey);
131
- analytics.operational.connectSucceededEvent(definitionId, extensionKey);
136
+ analytics.operational.connectSucceededEvent(id, definitionId, extensionKey);
132
137
  reload();
133
138
  }, err => {
134
- analytics.operational.connectFailedEvent(definitionId, extensionKey, err.type);
139
+ analytics.operational.connectFailedEvent(id, definitionId, extensionKey, err.type);
135
140
 
136
141
  if (err.type === 'auth_window_closed') {
137
142
  analytics.ui.closedAuthEvent(appearance, definitionId, extensionKey);
@@ -140,7 +145,7 @@ export const useSmartCardActions = (id, url, analytics) => {
140
145
  reload();
141
146
  });
142
147
  }
143
- }, [analytics.ui, analytics.screen, analytics.track, analytics.operational, reload, details, status]);
148
+ }, [analytics.ui, analytics.screen, analytics.track, analytics.operational, id, reload, details, status]);
144
149
  const invoke = useCallback(async (opts, appearance) => {
145
150
  const {
146
151
  key,
@@ -1,40 +1,2 @@
1
- import { uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, uiRenderSuccessEvent, uiRenderFailedEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountConnected, screenAuthPopupEvent, instrumentEvent } from '../../utils/analytics';
2
- import { useMemo } from 'react';
3
- export const useSmartLinkAnalytics = dispatchAnalytics => {
4
- const ui = useMemo(() => ({
5
- authEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthEvent(display, definitionId, extensionKey)),
6
- authAlternateAccountEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthAlternateAccountEvent(display, definitionId, extensionKey)),
7
- cardClickedEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiCardClickedEvent(display, definitionId, extensionKey)),
8
- actionClickedEvent: (providerKey, actionType, display) => dispatchAnalytics(uiActionClickedEvent(providerKey, actionType, display)),
9
- closedAuthEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiClosedAuthEvent(display, definitionId, extensionKey)),
10
- renderSuccessEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiRenderSuccessEvent(display, definitionId, extensionKey)),
11
- renderFailedEvent: (display, error, errorInfo) => dispatchAnalytics(uiRenderFailedEvent(display, error, errorInfo))
12
- }), [dispatchAnalytics]);
13
- const operational = useMemo(() => ({
14
- resolvedEvent: (id, definitionId, extensionKey, resourceType) => dispatchAnalytics(resolvedEvent(id, definitionId, extensionKey, resourceType)),
15
- unresolvedEvent: (id, status, definitionId, extensionKey, resourceType) => dispatchAnalytics(unresolvedEvent(id, status, definitionId, extensionKey, resourceType)),
16
- invokeSucceededEvent: (id, providerKey, actionType, display) => dispatchAnalytics(invokeSucceededEvent(id, providerKey, actionType, display)),
17
- invokeFailedEvent: (id, providerKey, actionType, display, reason) => dispatchAnalytics(invokeFailedEvent(id, providerKey, actionType, display, reason)),
18
- connectSucceededEvent: (definitionId, extensionKey) => dispatchAnalytics(connectSucceededEvent(definitionId, extensionKey)),
19
- connectFailedEvent: (definitionId, extensionKey, reason) => dispatchAnalytics(connectFailedEvent(definitionId, extensionKey, reason)),
20
- instrument: (id, status, definitionId, extensionKey, resourceType, error) => {
21
- const event = instrumentEvent(id, status, definitionId, extensionKey, resourceType, error);
22
-
23
- if (event) {
24
- dispatchAnalytics(event);
25
- }
26
- }
27
- }), [dispatchAnalytics]);
28
- const track = useMemo(() => ({
29
- appAccountConnected: (definitionId, extensionKey) => dispatchAnalytics(trackAppAccountConnected(definitionId, extensionKey))
30
- }), [dispatchAnalytics]);
31
- const screen = useMemo(() => ({
32
- authPopupEvent: (definitionId, extensionKey) => dispatchAnalytics(screenAuthPopupEvent(definitionId, extensionKey))
33
- }), [dispatchAnalytics]);
34
- return useMemo(() => ({
35
- ui,
36
- operational,
37
- track,
38
- screen
39
- }), [ui, operational, track, screen]);
40
- };
1
+ export { startUfoExperience, succeedUfoExperience, failUfoExperience, addMetadataToExperience } from './ufoExperiences';
2
+ export { useSmartLinkAnalytics } from './useSmartLinkAnalytics';
@@ -0,0 +1,40 @@
1
+ import { ConcurrentExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atlaskit/ufo';
2
+ const ufoExperiences = {
3
+ 'smart-link-rendered': new ConcurrentExperience('smart-link-rendered', {
4
+ type: ExperienceTypes.Load,
5
+ performanceType: ExperiencePerformanceTypes.PageSegmentLoad,
6
+ platform: {
7
+ component: 'smart-links'
8
+ }
9
+ }),
10
+ 'smart-link-authenticated': new ConcurrentExperience('smart-link-authenticated', {
11
+ type: ExperienceTypes.Load,
12
+ performanceType: ExperiencePerformanceTypes.PageSegmentLoad,
13
+ platform: {
14
+ component: 'smart-links'
15
+ }
16
+ })
17
+ };
18
+ export const startUfoExperience = (experienceName, id, properties) => {
19
+ const experience = ufoExperiences[experienceName].getInstance(id);
20
+ experience.start();
21
+
22
+ if (properties) {
23
+ experience.addMetadata(properties);
24
+ }
25
+ };
26
+ export const succeedUfoExperience = (experienceName, id, properties) => {
27
+ const experience = ufoExperiences[experienceName].getInstance(id);
28
+ experience.success({
29
+ metadata: properties
30
+ });
31
+ };
32
+ export const failUfoExperience = (experienceName, id, properties) => {
33
+ const experience = ufoExperiences[experienceName].getInstance(id);
34
+ experience.failure({
35
+ metadata: properties
36
+ });
37
+ };
38
+ export const addMetadataToExperience = (experienceName, id, properties) => {
39
+ ufoExperiences[experienceName].getInstance(id).addMetadata(properties);
40
+ };
@@ -0,0 +1,62 @@
1
+ import { uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, uiRenderSuccessEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountConnected, screenAuthPopupEvent, instrumentEvent } from '../../utils/analytics';
2
+ import { useMemo } from 'react';
3
+ import { startUfoExperience, succeedUfoExperience } from './ufoExperiences';
4
+ export const useSmartLinkAnalytics = dispatchAnalytics => {
5
+ const ui = useMemo(() => ({
6
+ authEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthEvent(display, definitionId, extensionKey)),
7
+ authAlternateAccountEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthAlternateAccountEvent(display, definitionId, extensionKey)),
8
+ cardClickedEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiCardClickedEvent(display, definitionId, extensionKey)),
9
+ actionClickedEvent: (providerKey, actionType, display) => dispatchAnalytics(uiActionClickedEvent(providerKey, actionType, display)),
10
+ closedAuthEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiClosedAuthEvent(display, definitionId, extensionKey)),
11
+ renderSuccessEvent: (display, id, definitionId, extensionKey) => {
12
+ succeedUfoExperience('smart-link-rendered', id, {
13
+ extensionKey,
14
+ display
15
+ }); // UFO will disregard this if authentication experience has not yet been started
16
+
17
+ succeedUfoExperience('smart-link-authenticated', id, {
18
+ display
19
+ });
20
+ dispatchAnalytics(uiRenderSuccessEvent(display, definitionId, extensionKey));
21
+ }
22
+ }), [dispatchAnalytics]);
23
+ const operational = useMemo(() => ({
24
+ resolvedEvent: (id, definitionId, extensionKey, resourceType) => dispatchAnalytics(resolvedEvent(id, definitionId, extensionKey, resourceType)),
25
+ unresolvedEvent: (id, status, definitionId, extensionKey, resourceType) => dispatchAnalytics(unresolvedEvent(id, status, definitionId, extensionKey, resourceType)),
26
+ invokeSucceededEvent: (id, providerKey, actionType, display) => dispatchAnalytics(invokeSucceededEvent(id, providerKey, actionType, display)),
27
+ invokeFailedEvent: (id, providerKey, actionType, display, reason) => dispatchAnalytics(invokeFailedEvent(id, providerKey, actionType, display, reason)),
28
+ connectSucceededEvent: (id, definitionId, extensionKey) => {
29
+ startUfoExperience('smart-link-authenticated', id, {
30
+ extensionKey,
31
+ status: 'success'
32
+ });
33
+ dispatchAnalytics(connectSucceededEvent(definitionId, extensionKey));
34
+ },
35
+ connectFailedEvent: (id, definitionId, extensionKey, status) => {
36
+ startUfoExperience('smart-link-authenticated', id, {
37
+ extensionKey,
38
+ status
39
+ });
40
+ dispatchAnalytics(connectFailedEvent(definitionId, extensionKey, status));
41
+ },
42
+ instrument: (id, status, definitionId, extensionKey, resourceType, error) => {
43
+ const event = instrumentEvent(id, status, definitionId, extensionKey, resourceType, error);
44
+
45
+ if (event) {
46
+ dispatchAnalytics(event);
47
+ }
48
+ }
49
+ }), [dispatchAnalytics]);
50
+ const track = useMemo(() => ({
51
+ appAccountConnected: (definitionId, extensionKey) => dispatchAnalytics(trackAppAccountConnected(definitionId, extensionKey))
52
+ }), [dispatchAnalytics]);
53
+ const screen = useMemo(() => ({
54
+ authPopupEvent: (definitionId, extensionKey) => dispatchAnalytics(screenAuthPopupEvent(definitionId, extensionKey))
55
+ }), [dispatchAnalytics]);
56
+ return useMemo(() => ({
57
+ ui,
58
+ operational,
59
+ track,
60
+ screen
61
+ }), [ui, operational, track, screen]);
62
+ };
@@ -11,12 +11,10 @@ export function useSmartLink(id, url, dispatchAnalytics) {
11
11
  const config = useSmartLinkConfig();
12
12
  const renderers = useSmartLinkRenderers(); // NB: used to propagate errors from hooks to error boundaries.
13
13
 
14
- const [, setState] = useState(); // Register the current card.
14
+ const [error, setError] = useState(null); // Register the current card.
15
15
 
16
16
  const register = () => {
17
- actions.register().catch(err => setState(() => {
18
- throw err;
19
- }));
17
+ actions.register().catch(err => setError(err));
20
18
  }; // AFP-2511 TODO: Fix automatic suppressions below
21
19
  // eslint-disable-next-line react-hooks/exhaustive-deps
22
20
 
@@ -28,6 +26,7 @@ export function useSmartLink(id, url, dispatchAnalytics) {
28
26
  actions,
29
27
  config,
30
28
  analytics,
31
- renderers
29
+ renderers,
30
+ error
32
31
  };
33
32
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "16.0.0",
3
+ "version": "16.2.1",
4
4
  "sideEffects": false
5
5
  }
@@ -21,7 +21,8 @@ export const BlockCard = ({
21
21
  isSelected,
22
22
  onResolve,
23
23
  testId,
24
- showActions
24
+ showActions,
25
+ platform
25
26
  }) => {
26
27
  var _details$meta, _forbiddenViewProps$c;
27
28
 
@@ -42,7 +43,7 @@ export const BlockCard = ({
42
43
  });
43
44
 
44
45
  case 'resolved':
45
- const resolvedViewProps = extractBlockProps(data, meta, extractorOpts, renderers);
46
+ const resolvedViewProps = extractBlockProps(data, meta, extractorOpts, renderers, platform);
46
47
 
47
48
  if (onResolve) {
48
49
  onResolve({
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { isIntersectionObserverSupported } from '@atlaskit/media-ui';
3
3
  import { LazyLazilyRenderCard } from './LazyLazilyRenderCard';
4
4
  import { LazyIntersectionObserverCard } from './LazyIntersectionObserverCard';
5
- export function LazyCardWithUrlContent(props) {
5
+ export default function LazyCardWithUrlContent(props) {
6
6
  if (isIntersectionObserverSupported()) {
7
7
  return /*#__PURE__*/React.createElement(LazyIntersectionObserverCard, props);
8
8
  } else {
@@ -28,7 +28,8 @@ export function CardWithUrlContent({
28
28
  actions,
29
29
  config,
30
30
  analytics,
31
- renderers
31
+ renderers,
32
+ error
32
33
  } = useSmartLink(id, url, dispatchAnalytics);
33
34
  const definitionId = getDefinitionId(state.details);
34
35
  const extensionKey = getExtensionKey(state.details);
@@ -67,9 +68,13 @@ export function CardWithUrlContent({
67
68
 
68
69
  useEffect(() => {
69
70
  if (isFinalState(state.status)) {
70
- analytics.ui.renderSuccessEvent(appearance, definitionId, extensionKey);
71
+ analytics.ui.renderSuccessEvent(appearance, id, definitionId, extensionKey);
71
72
  }
72
- }, [appearance, state.details, state.status, url, definitionId, extensionKey, analytics.ui]);
73
+ }, [appearance, state.details, state.status, url, definitionId, extensionKey, analytics.ui, id]); // We have to keep this last to prevent hook order from being violated
74
+
75
+ if (error) {
76
+ throw error;
77
+ }
73
78
 
74
79
  switch (appearance) {
75
80
  case 'inline':
@@ -99,7 +104,8 @@ export function CardWithUrlContent({
99
104
  isSelected: isSelected,
100
105
  onResolve: onResolve,
101
106
  testId: testId,
102
- showActions: showActions
107
+ showActions: showActions,
108
+ platform: platform
103
109
  });
104
110
 
105
111
  case 'embed':