@atlaskit/smart-card 20.0.6 → 20.1.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 (51) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/cjs/state/actions/constants.js +4 -2
  3. package/dist/cjs/state/actions/index.js +51 -19
  4. package/dist/cjs/version.json +1 -1
  5. package/dist/cjs/view/BlockCard/index.js +29 -0
  6. package/dist/cjs/view/CardWithUrl/component.js +7 -2
  7. package/dist/cjs/view/CardWithUrl/loader.js +2 -0
  8. package/dist/cjs/view/EmbedCard/index.js +29 -0
  9. package/dist/cjs/view/FlexibleCard/index.js +34 -7
  10. package/dist/cjs/view/HoverCard/components/HoverCardContent.js +9 -1
  11. package/dist/cjs/view/InlineCard/index.js +29 -0
  12. package/dist/es2019/state/actions/constants.js +2 -1
  13. package/dist/es2019/state/actions/index.js +46 -18
  14. package/dist/es2019/version.json +1 -1
  15. package/dist/es2019/view/BlockCard/index.js +29 -0
  16. package/dist/es2019/view/CardWithUrl/component.js +7 -2
  17. package/dist/es2019/view/CardWithUrl/loader.js +2 -0
  18. package/dist/es2019/view/EmbedCard/index.js +29 -0
  19. package/dist/es2019/view/FlexibleCard/index.js +32 -7
  20. package/dist/es2019/view/HoverCard/components/HoverCardContent.js +6 -0
  21. package/dist/es2019/view/InlineCard/index.js +29 -0
  22. package/dist/esm/state/actions/constants.js +2 -1
  23. package/dist/esm/state/actions/index.js +51 -20
  24. package/dist/esm/version.json +1 -1
  25. package/dist/esm/view/BlockCard/index.js +29 -0
  26. package/dist/esm/view/CardWithUrl/component.js +7 -2
  27. package/dist/esm/view/CardWithUrl/loader.js +2 -0
  28. package/dist/esm/view/EmbedCard/index.js +29 -0
  29. package/dist/esm/view/FlexibleCard/index.js +33 -7
  30. package/dist/esm/view/HoverCard/components/HoverCardContent.js +8 -1
  31. package/dist/esm/view/InlineCard/index.js +29 -0
  32. package/dist/types/state/actions/constants.d.ts +1 -0
  33. package/dist/types/state/actions/index.d.ts +1 -0
  34. package/dist/types/state/hooks/useSmartLink.d.ts +1 -0
  35. package/dist/types/view/BlockCard/types.d.ts +2 -0
  36. package/dist/types/view/Card/index.d.ts +1 -1
  37. package/dist/types/view/Card/types.d.ts +2 -1
  38. package/dist/types/view/CardWithUrl/component.d.ts +1 -1
  39. package/dist/types/view/CardWithUrl/types.d.ts +2 -1
  40. package/dist/types/view/EmbedCard/components/styled.d.ts +16 -16
  41. package/dist/types/view/EmbedCard/types.d.ts +2 -0
  42. package/dist/types/view/FlexibleCard/types.d.ts +9 -4
  43. package/dist/types/view/HoverCard/types.d.ts +1 -0
  44. package/dist/types/view/InlineCard/Frame/styled.d.ts +1 -1
  45. package/dist/types/view/InlineCard/Icon.d.ts +3 -3
  46. package/dist/types/view/InlineCard/IconAndTitleLayout/styled.d.ts +9 -9
  47. package/dist/types/view/InlineCard/ResolvingView/styled.d.ts +13 -5
  48. package/dist/types/view/InlineCard/styled.d.ts +8 -4
  49. package/dist/types/view/InlineCard/types.d.ts +2 -1
  50. package/dist/types/view/types.d.ts +6 -0
  51. package/package.json +4 -4
@@ -1,10 +1,9 @@
1
1
  import { useMemo, useCallback } from 'react';
2
2
  import { auth } from '@atlaskit/outbound-auth-flow-client';
3
- import { APIError } from '@atlaskit/linking-common';
4
3
  import { useSmartLinkContext } from '@atlaskit/link-provider';
