@atlaskit/smart-card 25.4.1 → 25.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/cjs/state/actions/index.js +10 -132
- package/dist/cjs/state/hooks/use-resolve/index.js +169 -0
- package/dist/cjs/version.json +1 -1
- package/dist/cjs/view/FlexibleCard/components/common/lozenge-action/index.js +23 -13
- package/dist/es2019/state/actions/index.js +8 -125
- package/dist/es2019/state/hooks/use-resolve/index.js +131 -0
- package/dist/es2019/version.json +1 -1
- package/dist/es2019/view/FlexibleCard/components/common/lozenge-action/index.js +13 -3
- package/dist/esm/state/actions/index.js +10 -132
- package/dist/esm/state/hooks/use-resolve/index.js +161 -0
- package/dist/esm/version.json +1 -1
- package/dist/esm/view/FlexibleCard/components/common/lozenge-action/index.js +23 -13
- package/dist/types/extractors/common/__mocks__/jsonld.d.ts +4 -224
- package/dist/types/state/hooks/use-invoke/types.d.ts +3 -1
- package/dist/types/state/hooks/use-resolve/index.d.ts +2 -0
- package/package.json +4 -4
- package/report.api.md +1 -1
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { useMemo, useCallback } from 'react';
|
|
2
2
|
import { auth } from '@atlaskit/outbound-auth-flow-client';
|
|
3
3
|
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
4
|
-
import {
|
|
5
|
-
import { getDefinitionId, getByDefinitionId, getServices,
|
|
6
|
-
import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA } from './constants';
|
|
4
|
+
import { ACTION_UPDATE_METADATA_STATUS, cardAction, ACTION_RESOLVING } from '@atlaskit/linking-common';
|
|
5
|
+
import { getDefinitionId, getByDefinitionId, getServices, getExtensionKey } from '../helpers';
|
|
7
6
|
import * as measure from '../../utils/performance';
|
|
8
|
-
import { getUnauthorizedJsonLd } from '../../utils/jsonld';
|
|
9
|
-
import { addMetadataToExperience } from '../analytics';
|
|
10
7
|
import { SmartLinkStatus } from '../../constants';
|
|
11
|
-
import
|
|
8
|
+
import useResolve from '../hooks/use-resolve';
|
|
12
9
|
export const useSmartCardActions = (id, url, analytics) => {
|
|
10
|
+
const resolveUrl = useResolve();
|
|
13
11
|
const {
|
|
14
12
|
store,
|
|
15
|
-
connections
|
|
16
|
-
config
|
|
13
|
+
connections
|
|
17
14
|
} = useSmartLinkContext();
|
|
18
15
|
const {
|
|
19
16
|
getState,
|
|
@@ -27,103 +24,12 @@ export const useSmartCardActions = (id, url, analytics) => {
|
|
|
27
24
|
status: SmartLinkStatus.Pending,
|
|
28
25
|
details: undefined
|
|
29
26
|
};
|
|
30
|
-
const hasAuthFlowSupported = config.authFlow !== 'disabled';
|
|
31
|
-
const hasData = !!(details && details.data);
|
|
32
27
|
const setMetadataStatus = useCallback(metadataStatus => {
|
|
33
28
|
dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
|
|
34
29
|
url
|
|
35
30
|
}, undefined, undefined, metadataStatus));
|
|
36
31
|
}, [dispatch, url]);
|
|
37
|
-
const
|
|
38
|
-
// If metadata request then set metadata status, return and do not alter link status
|
|
39
|
-
if (isMetadataRequest) {
|
|
40
|
-
setMetadataStatus('errored');
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
if (error.kind === 'fatal') {
|
|
44
|
-
// If there's no previous data in the store for this URL, then bail
|
|
45
|
-
// out and let the editor handle fallbacks (returns to a blue link).
|
|
46
|
-
if (!hasData && status !== 'resolved') {
|
|
47
|
-
dispatch(cardAction(ACTION_ERROR, {
|
|
48
|
-
url
|
|
49
|
-
}, details, error));
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
52
|
-
// If we already have resolved data for this URL in the store, then
|
|
53
|
-
// simply fallback to the previous data.
|
|
54
|
-
if (hasData) {
|
|
55
|
-
dispatch(cardAction(ACTION_RESOLVED, {
|
|
56
|
-
url
|
|
57
|
-
}, details));
|
|
58
|
-
}
|
|
59
|
-
// Handle AuthErrors (user did not have access to resource) -
|
|
60
|
-
// Missing AAID in ASAP claims, or missing UserContext, or 403 from downstream
|
|
61
|
-
} else if (error.kind === 'auth') {
|
|
62
|
-
dispatch(cardAction(ACTION_RESOLVED, {
|
|
63
|
-
url
|
|
64
|
-
}, getUnauthorizedJsonLd()));
|
|
65
|
-
} else {
|
|
66
|
-
if (error.kind === 'fallback') {
|
|
67
|
-
// Fallback to blue link with smart link formatting. Not part of reliability.
|
|
68
|
-
dispatch(cardAction(ACTION_ERROR_FALLBACK, {
|
|
69
|
-
url
|
|
70
|
-
}, response, error));
|
|
71
|
-
} else {
|
|
72
|
-
// Fallback to blue link with smart link formatting. Part of reliability.
|
|
73
|
-
dispatch(cardAction(ACTION_ERROR, {
|
|
74
|
-
url
|
|
75
|
-
}, undefined, error));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}, [setMetadataStatus, hasData, status, dispatch, details]);
|
|
79
|
-
const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false, isMetadataRequest) => {
|
|
80
|
-
const hostname = new URL(resourceUrl).hostname;
|
|
81
|
-
const nextStatus = response ? getStatus(response) : 'fatal';
|
|
82
|
-
|
|
83
|
-
// If we require authorization & do not have an authFlow available,
|
|
84
|
-
// throw an error and render as a normal blue link.
|
|
85
|
-
if ((nextStatus === 'unauthorized' || nextStatus === 'forbidden') && !hasAuthFlowSupported) {
|
|
86
|
-
handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response, isMetadataRequest);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Handle any other errors
|
|
91
|
-
if (nextStatus === 'fatal') {
|
|
92
|
-
handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL), undefined, isMetadataRequest);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Handle errors of any other kind in the metadata request response
|
|
97
|
-
if (isMetadataRequest && nextStatus !== 'resolved') {
|
|
98
|
-
handleResolvedLinkError(resourceUrl, new APIError('error', hostname, ERROR_MESSAGE_METADATA), response, isMetadataRequest);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
//if a link resolves normally, metadata will also always be resolved
|
|
103
|
-
setMetadataStatus('resolved');
|
|
104
|
-
// Dispatch Analytics and resolved card action - including unauthorized states.
|
|
105
|
-
if (isReloading) {
|
|
106
|
-
dispatch(cardAction(ACTION_RELOADING, {
|
|
107
|
-
url: resourceUrl
|
|
108
|
-
}, response));
|
|
109
|
-
} else {
|
|
110
|
-
dispatch(cardAction(ACTION_RESOLVED, {
|
|
111
|
-
url: resourceUrl
|
|
112
|
-
}, response, undefined, undefined, isMetadataRequest));
|
|
113
|
-
}
|
|
114
|
-
}, [dispatch, handleResolvedLinkError, hasAuthFlowSupported, setMetadataStatus]);
|
|
115
|
-
const resolve = useCallback(async (resourceUrl = url, isReloading = false, isMetadataRequest = false) => {
|
|
116
|
-
// Request JSON-LD data for the card from ORS, if it has extended
|
|
117
|
-
// its cache lifespan OR there is no data for it currently. Once the data
|
|
118
|
-
// has come back asynchronously, dispatch the resolved action for the card.
|
|
119
|
-
if (isReloading || !hasData || isMetadataRequest) {
|
|
120
|
-
return connections.client.fetchData(resourceUrl, isReloading).then(response => handleResolvedLinkResponse(resourceUrl, response, isReloading, isMetadataRequest)).catch(error => handleResolvedLinkError(resourceUrl, error, undefined, isMetadataRequest));
|
|
121
|
-
} else {
|
|
122
|
-
addMetadataToExperience('smart-link-rendered', id, {
|
|
123
|
-
cached: true
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
}, [url, hasData, connections.client, handleResolvedLinkResponse, handleResolvedLinkError, id]);
|
|
32
|
+
const resolve = useCallback(async (resourceUrl = url, isReloading = false, isMetadataRequest = false) => resolveUrl(resourceUrl, isReloading, isMetadataRequest, id), [id, resolveUrl, url]);
|
|
127
33
|
const register = useCallback(() => {
|
|
128
34
|
if (!details) {
|
|
129
35
|
dispatch(cardAction(ACTION_RESOLVING, {
|
|
@@ -134,36 +40,13 @@ export const useSmartCardActions = (id, url, analytics) => {
|
|
|
134
40
|
return resolve();
|
|
135
41
|
}, [details, resolve, dispatch, url, setMetadataStatus]);
|
|
136
42
|
const reload = useCallback(() => {
|
|
137
|
-
var _details$data, _details$data$Type;
|
|
138
43
|
const definitionId = getDefinitionId(details);
|
|
139
|
-
|
|
140
|
-
// Start: Smart link Actions experiment
|
|
141
|
-
if (definitionId === 'jira-object-provider' && details !== null && details !== void 0 && (_details$data = details.data) !== null && _details$data !== void 0 && (_details$data$Type = _details$data['@type']) !== null && _details$data$Type !== void 0 && _details$data$Type.includes('atlassian:Task')) {
|
|
142
|
-
// EDM-5149: This is part of actionable element experiment where we
|
|
143
|
-
// reload jira issue link after embed view modal is closed.
|
|
144
|
-
// In our component, `reload` is only used in auth flow which
|
|
145
|
-
// jira link, being Atlassian product, would not fall into this category
|
|
146
|
-
// and would not be reloaded in normal smart link context.
|
|
147
|
-
// The code from resolve is duplicated here to avoid changing the response
|
|
148
|
-
// shape of resolve.
|
|
149
|
-
const previousJiraStatus = extractLozengeText(details);
|
|
150
|
-
connections.client.fetchData(url, true).then(response => {
|
|
151
|
-
handleResolvedLinkResponse(url, response, true, false);
|
|
152
|
-
const jiraStatus = extractLozengeText(response);
|
|
153
|
-
analytics.track.linkUpdated({
|
|
154
|
-
actionSubjectId: 'jiraIssueStatus',
|
|
155
|
-
previousJiraStatus,
|
|
156
|
-
jiraStatus
|
|
157
|
-
});
|
|
158
|
-
}).catch(error => handleResolvedLinkError(url, error, undefined, false));
|
|
159
|
-
}
|
|
160
|
-
// End: Smart ink Actions experiment
|
|
161
|
-
else if (definitionId) {
|
|
44
|
+
if (definitionId) {
|
|
162
45
|
getByDefinitionId(definitionId, getState()).map(url => resolve(url, true));
|
|
163
46
|
} else {
|
|
164
47
|
resolve(url, true);
|
|
165
48
|
}
|
|
166
|
-
}, [details,
|
|
49
|
+
}, [details, url, getState, resolve]);
|
|
167
50
|
const loadMetadata = useCallback(() => {
|
|
168
51
|
//metadataStatus will be undefined for SSR links only
|
|
169
52
|
if (metadataStatus === undefined) {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { addMetadataToExperience } from '../../analytics';
|
|
3
|
+
import { getStatus } from '../../helpers';
|
|
4
|
+
import { ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, ACTION_RESOLVED, ACTION_UPDATE_METADATA_STATUS, APIError, cardAction } from '@atlaskit/linking-common';
|
|
5
|
+
import { ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA, ERROR_MESSAGE_OAUTH } from '../../actions/constants';
|
|
6
|
+
import { getUnauthorizedJsonLd } from '../../../utils/jsonld';
|
|
7
|
+
import { SmartLinkStatus } from '../../../constants';
|
|
8
|
+
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
9
|
+
const useResolve = () => {
|
|
10
|
+
// Request JSON-LD data for the card from ORS, if it has extended
|
|
11
|
+
// its cache lifespan OR there is no data for it currently. Once the data
|
|
12
|
+
// has come back asynchronously, dispatch the resolved action for the card.
|
|
13
|
+
const {
|
|
14
|
+
store,
|
|
15
|
+
connections,
|
|
16
|
+
config
|
|
17
|
+
} = useSmartLinkContext();
|
|
18
|
+
const {
|
|
19
|
+
getState,
|
|
20
|
+
dispatch
|
|
21
|
+
} = store;
|
|
22
|
+
const hasAuthFlowSupported = config.authFlow !== 'disabled';
|
|
23
|
+
const setMetadataStatus = useCallback((url, metadataStatus) => {
|
|
24
|
+
dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
|
|
25
|
+
url
|
|
26
|
+
}, undefined, undefined, metadataStatus));
|
|
27
|
+
}, [dispatch]);
|
|
28
|
+
const handleResolvedLinkError = useCallback((url, error, response, isMetadataRequest) => {
|
|
29
|
+
const {
|
|
30
|
+
details
|
|
31
|
+
} = getState()[url] || {
|
|
32
|
+
status: SmartLinkStatus.Pending,
|
|
33
|
+
details: undefined
|
|
34
|
+
};
|
|
35
|
+
const hasData = !!(details && details.data);
|
|
36
|
+
|
|
37
|
+
// If metadata request then set metadata status, return and do not alter link status
|
|
38
|
+
if (isMetadataRequest) {
|
|
39
|
+
setMetadataStatus(url, 'errored');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (error.kind === 'fatal') {
|
|
43
|
+
// If there's no previous data in the store for this URL, then bail
|
|
44
|
+
// out and let the editor handle fallbacks (returns to a blue link).
|
|
45
|
+
if (!hasData && status !== 'resolved') {
|
|
46
|
+
dispatch(cardAction(ACTION_ERROR, {
|
|
47
|
+
url
|
|
48
|
+
}, details, error));
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
// If we already have resolved data for this URL in the store, then
|
|
52
|
+
// simply fallback to the previous data.
|
|
53
|
+
if (hasData) {
|
|
54
|
+
dispatch(cardAction(ACTION_RESOLVED, {
|
|
55
|
+
url
|
|
56
|
+
}, details));
|
|
57
|
+
}
|
|
58
|
+
// Handle AuthErrors (user did not have access to resource) -
|
|
59
|
+
// Missing AAID in ASAP claims, or missing UserContext, or 403 from downstream
|
|
60
|
+
} else if (error.kind === 'auth') {
|
|
61
|
+
dispatch(cardAction(ACTION_RESOLVED, {
|
|
62
|
+
url
|
|
63
|
+
}, getUnauthorizedJsonLd()));
|
|
64
|
+
} else {
|
|
65
|
+
if (error.kind === 'fallback') {
|
|
66
|
+
// Fallback to blue link with smart link formatting. Not part of reliability.
|
|
67
|
+
dispatch(cardAction(ACTION_ERROR_FALLBACK, {
|
|
68
|
+
url
|
|
69
|
+
}, response, error));
|
|
70
|
+
} else {
|
|
71
|
+
// Fallback to blue link with smart link formatting. Part of reliability.
|
|
72
|
+
dispatch(cardAction(ACTION_ERROR, {
|
|
73
|
+
url
|
|
74
|
+
}, undefined, error));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}, [getState, setMetadataStatus, dispatch]);
|
|
78
|
+
const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false, isMetadataRequest) => {
|
|
79
|
+
const hostname = new URL(resourceUrl).hostname;
|
|
80
|
+
const nextStatus = response ? getStatus(response) : 'fatal';
|
|
81
|
+
|
|
82
|
+
// If we require authorization & do not have an authFlow available,
|
|
83
|
+
// throw an error and render as a normal blue link.
|
|
84
|
+
if ((nextStatus === 'unauthorized' || nextStatus === 'forbidden') && !hasAuthFlowSupported) {
|
|
85
|
+
handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response, isMetadataRequest);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Handle any other errors
|
|
90
|
+
if (nextStatus === 'fatal') {
|
|
91
|
+
handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL), undefined, isMetadataRequest);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Handle errors of any other kind in the metadata request response
|
|
96
|
+
if (isMetadataRequest && nextStatus !== 'resolved') {
|
|
97
|
+
handleResolvedLinkError(resourceUrl, new APIError('error', hostname, ERROR_MESSAGE_METADATA), response, isMetadataRequest);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//if a link resolves normally, metadata will also always be resolved
|
|
102
|
+
setMetadataStatus(resourceUrl, 'resolved');
|
|
103
|
+
// Dispatch Analytics and resolved card action - including unauthorized states.
|
|
104
|
+
if (isReloading) {
|
|
105
|
+
dispatch(cardAction(ACTION_RELOADING, {
|
|
106
|
+
url: resourceUrl
|
|
107
|
+
}, response));
|
|
108
|
+
} else {
|
|
109
|
+
dispatch(cardAction(ACTION_RESOLVED, {
|
|
110
|
+
url: resourceUrl
|
|
111
|
+
}, response, undefined, undefined, isMetadataRequest));
|
|
112
|
+
}
|
|
113
|
+
}, [dispatch, handleResolvedLinkError, hasAuthFlowSupported, setMetadataStatus]);
|
|
114
|
+
return useCallback(async (url, isReloading = false, isMetadataRequest = false, id = '') => {
|
|
115
|
+
const {
|
|
116
|
+
details
|
|
117
|
+
} = getState()[url] || {
|
|
118
|
+
status: SmartLinkStatus.Pending,
|
|
119
|
+
details: undefined
|
|
120
|
+
};
|
|
121
|
+
const hasData = !!(details && details.data);
|
|
122
|
+
if (isReloading || !hasData || isMetadataRequest) {
|
|
123
|
+
return connections.client.fetchData(url, isReloading).then(response => handleResolvedLinkResponse(url, response, isReloading, isMetadataRequest)).catch(error => handleResolvedLinkError(url, error, undefined, isMetadataRequest));
|
|
124
|
+
} else {
|
|
125
|
+
addMetadataToExperience('smart-link-rendered', id, {
|
|
126
|
+
cached: true
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}, [connections.client, getState, handleResolvedLinkError, handleResolvedLinkResponse]);
|
|
130
|
+
};
|
|
131
|
+
export default useResolve;
|
package/dist/es2019/version.json
CHANGED
|
@@ -12,6 +12,7 @@ import useInvoke from '../../../../../state/hooks/use-invoke';
|
|
|
12
12
|
import { InvokeActionError } from '../../../../../state/hooks/use-invoke/types';
|
|
13
13
|
import extractLozengeActionItems from '../../../../../extractors/action/extract-lozenge-action-items';
|
|
14
14
|
import createStatusUpdateRequest from '../../../../../utils/actions/create-status-update-request';
|
|
15
|
+
import useResolve from '../../../../../state/hooks/use-resolve';
|
|
15
16
|
const validateItems = (items = [], text) => {
|
|
16
17
|
return items.filter(item => item.text !== text);
|
|
17
18
|
};
|
|
@@ -27,6 +28,7 @@ const LozengeAction = ({
|
|
|
27
28
|
const [items, setItems] = useState();
|
|
28
29
|
const [errorCode, setErrorCode] = useState();
|
|
29
30
|
const invoke = useInvoke();
|
|
31
|
+
const reload = useResolve();
|
|
30
32
|
const handleOpenChange = useCallback(async args => {
|
|
31
33
|
setIsOpen(args.isOpen);
|
|
32
34
|
if (args.isOpen && !isLoaded && action !== null && action !== void 0 && action.read) {
|
|
@@ -57,19 +59,27 @@ const LozengeAction = ({
|
|
|
57
59
|
})), [appearance, testId, text]);
|
|
58
60
|
const handleItemClick = useCallback(async id => {
|
|
59
61
|
try {
|
|
60
|
-
|
|
62
|
+
const updateAction = action === null || action === void 0 ? void 0 : action.update;
|
|
63
|
+
if (updateAction && id) {
|
|
61
64
|
setIsLoading(true);
|
|
62
|
-
const request = createStatusUpdateRequest(
|
|
65
|
+
const request = createStatusUpdateRequest(updateAction, id);
|
|
63
66
|
await invoke(request);
|
|
64
67
|
setIsLoading(false);
|
|
65
68
|
setIsOpen(false);
|
|
69
|
+
const {
|
|
70
|
+
url,
|
|
71
|
+
id: linkId
|
|
72
|
+
} = updateAction.details || {};
|
|
73
|
+
if (url) {
|
|
74
|
+
await reload(url, true, undefined, linkId);
|
|
75
|
+
}
|
|
66
76
|
}
|
|
67
77
|
} catch (err) {
|
|
68
78
|
// TODO: EDM-6261: Error state
|
|
69
79
|
setIsLoading(false);
|
|
70
80
|
setErrorCode(InvokeActionError.Unknown);
|
|
71
81
|
}
|
|
72
|
-
}, [action === null || action === void 0 ? void 0 : action.update, invoke]);
|
|
82
|
+
}, [action === null || action === void 0 ? void 0 : action.update, invoke, reload]);
|
|
73
83
|
const dropdownItemGroup = useMemo(() => {
|
|
74
84
|
if (errorCode) {
|
|
75
85
|
return jsx(LozengeActionError, {
|
|
@@ -4,19 +4,16 @@ function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyri
|
|
|
4
4
|
import { useMemo, useCallback } from 'react';
|
|
5
5
|
import { auth } from '@atlaskit/outbound-auth-flow-client';
|
|
6
6
|
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
7
|
-
import {
|
|
8
|
-
import { getDefinitionId, getByDefinitionId, getServices,
|
|
9
|
-
import { ERROR_MESSAGE_OAUTH, ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA } from './constants';
|
|
7
|
+
import { ACTION_UPDATE_METADATA_STATUS, cardAction, ACTION_RESOLVING } from '@atlaskit/linking-common';
|
|
8
|
+
import { getDefinitionId, getByDefinitionId, getServices, getExtensionKey } from '../helpers';
|
|
10
9
|
import * as measure from '../../utils/performance';
|
|
11
|
-
import { getUnauthorizedJsonLd } from '../../utils/jsonld';
|
|
12
|
-
import { addMetadataToExperience } from '../analytics';
|
|
13
10
|
import { SmartLinkStatus } from '../../constants';
|
|
14
|
-
import
|
|
11
|
+
import useResolve from '../hooks/use-resolve';
|
|
15
12
|
export var useSmartCardActions = function useSmartCardActions(id, url, analytics) {
|
|
13
|
+
var resolveUrl = useResolve();
|
|
16
14
|
var _useSmartLinkContext = useSmartLinkContext(),
|
|
17
15
|
store = _useSmartLinkContext.store,
|
|
18
|
-
connections = _useSmartLinkContext.connections
|
|
19
|
-
config = _useSmartLinkContext.config;
|
|
16
|
+
connections = _useSmartLinkContext.connections;
|
|
20
17
|
var getState = store.getState,
|
|
21
18
|
dispatch = store.dispatch;
|
|
22
19
|
var _ref = getState()[url] || {
|
|
@@ -26,93 +23,11 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
|
|
|
26
23
|
details = _ref.details,
|
|
27
24
|
status = _ref.status,
|
|
28
25
|
metadataStatus = _ref.metadataStatus;
|
|
29
|
-
var hasAuthFlowSupported = config.authFlow !== 'disabled';
|
|
30
|
-
var hasData = !!(details && details.data);
|
|
31
26
|
var setMetadataStatus = useCallback(function (metadataStatus) {
|
|
32
27
|
dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
|
|
33
28
|
url: url
|
|
34
29
|
}, undefined, undefined, metadataStatus));
|
|
35
30
|
}, [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
|
-
if (error.kind === 'fatal') {
|
|
43
|
-
// If there's no previous data in the store for this URL, then bail
|
|
44
|
-
// out and let the editor handle fallbacks (returns to a blue link).
|
|
45
|
-
if (!hasData && status !== 'resolved') {
|
|
46
|
-
dispatch(cardAction(ACTION_ERROR, {
|
|
47
|
-
url: url
|
|
48
|
-
}, details, error));
|
|
49
|
-
throw error;
|
|
50
|
-
}
|
|
51
|
-
// If we already have resolved data for this URL in the store, then
|
|
52
|
-
// simply fallback to the previous data.
|
|
53
|
-
if (hasData) {
|
|
54
|
-
dispatch(cardAction(ACTION_RESOLVED, {
|
|
55
|
-
url: url
|
|
56
|
-
}, details));
|
|
57
|
-
}
|
|
58
|
-
// Handle AuthErrors (user did not have access to resource) -
|
|
59
|
-
// Missing AAID in ASAP claims, or missing UserContext, or 403 from downstream
|
|
60
|
-
} else if (error.kind === 'auth') {
|
|
61
|
-
dispatch(cardAction(ACTION_RESOLVED, {
|
|
62
|
-
url: url
|
|
63
|
-
}, getUnauthorizedJsonLd()));
|
|
64
|
-
} else {
|
|
65
|
-
if (error.kind === 'fallback') {
|
|
66
|
-
// Fallback to blue link with smart link formatting. Not part of reliability.
|
|
67
|
-
dispatch(cardAction(ACTION_ERROR_FALLBACK, {
|
|
68
|
-
url: url
|
|
69
|
-
}, response, error));
|
|
70
|
-
} else {
|
|
71
|
-
// Fallback to blue link with smart link formatting. Part of reliability.
|
|
72
|
-
dispatch(cardAction(ACTION_ERROR, {
|
|
73
|
-
url: url
|
|
74
|
-
}, undefined, error));
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}, [setMetadataStatus, hasData, status, dispatch, details]);
|
|
78
|
-
var handleResolvedLinkResponse = useCallback(function (resourceUrl, response) {
|
|
79
|
-
var isReloading = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
80
|
-
var isMetadataRequest = arguments.length > 3 ? arguments[3] : undefined;
|
|
81
|
-
var hostname = new URL(resourceUrl).hostname;
|
|
82
|
-
var nextStatus = response ? getStatus(response) : 'fatal';
|
|
83
|
-
|
|
84
|
-
// If we require authorization & do not have an authFlow available,
|
|
85
|
-
// throw an error and render as a normal blue link.
|
|
86
|
-
if ((nextStatus === 'unauthorized' || nextStatus === 'forbidden') && !hasAuthFlowSupported) {
|
|
87
|
-
handleResolvedLinkError(resourceUrl, new APIError('fallback', hostname, ERROR_MESSAGE_OAUTH), response, isMetadataRequest);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Handle any other errors
|
|
92
|
-
if (nextStatus === 'fatal') {
|
|
93
|
-
handleResolvedLinkError(resourceUrl, new APIError('fatal', hostname, ERROR_MESSAGE_FATAL), undefined, isMetadataRequest);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Handle errors of any other kind in the metadata request response
|
|
98
|
-
if (isMetadataRequest && nextStatus !== 'resolved') {
|
|
99
|
-
handleResolvedLinkError(resourceUrl, new APIError('error', hostname, ERROR_MESSAGE_METADATA), response, isMetadataRequest);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
//if a link resolves normally, metadata will also always be resolved
|
|
104
|
-
setMetadataStatus('resolved');
|
|
105
|
-
// Dispatch Analytics and resolved card action - including unauthorized states.
|
|
106
|
-
if (isReloading) {
|
|
107
|
-
dispatch(cardAction(ACTION_RELOADING, {
|
|
108
|
-
url: resourceUrl
|
|
109
|
-
}, response));
|
|
110
|
-
} else {
|
|
111
|
-
dispatch(cardAction(ACTION_RESOLVED, {
|
|
112
|
-
url: resourceUrl
|
|
113
|
-
}, response, undefined, undefined, isMetadataRequest));
|
|
114
|
-
}
|
|
115
|
-
}, [dispatch, handleResolvedLinkError, hasAuthFlowSupported, setMetadataStatus]);
|
|
116
31
|
var resolve = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
|
|
117
32
|
var resourceUrl,
|
|
118
33
|
isReloading,
|
|
@@ -125,26 +40,14 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
|
|
|
125
40
|
resourceUrl = _args.length > 0 && _args[0] !== undefined ? _args[0] : url;
|
|
126
41
|
isReloading = _args.length > 1 && _args[1] !== undefined ? _args[1] : false;
|
|
127
42
|
isMetadataRequest = _args.length > 2 && _args[2] !== undefined ? _args[2] : false;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
return _context.abrupt("return", connections.client.fetchData(resourceUrl, isReloading).then(function (response) {
|
|
133
|
-
return handleResolvedLinkResponse(resourceUrl, response, isReloading, isMetadataRequest);
|
|
134
|
-
}).catch(function (error) {
|
|
135
|
-
return handleResolvedLinkError(resourceUrl, error, undefined, isMetadataRequest);
|
|
136
|
-
}));
|
|
137
|
-
case 7:
|
|
138
|
-
addMetadataToExperience('smart-link-rendered', id, {
|
|
139
|
-
cached: true
|
|
140
|
-
});
|
|
141
|
-
case 8:
|
|
43
|
+
return _context.abrupt("return", resolveUrl(resourceUrl, isReloading, isMetadataRequest, id));
|
|
44
|
+
case 4:
|
|
142
45
|
case "end":
|
|
143
46
|
return _context.stop();
|
|
144
47
|
}
|
|
145
48
|
}
|
|
146
49
|
}, _callee);
|
|
147
|
-
})), [
|
|
50
|
+
})), [id, resolveUrl, url]);
|
|
148
51
|
var register = useCallback(function () {
|
|
149
52
|
if (!details) {
|
|
150
53
|
dispatch(cardAction(ACTION_RESOLVING, {
|
|
@@ -155,40 +58,15 @@ export var useSmartCardActions = function useSmartCardActions(id, url, analytics
|
|
|
155
58
|
return resolve();
|
|
156
59
|
}, [details, resolve, dispatch, url, setMetadataStatus]);
|
|
157
60
|
var reload = useCallback(function () {
|
|
158
|
-
var _details$data, _details$data$Type;
|
|
159
61
|
var definitionId = getDefinitionId(details);
|
|
160
|
-
|
|
161
|
-
// Start: Smart link Actions experiment
|
|
162
|
-
if (definitionId === 'jira-object-provider' && details !== null && details !== void 0 && (_details$data = details.data) !== null && _details$data !== void 0 && (_details$data$Type = _details$data['@type']) !== null && _details$data$Type !== void 0 && _details$data$Type.includes('atlassian:Task')) {
|
|
163
|
-
// EDM-5149: This is part of actionable element experiment where we
|
|
164
|
-
// reload jira issue link after embed view modal is closed.
|
|
165
|
-
// In our component, `reload` is only used in auth flow which
|
|
166
|
-
// jira link, being Atlassian product, would not fall into this category
|
|
167
|
-
// and would not be reloaded in normal smart link context.
|
|
168
|
-
// The code from resolve is duplicated here to avoid changing the response
|
|
169
|
-
// shape of resolve.
|
|
170
|
-
var previousJiraStatus = extractLozengeText(details);
|
|
171
|
-
connections.client.fetchData(url, true).then(function (response) {
|
|
172
|
-
handleResolvedLinkResponse(url, response, true, false);
|
|
173
|
-
var jiraStatus = extractLozengeText(response);
|
|
174
|
-
analytics.track.linkUpdated({
|
|
175
|
-
actionSubjectId: 'jiraIssueStatus',
|
|
176
|
-
previousJiraStatus: previousJiraStatus,
|
|
177
|
-
jiraStatus: jiraStatus
|
|
178
|
-
});
|
|
179
|
-
}).catch(function (error) {
|
|
180
|
-
return handleResolvedLinkError(url, error, undefined, false);
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
// End: Smart ink Actions experiment
|
|
184
|
-
else if (definitionId) {
|
|
62
|
+
if (definitionId) {
|
|
185
63
|
getByDefinitionId(definitionId, getState()).map(function (url) {
|
|
186
64
|
return resolve(url, true);
|
|
187
65
|
});
|
|
188
66
|
} else {
|
|
189
67
|
resolve(url, true);
|
|
190
68
|
}
|
|
191
|
-
}, [details,
|
|
69
|
+
}, [details, url, getState, resolve]);
|
|
192
70
|
var loadMetadata = useCallback(function () {
|
|
193
71
|
//metadataStatus will be undefined for SSR links only
|
|
194
72
|
if (metadataStatus === undefined) {
|