@atlaskit/smart-card 26.20.1 → 26.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/extractors/common/meta/extractIsTrusted.js +7 -0
  3. package/dist/cjs/state/actions/index.js +16 -52
  4. package/dist/cjs/state/analytics/useSmartLinkAnalytics.js +12 -11
  5. package/dist/cjs/state/hooks/use-invoke-client-action/index.js +78 -0
  6. package/dist/cjs/state/hooks/use-invoke-client-action/types.js +5 -0
  7. package/dist/cjs/utils/analytics/analytics.js +5 -9
  8. package/dist/cjs/utils/mocks.js +9 -4
  9. package/dist/cjs/view/BlockCard/actions/PreviewAction.js +6 -70
  10. package/dist/cjs/view/BlockCard/components/Action.js +1 -3
  11. package/dist/cjs/view/LinkUrl/index.js +1 -1
  12. package/dist/es2019/extractors/common/meta/extractIsTrusted.js +7 -0
  13. package/dist/es2019/state/actions/index.js +10 -38
  14. package/dist/es2019/state/analytics/useSmartLinkAnalytics.js +12 -11
  15. package/dist/es2019/state/hooks/use-invoke-client-action/index.js +52 -0
  16. package/dist/es2019/state/hooks/use-invoke-client-action/types.js +1 -0
  17. package/dist/es2019/utils/analytics/analytics.js +5 -9
  18. package/dist/es2019/utils/mocks.js +9 -4
  19. package/dist/es2019/view/BlockCard/actions/PreviewAction.js +3 -44
  20. package/dist/es2019/view/BlockCard/components/Action.js +1 -1
  21. package/dist/es2019/view/LinkUrl/index.js +1 -1
  22. package/dist/esm/extractors/common/meta/extractIsTrusted.js +7 -0
  23. package/dist/esm/state/actions/index.js +16 -49
  24. package/dist/esm/state/analytics/useSmartLinkAnalytics.js +12 -11
  25. package/dist/esm/state/hooks/use-invoke-client-action/index.js +67 -0
  26. package/dist/esm/state/hooks/use-invoke-client-action/types.js +1 -0
  27. package/dist/esm/utils/analytics/analytics.js +5 -9
  28. package/dist/esm/utils/mocks.js +9 -4
  29. package/dist/esm/view/BlockCard/actions/PreviewAction.js +8 -65
  30. package/dist/esm/view/BlockCard/components/Action.js +1 -3
  31. package/dist/esm/view/LinkUrl/index.js +1 -1
  32. package/dist/types/state/analytics/useSmartLinkAnalytics.d.ts +3 -3
  33. package/dist/types/state/flexible-ui-context/index.d.ts +6 -6
  34. package/dist/types/state/hooks/use-invoke-client-action/index.d.ts +6 -0
  35. package/dist/types/state/hooks/use-invoke-client-action/types.d.ts +30 -0
  36. package/dist/types/state/hooks/useSmartLink.d.ts +3 -3
  37. package/dist/types/utils/analytics/types.d.ts +3 -3
  38. package/dist/types/utils/mocks.d.ts +3 -3
  39. package/dist/types/view/BlockCard/actions/PreviewAction.d.ts +0 -5
  40. package/dist/types/view/FlexibleCard/components/utils.d.ts +3 -3
  41. package/dist/types-ts4.5/state/analytics/useSmartLinkAnalytics.d.ts +3 -3
  42. package/dist/types-ts4.5/state/flexible-ui-context/index.d.ts +6 -6
  43. package/dist/types-ts4.5/state/hooks/use-invoke-client-action/index.d.ts +6 -0
  44. package/dist/types-ts4.5/state/hooks/use-invoke-client-action/types.d.ts +30 -0
  45. package/dist/types-ts4.5/state/hooks/useSmartLink.d.ts +3 -3
  46. package/dist/types-ts4.5/utils/analytics/types.d.ts +3 -3
  47. package/dist/types-ts4.5/utils/mocks.d.ts +3 -3
  48. package/dist/types-ts4.5/view/BlockCard/actions/PreviewAction.d.ts +0 -5
  49. package/dist/types-ts4.5/view/FlexibleCard/components/utils.d.ts +3 -3
  50. package/package.json +9 -5
  51. package/report.api.md +7 -7
  52. package/tmp/api-report-tmp.d.ts +6 -6