5
- import { ACTION_PENDING, ACTION_RESOLVED, ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, cardAction } from '@atlaskit/linking-common';
4
+ import { ACTION_PENDING, ACTION_RESOLVED, ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, ACTION_UPDATE_METADATA_STATUS, cardAction, APIError } from '@atlaskit/linking-common';
6
5
  import { getDefinitionId, getByDefinitionId, getServices, getStatus, getExtensionKey } from '../helpers';
7
- import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL } from './constants';
6
+ import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA } from './constants';
8
7
  import * as measure from '../../utils/performance';
9
8
  import { getUnauthorizedJsonLd } from '../../utils/jsonld';
10
9
  import { addMetadataToExperience } from '../analytics';
@@ -20,14 +19,26 @@ export const useSmartCardActions = (id, url, analytics) => {
20
19
  } = store;
21
20
  const {
22
21
  details,
23
- status
22
+ status,
23
+ metadataStatus
24
24
  } = getState()[url] || {
25
25
  status: 'pending',
26
26
  details: undefined
27
27
  };
28
28
  const hasAuthFlowSupported = config.authFlow !== 'disabled';
29
29
  const hasData = !!(details && details.data);
30
- const handleResolvedLinkError = useCallback((url, error, response) => {
30
+ const setMetadataStatus = useCallback(metadataStatus => {
31
+ dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
32
+ url
33
+ }, undefined, undefined, metadataStatus));
34
+ }, [dispatch, url]);
35
+ const handleResolvedLinkError = useCallback((url, error, response, isMetadataRequest) => {
36
+ // If metadata request then set metadata status, return and do not alter link status
37
+ if (isMetadataRequest) {
38
+ setMetadataStatus('errored');
39
+ return;
40
+ }
41
+
31
42
  if (error.kind === 'fatal') {
32
43
  // If there's no previous data in the store for this URL, then bail
33
44
  // out and let the editor handle fallbacks (returns to a blue link).
@@ -64,24 +75,32 @@ export const useSmartCardActions = (id, url, analytics) => {
64
75
  }, undefined, error));
65
76
  }
66
77
  }
67
- }, [hasData, status, dispatch, details]);
68
- const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false) => {
78
+ }, [setMetadataStatus, hasData, status, dispatch, details]);
79
+ const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false, isMetadataRequest) => {
69
80
  const hostname = new URL(resourceUrl).hostname;
70
81
  const nextStatus = response ? getStatus(response) : 'fatal'; // If we require authorization & do not have an authFlow available,
71
82
  // throw an error and render as a normal blue link.
72
83
 
73
84
  if ((nextStatus === 'unauthorized' || nextStatus === 'forbidden') && !hasAuthFlowSupported) {
74
- handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response);
85
+ handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response, isMetadataRequest);
75
86
  return;
76
87
  } // Handle any other errors
77
88
 
78
89
 
79
90
  if (nextStatus === 'fatal') {
80
- handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL));
91
+ handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL), undefined, isMetadataRequest);
81
92
  return;
82
- } // Dispatch Analytics and resolved card action - including unauthorized states.
93
+ } // Handle errors of any other kind in the metadata request response
83
94
 
84
95
 
96
+ if (isMetadataRequest && nextStatus !== 'resolved') {
97
+ handleResolvedLinkError(resourceUrl, new APIError('error', hostname, ERROR_MESSAGE_METADATA), response, isMetadataRequest);
98
+ return;
99
+ } //if a link resolves normally, metadata will also always be resolved
100
+
101
+
102
+ setMetadataStatus('resolved'); // Dispatch Analytics and resolved card action - including unauthorized states.
103
+
85
104
  if (isReloading) {
86
105
  dispatch(cardAction(ACTION_RELOADING, {
87
106
  url: resourceUrl
@@ -89,15 +108,15 @@ export const useSmartCardActions = (id, url, analytics) => {
89
108
  } else {
90
109
  dispatch(cardAction(ACTION_RESOLVED, {
91
110
  url: resourceUrl
92
- }, response));
111
+ }, response, undefined, undefined, isMetadataRequest));
93
112
  }
94
- }, [dispatch, handleResolvedLinkError, hasAuthFlowSupported]);
95
- const resolve = useCallback(async (resourceUrl = url, isReloading = false) => {
113
+ }, [dispatch, handleResolvedLinkError, hasAuthFlowSupported, setMetadataStatus]);
114
+ const resolve = useCallback(async (resourceUrl = url, isReloading = false, isMetadataRequest = false) => {
96
115
  // Request JSON-LD data for the card from ORS, iff it has extended
97
116
  // its cache lifespan OR there is no data for it currently. Once the data
98
117
  // has come back asynchronously, dispatch the resolved action for the card.
99
- if (isReloading || !hasData) {
100
- return connections.client.fetchData(resourceUrl).then(response => handleResolvedLinkResponse(resourceUrl, response, isReloading)).catch(error => handleResolvedLinkError(resourceUrl, error));
118
+ if (isReloading || !hasData || isMetadataRequest) {
119
+ return connections.client.fetchData(resourceUrl).then(response => handleResolvedLinkResponse(resourceUrl, response, isReloading, isMetadataRequest)).catch(error => handleResolvedLinkError(resourceUrl, error, undefined, isMetadataRequest));
101
120
  } else {
102
121
  addMetadataToExperience('smart-link-rendered', id, {
103
122
  cached: true
@@ -109,10 +128,11 @@ export const useSmartCardActions = (id, url, analytics) => {
109
128
  dispatch(cardAction(ACTION_PENDING, {
110
129
  url
111
130
  }));
131
+ setMetadataStatus('pending');
112
132
  }
113
133
 
114
134
  return resolve();
115
- }, [url, resolve, details, dispatch]);
135
+ }, [details, resolve, dispatch, url, setMetadataStatus]);
116
136
  const reload = useCallback(() => {
117
137
  const definitionId = getDefinitionId(details);
118
138
 
@@ -122,6 +142,13 @@ export const useSmartCardActions = (id, url, analytics) => {
122
142
  resolve(url, true);
123
143
  }
124
144
  }, [url, details, getState, resolve]);
145
+ const loadMetadata = useCallback(() => {
146
+ //metadataStatus will be undefined for SSR links only
147
+ if (metadataStatus === undefined) {
148
+ setMetadataStatus('pending');
149
+ return resolve(url, false, true);
150
+ }
151
+ }, [metadataStatus, resolve, setMetadataStatus, url]);
125
152
  const authorize = useCallback(appearance => {
126
153
  const definitionId = getDefinitionId(details);
127
154
  const extensionKey = getExtensionKey(details);
@@ -187,6 +214,7 @@ export const useSmartCardActions = (id, url, analytics) => {
187
214
  register,
188
215
  reload,
189
216
  authorize,
190
- invoke
191
- }), [register, reload, authorize, invoke]);
217
+ invoke,
218
+ loadMetadata
219
+ }), [register, reload, authorize, invoke, loadMetadata]);
192
220
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "20.0.6",
3
+ "version": "20.1.0",
4
4
  "sideEffects": false
5
5
  }