@@ -239,25 +239,26 @@ export const useSmartLinkAnalytics = (url, _dispatchAnalytics, id, defaultLocati
239
239
  * @returns
240
240
  */
241
241
  actionClickedEvent: ({
242
- id,
242
+ id: experienceId,
243
243
  actionType,
244
244
  display,
245
245
  invokeType,
246
- extensionKey,
246
+ extensionKey: overrideExtensionKey,
247
247
  definitionId,
248
248
  resourceType,
249
249
  destinationProduct,
250
250
  destinationSubproduct,
251
251
  location
252
252
  }) => {
253
- startUfoExperience('smart-link-action-invocation', id, {
253
+ const extensionKey = overrideExtensionKey !== null && overrideExtensionKey !== void 0 ? overrideExtensionKey : extractedExtensionKey;
254
+ startUfoExperience('smart-link-action-invocation', experienceId, {
254
255
  actionType,
255
256
  display,
256
257
  extensionKey,
257
258
  invokeType
258
259
  });
259
260
  dispatchAnalytics(applyCommonAttributes(uiActionClickedEvent({
260
- id,
261
+ id: defaultId,
261
262
  actionType,
262
263
  display,
263
264
  extensionKey,
@@ -494,7 +495,7 @@ export const useSmartLinkAnalytics = (url, _dispatchAnalytics, id, defaultLocati
494
495
  * Fires an event that represent a click was performed on a Status Lozenge open preview button
495
496
  */
496
497
  smartLinkLozengeActionErrorOpenPreviewClickedEvent: () => dispatchAnalytics(applyCommonAttributes(uiSmartLinkStatusOpenPreviewButtonClicked(), commonAttributes))
497
- }), [defaultId, commonAttributes, dispatchAnalytics]);
498
+ }), [dispatchAnalytics, commonAttributes, defaultId, extractedExtensionKey]);
498
499
 
499
500
  /** Contains all operational analytics events */
500
501
  const operational = useMemo(() => ({
@@ -506,7 +507,7 @@ export const useSmartLinkAnalytics = (url, _dispatchAnalytics, id, defaultLocati
506
507
  * @param display Whether the card was an Inline, Block, Embed or Flexible UI.
507
508
  */
508
509
  invokeSucceededEvent: ({
509
- id,
510
+ id: experienceId,
510
511
  actionType,
511
512
  display,
512
513
  extensionKey,
@@ -516,9 +517,9 @@ export const useSmartLinkAnalytics = (url, _dispatchAnalytics, id, defaultLocati
516
517
  destinationSubproduct,
517
518
  location
518
519
  }) => {
519
- succeedUfoExperience('smart-link-action-invocation', id);
520
+ succeedUfoExperience('smart-link-action-invocation', experienceId);
520
521
  dispatchAnalytics(applyCommonAttributes(invokeSucceededEvent({
521
- id,
522
+ id: defaultId,
522
523
  actionType,
523
524
  display,
524
525
  extensionKey,
@@ -538,7 +539,7 @@ export const useSmartLinkAnalytics = (url, _dispatchAnalytics, id, defaultLocati
538
539
  * @param reason The reason the invocation failed.
539
540
  */
540
541
  invokeFailedEvent: ({
541
- id,
542
+ id: experienceId,
542
543
  actionType,
543
544
  display,
544
545
  reason,
@@ -549,9 +550,9 @@ export const useSmartLinkAnalytics = (url, _dispatchAnalytics, id, defaultLocati
549
550
  destinationSubproduct,
550
551
  location
551
552
  }) => {
552
- failUfoExperience('smart-link-action-invocation', id);
553
+ failUfoExperience('smart-link-action-invocation', experienceId);
553
554
  dispatchAnalytics(applyCommonAttributes(invokeFailedEvent({
554
- id,
555
+ id: defaultId,
555
556
  actionType,
556
557
  display,
557
558
  reason,
@@ -0,0 +1,52 @@
1
+ import { useCallback } from 'react';
2
+ import uuid from 'uuid';
3
+ import * as measure from '../../../utils/performance';
4
+ /**
5
+ * Invoke client action such as preview, download and open link
6
+ */
7
+ const useInvokeClientAction = ({
8
+ analytics
9
+ }) => useCallback(async ({
10
+ actionType,
11
+ actionFn,
12
+ extensionKey,
13
+ display
14
+ }) => {
15
+ const experienceId = uuid();
16
+
17
+ // Begin performance instrumentation.
18
+ const markName = `${experienceId}-${actionType}`;
19
+ measure.mark(markName, 'pending');
20
+ try {
21
+ // Begin analytics instrumentation.
22
+ analytics === null || analytics === void 0 ? void 0 : analytics.ui.actionClickedEvent({
23
+ id: experienceId,
24
+ extensionKey,
25
+ actionType,
26
+ display,
27
+ invokeType: 'client'
28
+ });
29
+
30
+ // Invoke action
31
+ const result = await actionFn();
32
+ measure.mark(markName, 'resolved');
33
+ analytics === null || analytics === void 0 ? void 0 : analytics.operational.invokeSucceededEvent({
34
+ id: experienceId,
35
+ extensionKey,
36
+ actionType,
37
+ display
38
+ });
39
+ return result;
40
+ } catch (err) {
41
+ measure.mark(markName, 'errored');
42
+ const reason = typeof err === 'string' ? err : err === null || err === void 0 ? void 0 : err.message;
43
+ analytics === null || analytics === void 0 ? void 0 : analytics.operational.invokeFailedEvent({
44
+ id: experienceId,
45
+ extensionKey,
46
+ actionType,
47
+ display,
48
+ reason
49
+ });
50
+ }
51
+ }, [analytics === null || analytics === void 0 ? void 0 : analytics.operational, analytics === null || analytics === void 0 ? void 0 : analytics.ui]);
52
+ export default useInvokeClientAction;
@@ -3,7 +3,7 @@ export const ANALYTICS_CHANNEL = 'media';
3
3
  export const context = {
4
4
  componentName: 'smart-cards',
5
5
  packageName: "@atlaskit/smart-card",
6
- packageVersion: "26.20.1"
6
+ packageVersion: "26.22.0"
7
7
  };
8
8
  export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
9
9
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -103,9 +103,7 @@ export const invokeSucceededEvent = ({
103
103
  destinationSubproduct,
104
104
  location
105
105
  }) => {
106
- const measure = getMeasure(id, 'resolved') || {
107
- duration: undefined
108
- };
106
+ const measure = id ? getMeasure(id, 'resolved') : undefined;
109
107
  return {
110
108
  action: 'resolved',
111
109
  actionSubject: 'smartLinkAction',
@@ -120,7 +118,7 @@ export const invokeSucceededEvent = ({
120
118
  destinationSubproduct,
121
119
  location,
122
120
  extensionKey,
123
- duration: measure.duration
121
+ duration: measure === null || measure === void 0 ? void 0 : measure.duration
124
122
  }
125
123
  };
126
124
  };
@@ -135,9 +133,7 @@ export const invokeFailedEvent = ({
135
133
  destinationSubproduct,
136
134
  location
137
135
  }) => {
138
- const measure = getMeasure(id, 'errored') || {
139
- duration: undefined
140
- };
136
+ const measure = id ? getMeasure(id, 'errored') : undefined;
141
137
  return {
142
138
  action: 'unresolved',
143
139
  actionSubject: 'smartLinkAction',
@@ -152,7 +148,7 @@ export const invokeFailedEvent = ({
152
148
  destinationProduct,
153
149
  destinationSubproduct,
154
150
  location,
155
- duration: measure.duration,
151
+ duration: measure === null || measure === void 0 ? void 0 : measure.duration,
156
152
  reason
157
153
  }
158
154
  };
@@ -54,11 +54,12 @@ export const mocks = {
54
54
  name: 'I love cheese',
55
55
  summary: 'Here is your serving of cheese: 🧀',
56
56
  'schema:potentialAction': {
57
- '@id': 'comment',
58
- '@type': 'CommentAction',
57
+ '@id': 'download',
58
+ '@type': 'DownloadAction',
59
59
  identifier: 'object-provider',
60
- name: 'Comment'
60
+ name: 'Download'
61
61
  },
62
+ 'atlassian:downloadUrl': 'https://some-download.url',
62
63
  preview: {
63
64
  href: 'https://www.ilovecheese.com'
64
65
  },
@@ -207,12 +208,16 @@ export const fakeFactory = (implementation, implementationPost, implementationPr
207
208
  export const waitFor = (time = 1) => new Promise(res => setTimeout(res, time));
208
209
  export const mockAnalytics = {
209
210
  ui: {
211
+ actionClickedEvent: () => {},
210
212
  buttonClickedEvent: () => {},
211
213
  modalClosedEvent: () => {},
212
214
  renderSuccessEvent: () => {},
213
215
  renderFailedEvent: () => {}
214
216
  },
215
- operational: {},
217
+ operational: {
218
+ invokeSucceededEvent: () => {},
219
+ invokeFailedEvent: () => {}
220
+ },
216
221
  track: {},
217
222
  screen: {
218
223
  modalViewedEvent: () => {}
@@ -1,46 +1,7 @@
1
- import _extends from "@babel/runtime/helpers/extends";
2
1
  import React from 'react';
3
- import ReactDOM from 'react-dom';
4
- import { FormattedMessage, IntlProvider } from 'react-intl-next';
2
+ import { FormattedMessage } from 'react-intl-next';
5
3
  import { messages } from '../../../messages';
6
- /*
7
- Explanatory note:
8
- Actions don't have access to the react tree of whatever is rendered them
9
- (and this concept is fraught inside editor anyway) so we want to ensure
10
- it is mounting to a new unique place. This function manages that, including
11
- creating an element if it doesn't exist, as well as tidying up the react tree
12
- (but not the element) upon closing the modal.
13
-
14
- This may strike you as really uncomfortable as you read it, so I wanted to note
15
- that a) this was discussed and agreed upon, and b) it's definitely odd, and if
16
- you find an elegant solution around this, you should definitely feel free to
17
- refactor it.
18
- */
19
- export async function previewFunction({
20
- popupMountPointId,
21
- onClose,
22
- ...rest
23
- }) {
24
- let popupMountPoint;
25
- popupMountPoint = document.getElementById(popupMountPointId);
26
- if (!popupMountPoint) {
27
- popupMountPoint = document.createElement('div');
28
- popupMountPoint.id = popupMountPointId;
29
- popupMountPoint.setAttribute('data-testid', 'preview-modal');
30
- document.body.appendChild(popupMountPoint);
31
- }
32
- let Modal = await import('../../EmbedModal');
33
- ReactDOM.render( /*#__PURE__*/React.createElement(IntlProvider, {
34
- locale: "en"
35
- }, /*#__PURE__*/React.createElement(Modal.default, _extends({}, rest, {
36
- onClose: context => {
37
- if (popupMountPoint) {
38
- onClose(context);
39
- ReactDOM.unmountComponentAtNode(popupMountPoint);
40
- }
41
- }
42
- }))), popupMountPoint);
43
- }
4
+ import { openEmbedModal } from '../../EmbedModal/utils';
44
5
 
45
6
  /*
46
7
  Most of these are optional as we are being fault-tolerant
@@ -53,11 +14,9 @@ export default (({
53
14
  }) => ({
54
15
  id: 'preview-content',
55
16
  text: /*#__PURE__*/React.createElement(FormattedMessage, messages.preview_improved),
56
- promise: () => previewFunction({
57
- popupMountPointId: 'twp-editor-preview-iframe',
17
+ promise: () => openEmbedModal({
58
18
  providerName: 'Preview',
59
19
  showModal: true,
60
- iframeName: 'twp-editor-preview-iframe',
61
20
  onClose: () => {},
62
21
  ...rest
63
22
  })
@@ -23,9 +23,9 @@ export const Action = ({
23
23
  setState('loading');
24
24
  promise().then(() => {
25
25
  setState('success');
26
- setTimeout(() => setState('init'), spinnerDelay);
27
26
  }).catch(() => {
28
27
  setState('failure');
28
+ }).finally(() => {
29
29
  setTimeout(() => setState('init'), spinnerDelay);
30
30
  });
31
31
  }
@@ -8,7 +8,7 @@ import LinkWarningModal from './LinkWarningModal';
8
8
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
9
9
  const PACKAGE_DATA = {
10
10
  packageName: "@atlaskit/smart-card",
11
- packageVersion: "26.20.1",
11
+ packageVersion: "26.22.0",
12
12
  componentName: 'linkUrl'
13
13
  };
14
14
  const Link = withLinkClickedEvent('a');
@@ -1,3 +1,10 @@
1
+ import { getBooleanFF } from '@atlaskit/platform-feature-flags';
1
2
  export var extractIsTrusted = function extractIsTrusted(meta) {
3
+ if (getBooleanFF('platform.linking-platform.smart-card.fix-is-trusted-pop')) {
4
+ if (!(meta !== null && meta !== void 0 && meta.key)) {
5
+ return false;
6
+ }
7
+ return !['iframely-object-provider', 'public-object-provider'].includes(meta.key);
8
+ }
2
9
  return Boolean((meta === null || meta === void 0 ? void 0 : meta.key) && meta.key !== 'iframely-object-provider');
3
10
  };
@@ -5,14 +5,16 @@ import { auth } from '@atlaskit/outbound-auth-flow-client';
5
5
  import { useSmartLinkContext } from '@atlaskit/link-provider';
6
6
  import { ACTION_UPDATE_METADATA_STATUS, cardAction, ACTION_RESOLVING } from '@atlaskit/linking-common';
7
7
  import { getDefinitionId, getByDefinitionId, getServices, getExtensionKey } from '../helpers';
8
- import * as measure from '../../utils/performance';
9
8
  import { SmartLinkStatus } from '../../constants';
10
9
  import useResolve from '../hooks/use-resolve';
10
+ import useInvokeClientAction from '../hooks/use-invoke-client-action';
11
11
  export var useSmartCardActions = function useSmartCardActions(id, url, analytics) {
12
12
  var resolveUrl = useResolve();
13
+ var invokeClientAction = useInvokeClientAction({
14
+ analytics: analytics
15
+ });
13
16
  var _useSmartLinkContext = useSmartLinkContext(),
14
- store = _useSmartLinkContext.store,
15
- connections = _useSmartLinkContext.connections;
17
+ store = _useSmartLinkContext.store;
16
18
  var getState = store.getState,
17
19
  dispatch = store.dispatch;
18
20
  var getSmartLinkState = useCallback(function () {
@@ -142,70 +144,35 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
142
144
  }, [getSmartLinkState, analytics.ui, analytics.screen, analytics.track, analytics.operational, id, reload]);
143
145
  var invoke = useCallback( /*#__PURE__*/function () {
144
146
  var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(opts, appearance) {
145
- var key, action, source, markName, response;
147
+ var key, action, source;
146
148
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
147
149
  while (1) switch (_context2.prev = _context2.next) {
148
150
  case 0:
149
151
  key = opts.key, action = opts.action;
150
152
  source = opts.source || appearance;
151
- markName = "".concat(id, "-").concat(action.type); // Begin performance instrumentation.
152
- measure.mark(markName, 'pending');
153
- _context2.prev = 4;
154
- // Begin analytics instrumentation.
155
- analytics.ui.actionClickedEvent({
156
- id: id,
157
- extensionKey: key,
158
- actionType: action.type,
159
- display: source,
160
- invokeType: opts.type
161
- });
162
- // Invoke action - either client-side or server-side.
163
153
  if (!(opts.type === 'client')) {
164
- _context2.next = 12;
154
+ _context2.next = 6;
165
155
  break;
166
156
  }
167
- _context2.next = 9;
168
- return opts.action.promise();
169
- case 9:
170
- response = _context2.sent;
171
- _context2.next = 15;
172
- break;
173
- case 12:
174
- _context2.next = 14;
175
- return connections.client.postData(opts);
176
- case 14:
177
- response = _context2.sent;
178
- case 15:
179
- measure.mark(markName, 'resolved');
180
- analytics.operational.invokeSucceededEvent({
181
- id: id,
182
- extensionKey: key,
183
- actionType: action.type,
184
- display: source
185
- });
186
- return _context2.abrupt("return", response);
187
- case 20:
188
- _context2.prev = 20;
189
- _context2.t0 = _context2["catch"](4);
190
- measure.mark(markName, 'errored');
191
- analytics.operational.invokeFailedEvent({
192
- id: id,
193
- extensionKey: key,
157
+ _context2.next = 5;
158
+ return invokeClientAction({
159
+ actionFn: opts.action.promise,
194
160
  actionType: action.type,
195
161
  display: source,
196
- reason: _context2.t0.message
162
+ extensionKey: key
197
163
  });
198
- throw _context2.t0;
199
- case 25:
164
+ case 5:
165
+ return _context2.abrupt("return", _context2.sent);
166
+ case 6:
200
167
  case "end":
201
168
  return _context2.stop();
202
169
  }
203
- }, _callee2, null, [[4, 20]]);
170
+ }, _callee2);
204
171
  }));
205
172
  return function (_x, _x2) {
206
173
  return _ref3.apply(this, arguments);
207
174
  };
208
- }(), [id, analytics.ui, analytics.operational, connections.client]);
175
+ }(), [invokeClientAction]);
209
176
  return useMemo(function () {
210
177
  return {
211
178
  register: register,
@@ -251,24 +251,25 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, _dispatch
251
251
  * @returns
252
252
  */
253
253
  actionClickedEvent: function actionClickedEvent(_ref6) {
254
- var id = _ref6.id,
254
+ var experienceId = _ref6.id,
255
255
  actionType = _ref6.actionType,
256
256
  display = _ref6.display,
257
257
  invokeType = _ref6.invokeType,
258
- extensionKey = _ref6.extensionKey,
258
+ overrideExtensionKey = _ref6.extensionKey,
259
259
  definitionId = _ref6.definitionId,
260
260
  resourceType = _ref6.resourceType,
261
261
  destinationProduct = _ref6.destinationProduct,
262
262
  destinationSubproduct = _ref6.destinationSubproduct,
263
263
  location = _ref6.location;
264
- startUfoExperience('smart-link-action-invocation', id, {
264
+ var extensionKey = overrideExtensionKey !== null && overrideExtensionKey !== void 0 ? overrideExtensionKey : extractedExtensionKey;
265
+ startUfoExperience('smart-link-action-invocation', experienceId, {
265
266
  actionType: actionType,
266
267
  display: display,
267
268
  extensionKey: extensionKey,
268
269
  invokeType: invokeType
269
270
  });
270
271
  dispatchAnalytics(applyCommonAttributes(uiActionClickedEvent({
271
- id: id,
272
+ id: defaultId,
272
273
  actionType: actionType,
273
274
  display: display,
274
275
  extensionKey: extensionKey,
@@ -513,7 +514,7 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, _dispatch
513
514
  return dispatchAnalytics(applyCommonAttributes(uiSmartLinkStatusOpenPreviewButtonClicked(), commonAttributes));
514
515
  }
515
516
  };
516
- }, [defaultId, commonAttributes, dispatchAnalytics]);
517
+ }, [dispatchAnalytics, commonAttributes, defaultId, extractedExtensionKey]);
517
518
 
518
519
  /** Contains all operational analytics events */
519
520
  var operational = useMemo(function () {
@@ -526,7 +527,7 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, _dispatch
526
527
  * @param display Whether the card was an Inline, Block, Embed or Flexible UI.
527
528
  */
528
529
  invokeSucceededEvent: function invokeSucceededEvent(_ref13) {
529
- var id = _ref13.id,
530
+ var experienceId = _ref13.id,
530
531
  actionType = _ref13.actionType,
531
532
  display = _ref13.display,
532
533
  extensionKey = _ref13.extensionKey,
@@ -535,9 +536,9 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, _dispatch
535
536
  destinationProduct = _ref13.destinationProduct,
536
537
  destinationSubproduct = _ref13.destinationSubproduct,
537
538
  location = _ref13.location;
538
- succeedUfoExperience('smart-link-action-invocation', id);
539
+ succeedUfoExperience('smart-link-action-invocation', experienceId);
539
540
  dispatchAnalytics(applyCommonAttributes(_invokeSucceededEvent({
540
- id: id,
541
+ id: defaultId,
541
542
  actionType: actionType,
542
543
  display: display,
543
544
  extensionKey: extensionKey,
@@ -557,7 +558,7 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, _dispatch
557
558
  * @param reason The reason the invocation failed.
558
559
  */
559
560
  invokeFailedEvent: function invokeFailedEvent(_ref14) {
560
- var id = _ref14.id,
561
+ var experienceId = _ref14.id,
561
562
  actionType = _ref14.actionType,
562
563
  display = _ref14.display,
563
564
  reason = _ref14.reason,
@@ -567,9 +568,9 @@ export var useSmartLinkAnalytics = function useSmartLinkAnalytics(url, _dispatch
567
568
  destinationProduct = _ref14.destinationProduct,
568
569
  destinationSubproduct = _ref14.destinationSubproduct,
569
570
  location = _ref14.location;
570
- failUfoExperience('smart-link-action-invocation', id);
571
+ failUfoExperience('smart-link-action-invocation', experienceId);
571
572
  dispatchAnalytics(applyCommonAttributes(_invokeFailedEvent({
572
- id: id,
573
+ id: defaultId,
573
574
  actionType: actionType,
574
575
  display: display,
575
576
  reason: reason,
@@ -0,0 +1,67 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
3
+ import { useCallback } from 'react';
4
+ import uuid from 'uuid';
5
+ import * as measure from '../../../utils/performance';
6
+ /**
7
+ * Invoke client action such as preview, download and open link
8
+ */
9
+ var useInvokeClientAction = function useInvokeClientAction(_ref) {
10
+ var analytics = _ref.analytics;
11
+ return useCallback( /*#__PURE__*/function () {
12
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref2) {
13
+ var actionType, actionFn, extensionKey, display, experienceId, markName, result, reason;
14
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
15
+ while (1) switch (_context.prev = _context.next) {
16
+ case 0:
17
+ actionType = _ref2.actionType, actionFn = _ref2.actionFn, extensionKey = _ref2.extensionKey, display = _ref2.display;
18
+ experienceId = uuid(); // Begin performance instrumentation.
19
+ markName = "".concat(experienceId, "-").concat(actionType);
20
+ measure.mark(markName, 'pending');
21
+ _context.prev = 4;
22
+ // Begin analytics instrumentation.
23
+ analytics === null || analytics === void 0 ? void 0 : analytics.ui.actionClickedEvent({
24
+ id: experienceId,
25
+ extensionKey: extensionKey,
26
+ actionType: actionType,
27
+ display: display,
28
+ invokeType: 'client'
29
+ });
30
+
31
+ // Invoke action
32
+ _context.next = 8;
33
+ return actionFn();
34
+ case 8:
35
+ result = _context.sent;
36
+ measure.mark(markName, 'resolved');
37
+ analytics === null || analytics === void 0 ? void 0 : analytics.operational.invokeSucceededEvent({
38
+ id: experienceId,
39
+ extensionKey: extensionKey,
40
+ actionType: actionType,
41
+ display: display
42
+ });
43
+ return _context.abrupt("return", result);
44
+ case 14:
45
+ _context.prev = 14;
46
+ _context.t0 = _context["catch"](4);
47
+ measure.mark(markName, 'errored');
48
+ reason = typeof _context.t0 === 'string' ? _context.t0 : _context.t0 === null || _context.t0 === void 0 ? void 0 : _context.t0.message;
49
+ analytics === null || analytics === void 0 ? void 0 : analytics.operational.invokeFailedEvent({
50
+ id: experienceId,
51
+ extensionKey: extensionKey,
52
+ actionType: actionType,
53
+ display: display,
54
+ reason: reason
55
+ });
56
+ case 19:
57
+ case "end":
58
+ return _context.stop();
59
+ }
60
+ }, _callee, null, [[4, 14]]);
61
+ }));
62
+ return function (_x) {
63
+ return _ref3.apply(this, arguments);
64
+ };
65
+ }(), [analytics === null || analytics === void 0 ? void 0 : analytics.operational, analytics === null || analytics === void 0 ? void 0 : analytics.ui]);
66
+ };
67
+ export default useInvokeClientAction;
@@ -13,7 +13,7 @@ export var ANALYTICS_CHANNEL = 'media';
13
13
  export var context = {
14
14
  componentName: 'smart-cards',
15
15
  packageName: "@atlaskit/smart-card",
16
- packageVersion: "26.20.1"
16
+ packageVersion: "26.22.0"
17
17
  };
18
18
  export var TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
19
19
  TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
@@ -113,9 +113,7 @@ export var invokeSucceededEvent = function invokeSucceededEvent(_ref2) {
113
113
  destinationProduct = _ref2.destinationProduct,
114
114
  destinationSubproduct = _ref2.destinationSubproduct,
115
115
  location = _ref2.location;
116
- var measure = getMeasure(id, 'resolved') || {
117
- duration: undefined
118
- };
116
+ var measure = id ? getMeasure(id, 'resolved') : undefined;
119
117
  return {
120
118
  action: 'resolved',
121
119
  actionSubject: 'smartLinkAction',
@@ -129,7 +127,7 @@ export var invokeSucceededEvent = function invokeSucceededEvent(_ref2) {
129
127
  destinationSubproduct: destinationSubproduct,
130
128
  location: location,
131
129
  extensionKey: extensionKey,
132
- duration: measure.duration
130
+ duration: measure === null || measure === void 0 ? void 0 : measure.duration
133
131
  })
134
132
  };
135
133
  };
@@ -143,9 +141,7 @@ export var invokeFailedEvent = function invokeFailedEvent(_ref3) {
143
141
  destinationProduct = _ref3.destinationProduct,
144
142
  destinationSubproduct = _ref3.destinationSubproduct,
145
143
  location = _ref3.location;
146
- var measure = getMeasure(id, 'errored') || {
147
- duration: undefined
148
- };
144
+ var measure = id ? getMeasure(id, 'errored') : undefined;
149
145
  return {
150
146
  action: 'unresolved',
151
147
  actionSubject: 'smartLinkAction',
@@ -159,7 +155,7 @@ export var invokeFailedEvent = function invokeFailedEvent(_ref3) {
159
155
  destinationProduct: destinationProduct,
160
156
  destinationSubproduct: destinationSubproduct,
161
157
  location: location,
162
- duration: measure.duration,
158
+ duration: measure === null || measure === void 0 ? void 0 : measure.duration,
163
159
  reason: reason
164
160
  })
165
161
  };
@@ -63,11 +63,12 @@ export var mocks = {
63
63
  name: 'I love cheese',
64
64
  summary: 'Here is your serving of cheese: 🧀',
65
65
  'schema:potentialAction': {
66
- '@id': 'comment',
67
- '@type': 'CommentAction',
66
+ '@id': 'download',
67
+ '@type': 'DownloadAction',
68
68
  identifier: 'object-provider',
69
- name: 'Comment'
69
+ name: 'Download'
70
70
  },
71
+ 'atlassian:downloadUrl': 'https://some-download.url',
71
72
  preview: {
72
73
  href: 'https://www.ilovecheese.com'
73
74
  },
@@ -290,12 +291,16 @@ export var waitFor = function waitFor() {
290
291
  };
291
292
  export var mockAnalytics = {
292
293
  ui: {
294
+ actionClickedEvent: function actionClickedEvent() {},
293
295
  buttonClickedEvent: function buttonClickedEvent() {},
294
296
  modalClosedEvent: function modalClosedEvent() {},
295
297
  renderSuccessEvent: function renderSuccessEvent() {},
296
298
  renderFailedEvent: function renderFailedEvent() {}
297
299
  },
298
- operational: {},
300
+ operational: {
301
+ invokeSucceededEvent: function invokeSucceededEvent() {},
302
+ invokeFailedEvent: function invokeFailedEvent() {}
303
+ },
299
304
  track: {},
300
305
  screen: {
301
306
  modalViewedEvent: function modalViewedEvent() {}