@@ -30,6 +30,7 @@ export const BlockCard = ({
30
30
  renderers,
31
31
  isSelected,
32
32
  onResolve,
33
+ onError,
33
34
  testId,
34
35
  showActions,
35
36
  platform
@@ -70,6 +71,13 @@ export const BlockCard = ({
70
71
  }));
71
72
 
72
73
  case 'unauthorized':
74
+ if (onError) {
75
+ onError({
76
+ url,
77
+ status
78
+ });
79
+ }
80
+
73
81
  const unauthorizedViewProps = extractBlockProps(data, meta, extractorOpts);
74
82
  return /*#__PURE__*/React.createElement(BlockCardUnauthorisedView, _extends({}, unauthorizedViewProps, {
75
83
  isSelected: isSelected,
@@ -80,6 +88,13 @@ export const BlockCard = ({
80
88
  }));
81
89
 
82
90
  case 'forbidden':
91
+ if (onError) {
92
+ onError({
93
+ url,
94
+ status
95
+ });
96
+ }
97
+
83
98
  const forbiddenViewProps = extractBlockProps(data, meta, extractorOpts);
84
99
  const cardMetadata = (_details$meta = details === null || details === void 0 ? void 0 : details.meta) !== null && _details$meta !== void 0 ? _details$meta : getUnauthorizedJsonLd().meta;
85
100
  const requestAccessContext = extractRequestAccessContext({
@@ -96,6 +111,13 @@ export const BlockCard = ({
96
111
  }));
97
112
 
98
113
  case 'not_found':
114
+ if (onError) {
115
+ onError({
116
+ url,
117
+ status
118
+ });
119
+ }
120
+
99
121
  const notFoundViewProps = extractBlockProps(data, meta, extractorOpts);
100
122
  return /*#__PURE__*/React.createElement(BlockCardNotFoundView, _extends({}, notFoundViewProps, {
101
123
  isSelected: isSelected,
@@ -105,6 +127,13 @@ export const BlockCard = ({
105
127
 
106
128
  case 'fallback':
107
129
  case 'errored':
130
+ if (onError) {
131
+ onError({
132
+ url,
133
+ status
134
+ });
135
+ }
136
+
108
137
  if (authFlow && authFlow === 'disabled') {
109
138
  return /*#__PURE__*/React.createElement(CardLinkView, {
110
139
  link: url,
@@ -20,6 +20,7 @@ export function CardWithUrlContent({
20
20
  appearance,
21
21
  dispatchAnalytics,
22
22
  onResolve,
23
+ onError,
23
24
  testId,
24
25
  showActions,
25
26
  inheritDimensions,
@@ -91,7 +92,7 @@ export function CardWithUrlContent({
91
92
  if (isFinalState(state.status)) {
92
93
  analytics.ui.renderSuccessEvent(appearance, state.status, id, definitionId, extensionKey);
93
94
  }
94
- }, [appearance, state.details, state.status, url, definitionId, extensionKey, analytics.ui, id]);
95
+ }, [appearance, state.status, url, definitionId, extensionKey, analytics.ui, id]);
95
96
 
96
97
  if (isFlexibleUi) {
97
98
  let cardState = state;
@@ -115,7 +116,8 @@ export function CardWithUrlContent({
115
116
  ui: ui,
116
117
  url: url,
117
118
  testId: testId,
118
- onResolve: onResolve
119
+ onResolve: onResolve,
120
+ onError: onError
119
121
  }, children);
120
122
  } // We have to keep this last to prevent hook order from being violated
121
123
 
@@ -135,6 +137,7 @@ export function CardWithUrlContent({
135
137
  handleFrameClick: handleClickWrapper,
136
138
  isSelected: isSelected,
137
139
  onResolve: onResolve,
140
+ onError: onError,
138
141
  testId: testId,
139
142
  inlinePreloaderStyle: inlinePreloaderStyle,
140
143
  showHoverPreview: showHoverPreview
@@ -154,6 +157,7 @@ export function CardWithUrlContent({
154
157
  handleAnalytics: dispatchAnalytics,
155
158
  isSelected: isSelected,
156
159
  onResolve: onResolve,
160
+ onError: onError,
157
161
  testId: testId,
158
162
  showActions: showActions,
159
163
  platform: platform
@@ -173,6 +177,7 @@ export function CardWithUrlContent({
173
177
  isFrameVisible: isFrameVisible,
174
178
  platform: platform,
175
179
  onResolve: onResolve,
180
+ onError: onError,
176
181
  testId: testId,
177
182
  inheritDimensions: inheritDimensions,
178
183
  showActions: showActions,
@@ -25,6 +25,7 @@ export function CardWithURLRenderer(props) {
25
25
  onClick,
26
26
  container,
27
27
  onResolve,
28
+ onError,
28
29
  testId,
29
30
  showActions,
30
31
  inheritDimensions,
@@ -85,6 +86,7 @@ export function CardWithURLRenderer(props) {
85
86
  dispatchAnalytics,
86
87
  container,
87
88
  onResolve,
89
+ onError,
88
90
  testId,
89
91
  showActions,
90
92
  inheritDimensions,
@@ -29,6 +29,7 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
29
29
  isFrameVisible,
30
30
  platform,
31
31
  onResolve,
32
+ onError,
32
33
  testId,
33
34
  inheritDimensions
34
35
  }, iframeRef) => {
@@ -91,6 +92,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
91
92
  }
92
93
 
93
94
  case 'unauthorized':
95
+ if (onError) {
96
+ onError({
97
+ url,
98
+ status
99
+ });
100
+ }
101
+
94
102
  const unauthorisedViewProps = extractEmbedProps(data, meta, platform);
95
103
  return /*#__PURE__*/React.createElement(EmbedCardUnauthorisedView, _extends({}, unauthorisedViewProps, {
96
104
  isSelected: isSelected,
@@ -100,6 +108,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
100
108
  }));
101
109
 
102
110
  case 'forbidden':
111
+ if (onError) {
112
+ onError({
113
+ url,
114
+ status
115
+ });
116
+ }
117
+
103
118
  const forbiddenViewProps = extractEmbedProps(data, meta, platform);
104
119
  const cardMetadata = (_details$meta = details === null || details === void 0 ? void 0 : details.meta) !== null && _details$meta !== void 0 ? _details$meta : getUnauthorizedJsonLd().meta;
105
120
  const requestAccessContext = extractRequestAccessContext({
@@ -116,6 +131,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
116
131
  }));
117
132
 
118
133
  case 'not_found':
134
+ if (onError) {
135
+ onError({
136
+ url,
137
+ status
138
+ });
139
+ }
140
+
119
141
  const notFoundViewProps = extractEmbedProps(data, meta, platform);
120
142
  return /*#__PURE__*/React.createElement(EmbedCardNotFoundView, _extends({}, notFoundViewProps, {
121
143
  isSelected: isSelected,
@@ -125,6 +147,13 @@ export const EmbedCard = /*#__PURE__*/React.forwardRef(({
125
147
 
126
148
  case 'fallback':
127
149
  case 'errored':
150
+ if (onError) {
151
+ onError({
152
+ url,
153
+ status
154
+ });
155
+ }
156
+
128
157
  return /*#__PURE__*/React.createElement(EmbedCardErroredView, {
129
158
  onRetry: handleErrorRetry,
130
159
  inheritDimensions: inheritDimensions,
@@ -1,5 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import React, { useEffect } from 'react';
3
+ import { SmartLinkStatus } from '../../constants';
3
4
  import Container from './components/container';
4
5
  import { FlexibleUiContext } from '../../state/flexible-ui-context';
5
6
  import { getContextByStatus, getRetryOptions } from './utils';
@@ -14,12 +15,13 @@ const FlexibleCard = ({
14
15
  cardState,
15
16
  children,
16
17
  onAuthorize,
18
+ onError,
19
+ onResolve,
17
20
  renderers,
18
21
  ui,
19
22
  url,
20
23
  onClick,
21
- testId,
22
- onResolve
24
+ testId
23
25
  }) => {
24
26
  const {
25
27
  status: cardType,
@@ -28,13 +30,36 @@ const FlexibleCard = ({
28
30
  const status = cardType;
29
31
  const context = getContextByStatus(url, status, details, renderers);
30
32
  const retry = getRetryOptions(url, status, details, onAuthorize);
33
+ const {
34
+ title
35
+ } = context || {};
31
36
  useEffect(() => {
32
- if (status === 'resolved' && onResolve) {
33
- onResolve({
34
- url
35
- });
37
+ switch (status) {
38
+ case SmartLinkStatus.Resolved:
39
+ if (onResolve) {
40
+ onResolve({
41
+ title,
42
+ url
43
+ });
44
+ }
45
+
46
+ break;
47
+
48
+ case SmartLinkStatus.Errored:
49
+ case SmartLinkStatus.Fallback:
50
+ case SmartLinkStatus.Forbidden:
51
+ case SmartLinkStatus.NotFound:
52
+ case SmartLinkStatus.Unauthorized:
53
+ if (onError) {
54
+ onError({
55
+ status,
56
+ url
57
+ });
58
+ }
59
+
60
+ break;
36
61
  }
37
- }, [onResolve, status, url]);
62
+ }, [onError, onResolve, status, title, url]);
38
63
  return /*#__PURE__*/React.createElement(FlexibleUiContext.Provider, {
39
64
  value: context
40
65
  }, /*#__PURE__*/React.createElement(Container, _extends({
@@ -4,6 +4,7 @@ import React, { useCallback, useEffect, useMemo } from 'react';
4
4
  import { ActionName, SmartLinkPosition, SmartLinkSize } from '../../../constants';
5
5
  import extractPreview from '../../../extractors/flexible/extract-preview';
6
6
  import { extractMetadata } from '../../../extractors/hover/extractMetadata';
7
+ import { useSmartCardActions } from '../../../state/actions';
7
8
  import { getExtensionKey } from '../../../state/helpers';
8
9
  import { isSpecialEvent } from '../../../utils';
9
10
  import FlexibleCard from '../../FlexibleCard';
@@ -41,6 +42,7 @@ export const toFooterActions = (cardActions, onActionClick) => cardActions.map(a
41
42
  }));
42
43
 
43
44
  const HoverCardContent = ({
45
+ id = '',
44
46
  analytics,
45
47
  cardActions = [],
46
48
  cardState,
@@ -51,6 +53,10 @@ const HoverCardContent = ({
51
53
  }) => {
52
54
  var _cardState$details;
53
55
 
56
+ const actions = useSmartCardActions(id, url, analytics);
57
+ useEffect(() => {
58
+ actions.loadMetadata();
59
+ }, [actions]);
54
60
  useEffect(() => {
55
61
  // Since hover preview only render on resolved status,
56
62
  // there is no need to check for statuses.
@@ -20,6 +20,7 @@ export const InlineCard = ({
20
20
  isSelected,
21
21
  renderers,
22
22
  onResolve,
23
+ onError,
23
24
  testId,
24
25
  inlinePreloaderStyle,
25
26
  showHoverPreview
@@ -64,6 +65,13 @@ export const InlineCard = ({
64
65
  }));
65
66
 
66
67
  case 'unauthorized':
68
+ if (onError) {
69
+ onError({
70
+ url,
71
+ status
72
+ });
73
+ }
74
+
67
75
  const provider = extractProvider(cardDetails);
68
76
  return /*#__PURE__*/React.createElement(InlineCardUnauthorizedView, {
69
77
  icon: provider && provider.icon,
@@ -75,6 +83,13 @@ export const InlineCard = ({
75
83
  });
76
84
 
77
85
  case 'forbidden':
86
+ if (onError) {
87
+ onError({
88
+ url,
89
+ status
90
+ });
91
+ }
92
+
78
93
  const providerForbidden = extractProvider(cardDetails);
79
94
  const cardMetadata = (_details$meta = details === null || details === void 0 ? void 0 : details.meta) !== null && _details$meta !== void 0 ? _details$meta : getUnauthorizedJsonLd().meta;
80
95
  const requestAccessContext = extractRequestAccessContext({
@@ -94,6 +109,13 @@ export const InlineCard = ({
94
109
  });
95
110
 
96
111
  case 'not_found':
112
+ if (onError) {
113
+ onError({
114
+ url,
115
+ status
116
+ });
117
+ }
118
+
97
119
  const providerNotFound = extractProvider(cardDetails);
98
120
  return /*#__PURE__*/React.createElement(InlineCardErroredView, {
99
121
  url: url,
@@ -106,6 +128,13 @@ export const InlineCard = ({
106
128
 
107
129
  case 'fallback':
108
130
  case 'errored':
131
+ if (onError) {
132
+ onError({
133
+ url,
134
+ status
135
+ });
136
+ }
137
+
109
138
  return /*#__PURE__*/React.createElement(CardLinkView, {
110
139
  link: url,
111
140
  isSelected: isSelected,
@@ -2,4 +2,5 @@ export var ANALYTICS_RESOLVING = 'resolving';
2
2
  export var ANALYTICS_ERROR = 'errored';
3
3
  export var ANALYTICS_FALLBACK = 'fallback';
4
4
  export var ERROR_MESSAGE_OAUTH = 'Provider.authFlow is not set to OAuth2.';
5
- export var ERROR_MESSAGE_FATAL = 'Fatal error resolving URL';
5
+ export var ERROR_MESSAGE_FATAL = 'Fatal error resolving URL';
6
+ export var ERROR_MESSAGE_METADATA = 'Error resolving metadata.';
@@ -2,11 +2,10 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
3
  import { useMemo, useCallback } from 'react';
4
4
  import { auth } from '@atlaskit/outbound-auth-flow-client';
5
- import { APIError } from '@atlaskit/linking-common';
6
5
  import { useSmartLinkContext } from '@atlaskit/link-provider';
7
- import { ACTION_PENDING, ACTION_RESOLVED, ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, cardAction } from '@atlaskit/linking-common';
6
+ import { ACTION_PENDING, ACTION_RESOLVED, ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, ACTION_UPDATE_METADATA_STATUS, cardAction, APIError } from '@atlaskit/linking-common';
8
7
  import { getDefinitionId, getByDefinitionId, getServices, getStatus, getExtensionKey } from '../helpers';
9
- import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL } from './constants';
8
+ import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA } from './constants';
10
9
  import * as measure from '../../utils/performance';
11
10
  import { getUnauthorizedJsonLd } from '../../utils/jsonld';
12
11
  import { addMetadataToExperience } from '../analytics';
@@ -24,11 +23,23 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
24
23
  details: undefined
25
24
  },
26
25
  details = _ref.details,
27
- status = _ref.status;
26
+ status = _ref.status,
27
+ metadataStatus = _ref.metadataStatus;
28
28
 
29
29
  var hasAuthFlowSupported = config.authFlow !== 'disabled';
30
30
  var hasData = !!(details && details.data);
31
- var handleResolvedLinkError = useCallback(function (url, error, response) {
31
+ var setMetadataStatus = useCallback(function (metadataStatus) {
32
+ dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
33
+ url: url
34
+ }, undefined, undefined, metadataStatus));
35
+ }, [dispatch, url]);
36
+ var handleResolvedLinkError = useCallback(function (url, error, response, isMetadataRequest) {
37
+ // If metadata request then set metadata status, return and do not alter link status
38
+ if (isMetadataRequest) {
39
+ setMetadataStatus('errored');
40
+ return;
41
+ }
42
+
32
43
  if (error.kind === 'fatal') {
33
44
  // If there's no previous data in the store for this URL, then bail
34
45
  // out and let the editor handle fallbacks (returns to a blue link).
@@ -65,25 +76,34 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
65
76
  }, undefined, error));
66
77
  }
67
78
  }
68
- }, [hasData, status, dispatch, details]);
79
+ }, [setMetadataStatus, hasData, status, dispatch, details]);
69
80
  var handleResolvedLinkResponse = useCallback(function (resourceUrl, response) {
70
81
  var isReloading = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
82
+ var isMetadataRequest = arguments.length > 3 ? arguments[3] : undefined;
71
83
  var hostname = new URL(resourceUrl).hostname;
72
84
  var nextStatus = response ? getStatus(response) : 'fatal'; // If we require authorization & do not have an authFlow available,
73
85
  // throw an error and render as a normal blue link.
74
86
 
75
87
  if ((nextStatus === 'unauthorized' || nextStatus === 'forbidden') && !hasAuthFlowSupported) {
76
- handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response);
88
+ handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response, isMetadataRequest);
77
89
  return;
78
90
  } // Handle any other errors
79
91
 
80
92
 
81
93
  if (nextStatus === 'fatal') {
82
- handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL));
94
+ handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL), undefined, isMetadataRequest);
95
+ return;
96
+ } // Handle errors of any other kind in the metadata request response
97
+
98
+
99
+ if (isMetadataRequest && nextStatus !== 'resolved') {
100
+ handleResolvedLinkError(resourceUrl, new APIError('error', hostname, ERROR_MESSAGE_METADATA), response, isMetadataRequest);
83
101
  return;
84
- } // Dispatch Analytics and resolved card action - including unauthorized states.
102
+ } //if a link resolves normally, metadata will also always be resolved
85
103
 
86
104
 
105
+ setMetadataStatus('resolved'); // Dispatch Analytics and resolved card action - including unauthorized states.
106
+
87
107
  if (isReloading) {
88
108
  dispatch(cardAction(ACTION_RELOADING, {
89
109
  url: resourceUrl
@@ -91,12 +111,13 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
91
111
  } else {
92
112
  dispatch(cardAction(ACTION_RESOLVED, {
93
113
  url: resourceUrl
94
- }, response));
114
+ }, response, undefined, undefined, isMetadataRequest));
95
115
  }
96
- }, [dispatch, handleResolvedLinkError, hasAuthFlowSupported]);
116
+ }, [dispatch, handleResolvedLinkError, hasAuthFlowSupported, setMetadataStatus]);
97
117
  var resolve = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
98
118
  var resourceUrl,
99
119
  isReloading,
120
+ isMetadataRequest,
100
121
  _args = arguments;
101
122
  return _regeneratorRuntime.wrap(function _callee$(_context) {
102
123
  while (1) {
@@ -104,24 +125,25 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
104
125
  case 0:
105
126
  resourceUrl = _args.length > 0 && _args[0] !== undefined ? _args[0] : url;
106
127
  isReloading = _args.length > 1 && _args[1] !== undefined ? _args[1] : false;
128
+ isMetadataRequest = _args.length > 2 && _args[2] !== undefined ? _args[2] : false;
107
129
 
108
- if (!(isReloading || !hasData)) {
109
- _context.next = 6;
130
+ if (!(isReloading || !hasData || isMetadataRequest)) {
131
+ _context.next = 7;
110
132
  break;
111
133
  }
112
134
 
113
135
  return _context.abrupt("return", connections.client.fetchData(resourceUrl).then(function (response) {
114
- return handleResolvedLinkResponse(resourceUrl, response, isReloading);
136
+ return handleResolvedLinkResponse(resourceUrl, response, isReloading, isMetadataRequest);
115
137
  }).catch(function (error) {
116
- return handleResolvedLinkError(resourceUrl, error);
138
+ return handleResolvedLinkError(resourceUrl, error, undefined, isMetadataRequest);
117
139
  }));
118
140
 
119
- case 6:
141
+ case 7:
120
142
  addMetadataToExperience('smart-link-rendered', id, {
121
143
  cached: true
122
144
  });
123
145
 
124
- case 7:
146
+ case 8:
125
147
  case "end":
126
148
  return _context.stop();
127
149
  }
@@ -133,10 +155,11 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
133
155
  dispatch(cardAction(ACTION_PENDING, {
134
156
  url: url
135
157
  }));
158
+ setMetadataStatus('pending');
136
159
  }
137
160
 
138
161
  return resolve();
139
- }, [url, resolve, details, dispatch]);
162
+ }, [details, resolve, dispatch, url, setMetadataStatus]);
140
163
  var reload = useCallback(function () {
141
164
  var definitionId = getDefinitionId(details);
142
165
 
@@ -148,6 +171,13 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
148
171
  resolve(url, true);
149
172
  }
150
173
  }, [url, details, getState, resolve]);
174
+ var loadMetadata = useCallback(function () {
175
+ //metadataStatus will be undefined for SSR links only
176
+ if (metadataStatus === undefined) {
177
+ setMetadataStatus('pending');
178
+ return resolve(url, false, true);
179
+ }
180
+ }, [metadataStatus, resolve, setMetadataStatus, url]);
151
181
  var authorize = useCallback(function (appearance) {
152
182
  var definitionId = getDefinitionId(details);
153
183
  var extensionKey = getExtensionKey(details);
@@ -243,7 +273,8 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
243
273
  register: register,
244
274
  reload: reload,
245
275
  authorize: authorize,
246
- invoke: invoke
276
+ invoke: invoke,
277
+ loadMetadata: loadMetadata
247
278
  };
248
- }, [register, reload, authorize, invoke]);
279
+ }, [register, reload, authorize, invoke, loadMetadata]);
249
280
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "20.0.6",
3
+ "version": "20.1.0",
4
4
  "sideEffects": false
5
5
  }