@atlaskit/smart-card 44.24.2 → 44.25.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.
- package/CHANGELOG.md +13 -0
- package/dist/cjs/extractors/flexible/extract-state.js +4 -1
- package/dist/cjs/ssr.js +14 -3
- package/dist/cjs/state/actions/index.js +111 -23
- package/dist/cjs/state/hooks/use-resolve/index.js +7 -13
- package/dist/cjs/state/hooks/use-response/index.js +9 -3
- package/dist/cjs/state/hooks/usePrefetch.js +7 -6
- package/dist/cjs/state/hooks/useSmartLink.js +12 -3
- package/dist/cjs/state/hooks-external/useSmartLinkActions.js +3 -1
- package/dist/cjs/utils/analytics/analytics.js +1 -1
- package/dist/cjs/view/CardWithUrl/component-lazy/LazyIntersectionObserverCard.js +1 -1
- package/dist/cjs/view/CardWithUrl/component.js +25 -3
- package/dist/cjs/view/CardWithUrl/loader.js +7 -1
- package/dist/cjs/view/EmbedCard/useEmbedResolvePostMessageListener.js +4 -1
- package/dist/cjs/view/FlexibleCard/components/actions/action/server-action/index.js +5 -1
- package/dist/cjs/view/FlexibleCard/components/elements/common/base-lozenge-element/lozenge-action/index.js +5 -1
- package/dist/cjs/view/HoverCard/components/HoverCardComponent.js +2 -1
- package/dist/cjs/view/LinkUrl/index.js +1 -1
- package/dist/es2019/extractors/flexible/extract-state.js +4 -1
- package/dist/es2019/ssr.js +14 -3
- package/dist/es2019/state/actions/index.js +85 -12
- package/dist/es2019/state/hooks/use-resolve/index.js +11 -2
- package/dist/es2019/state/hooks/use-response/index.js +9 -5
- package/dist/es2019/state/hooks/usePrefetch.js +8 -7
- package/dist/es2019/state/hooks/useSmartLink.js +13 -3
- package/dist/es2019/state/hooks-external/useSmartLinkActions.js +3 -1
- package/dist/es2019/utils/analytics/analytics.js +1 -1
- package/dist/es2019/view/CardWithUrl/component-lazy/LazyIntersectionObserverCard.js +1 -1
- package/dist/es2019/view/CardWithUrl/component.js +28 -4
- package/dist/es2019/view/CardWithUrl/loader.js +7 -1
- package/dist/es2019/view/EmbedCard/useEmbedResolvePostMessageListener.js +4 -1
- package/dist/es2019/view/FlexibleCard/components/actions/action/server-action/index.js +5 -1
- package/dist/es2019/view/FlexibleCard/components/elements/common/base-lozenge-element/lozenge-action/index.js +5 -1
- package/dist/es2019/view/HoverCard/components/HoverCardComponent.js +2 -1
- package/dist/es2019/view/LinkUrl/index.js +1 -1
- package/dist/esm/extractors/flexible/extract-state.js +4 -1
- package/dist/esm/ssr.js +14 -3
- package/dist/esm/state/actions/index.js +111 -23
- package/dist/esm/state/hooks/use-resolve/index.js +7 -13
- package/dist/esm/state/hooks/use-response/index.js +9 -3
- package/dist/esm/state/hooks/usePrefetch.js +7 -6
- package/dist/esm/state/hooks/useSmartLink.js +13 -3
- package/dist/esm/state/hooks-external/useSmartLinkActions.js +3 -1
- package/dist/esm/utils/analytics/analytics.js +1 -1
- package/dist/esm/view/CardWithUrl/component-lazy/LazyIntersectionObserverCard.js +1 -1
- package/dist/esm/view/CardWithUrl/component.js +26 -4
- package/dist/esm/view/CardWithUrl/loader.js +7 -1
- package/dist/esm/view/EmbedCard/useEmbedResolvePostMessageListener.js +4 -1
- package/dist/esm/view/FlexibleCard/components/actions/action/server-action/index.js +5 -1
- package/dist/esm/view/FlexibleCard/components/elements/common/base-lozenge-element/lozenge-action/index.js +5 -1
- package/dist/esm/view/HoverCard/components/HoverCardComponent.js +2 -1
- package/dist/esm/view/LinkUrl/index.js +1 -1
- package/dist/types/state/actions/index.d.ts +3 -2
- package/dist/types/state/hooks/use-resolve/index.d.ts +9 -1
- package/dist/types/state/hooks/use-response/index.d.ts +2 -2
- package/dist/types/state/hooks/usePrefetch.d.ts +2 -1
- package/dist/types/state/hooks/useSmartLink.d.ts +14 -6
- package/dist/types-ts4.5/state/actions/index.d.ts +3 -2
- package/dist/types-ts4.5/state/hooks/use-resolve/index.d.ts +9 -1
- package/dist/types-ts4.5/state/hooks/use-response/index.d.ts +2 -2
- package/dist/types-ts4.5/state/hooks/usePrefetch.d.ts +2 -1
- package/dist/types-ts4.5/state/hooks/useSmartLink.d.ts +14 -6
- package/package.json +6 -3
package/dist/es2019/ssr.js
CHANGED
|
@@ -5,6 +5,7 @@ import uuid from 'uuid';
|
|
|
5
5
|
import { AnalyticsContext } from '@atlaskit/analytics-next';
|
|
6
6
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
7
|
import { context } from './utils/analytics/analytics';
|
|
8
|
+
import { isFlexibleUiCard } from './utils/flexible';
|
|
8
9
|
import CardErrorBoundary from './view/CardWithUrl/card-error-boundary';
|
|
9
10
|
import { CardWithUrl, CardWithUrlContent } from './view/CardWithUrl/component';
|
|
10
11
|
import { LoadingCardLink } from './view/CardWithUrl/component-lazy/LoadingCardLink';
|
|
@@ -17,9 +18,14 @@ const CardSSROld = props => {
|
|
|
17
18
|
var _props$id;
|
|
18
19
|
return (_props$id = props.id) !== null && _props$id !== void 0 ? _props$id : uuid();
|
|
19
20
|
});
|
|
21
|
+
// FlexibleCards always need full ORS data regardless of appearance prop,
|
|
22
|
+
// because they render custom blocks (TitleBlock etc.) requiring a complete response.
|
|
23
|
+
// Override appearance to 'block' for FlexibleCards when FG is enabled.
|
|
24
|
+
const effectiveAppearance = isFlexibleUiCard(props.children, props.ui) && fg('platform_smartlink_inline_resolve_optimization') ? 'block' : props.appearance;
|
|
20
25
|
const cardProps = {
|
|
21
26
|
...props,
|
|
22
|
-
id
|
|
27
|
+
id,
|
|
28
|
+
appearance: effectiveAppearance
|
|
23
29
|
};
|
|
24
30
|
const ErrorFallbackComponent = cardProps.fallbackComponent;
|
|
25
31
|
const errorBoundaryFallbackComponent = () => {
|
|
@@ -28,7 +34,7 @@ const CardSSROld = props => {
|
|
|
28
34
|
}
|
|
29
35
|
return /*#__PURE__*/React.createElement(LoadingCardLink, cardProps);
|
|
30
36
|
};
|
|
31
|
-
const Component =
|
|
37
|
+
const Component = effectiveAppearance === 'inline' ? 'span' : 'div';
|
|
32
38
|
return /*#__PURE__*/React.createElement(AnalyticsContext, {
|
|
33
39
|
data: context
|
|
34
40
|
}, /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
@@ -47,9 +53,14 @@ const CardSSRNew = props => {
|
|
|
47
53
|
var _props$id2;
|
|
48
54
|
return (_props$id2 = props.id) !== null && _props$id2 !== void 0 ? _props$id2 : uuid();
|
|
49
55
|
});
|
|
56
|
+
// FlexibleCards always need full ORS data regardless of appearance prop,
|
|
57
|
+
// because they render custom blocks (TitleBlock etc.) requiring a complete response.
|
|
58
|
+
// Override appearance to 'block' for FlexibleCards when FG is enabled.
|
|
59
|
+
const effectiveAppearance = isFlexibleUiCard(props.children, props.ui) && fg('platform_smartlink_inline_resolve_optimization') ? 'block' : props.appearance;
|
|
50
60
|
const propsWithId = {
|
|
51
61
|
...props,
|
|
52
|
-
id
|
|
62
|
+
id,
|
|
63
|
+
appearance: effectiveAppearance
|
|
53
64
|
};
|
|
54
65
|
return /*#__PURE__*/React.createElement(AnalyticsContext, {
|
|
55
66
|
data: context
|
|
@@ -101,8 +101,40 @@ export const useSmartCardActions = (id, url) => {
|
|
|
101
101
|
url
|
|
102
102
|
}, undefined, undefined, metadataStatus));
|
|
103
103
|
}, [dispatch, url]);
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
|
|
105
|
+
// Original resolve function — signature kept intact for maximum safety when FG is off.
|
|
106
|
+
const resolve = useCallback(async (resourceUrl = url, isReloading = false, isMetadataRequest = false) => resolveUrl({
|
|
107
|
+
url: resourceUrl,
|
|
108
|
+
isReloading,
|
|
109
|
+
isMetadataRequest,
|
|
110
|
+
id
|
|
111
|
+
}), [id, resolveUrl, url]);
|
|
112
|
+
|
|
113
|
+
// New resolve function accepting ResolveUrlParams (minus 'id' which is closed over).
|
|
114
|
+
// Used when FG is enabled to pass appearance to ORS.
|
|
115
|
+
const resolveNew = useCallback(async (params = {}) => {
|
|
116
|
+
const {
|
|
117
|
+
url: resourceUrl = url,
|
|
118
|
+
isReloading = false,
|
|
119
|
+
isMetadataRequest = false,
|
|
120
|
+
appearance
|
|
121
|
+
} = params;
|
|
122
|
+
return resolveUrl({
|
|
123
|
+
url: resourceUrl,
|
|
124
|
+
isReloading,
|
|
125
|
+
isMetadataRequest,
|
|
126
|
+
id,
|
|
127
|
+
appearance
|
|
128
|
+
});
|
|
129
|
+
}, [id, resolveUrl, url]);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Register a smart link for resolution.
|
|
133
|
+
* @param appearance - Card appearance hint for ORS to optimize response payload.
|
|
134
|
+
* When 'inline', ORS returns minimal data (title, status).
|
|
135
|
+
* When 'block' or 'embed', ORS returns full data including summary.
|
|
136
|
+
*/
|
|
137
|
+
const register = useCallback(appearance => {
|
|
106
138
|
const {
|
|
107
139
|
details
|
|
108
140
|
} = getSmartLinkState();
|
|
@@ -110,31 +142,72 @@ export const useSmartCardActions = (id, url) => {
|
|
|
110
142
|
dispatch(cardAction(ACTION_RESOLVING, {
|
|
111
143
|
url
|
|
112
144
|
}));
|
|
145
|
+
// Always set metadataStatus to 'pending' during registration to prevent
|
|
146
|
+
// loadMetadata from firing a duplicate concurrent fetch if a hover card
|
|
147
|
+
// mounts while registration is in-flight. This matches pre-PR behaviour.
|
|
113
148
|
setMetadataStatus('pending');
|
|
114
149
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
150
|
+
if (fg('platform_smartlink_inline_resolve_optimization')) {
|
|
151
|
+
return resolveNew({
|
|
152
|
+
url,
|
|
153
|
+
appearance
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return resolve(url);
|
|
157
|
+
}, [getSmartLinkState, resolve, resolveNew, dispatch, url, setMetadataStatus]);
|
|
158
|
+
const reload = useCallback(appearance => {
|
|
118
159
|
const {
|
|
119
160
|
details
|
|
120
161
|
} = getSmartLinkState();
|
|
121
162
|
const definitionId = getDefinitionId(details);
|
|
122
|
-
if (
|
|
123
|
-
|
|
163
|
+
if (fg('platform_smartlink_inline_resolve_optimization')) {
|
|
164
|
+
if (definitionId) {
|
|
165
|
+
getByDefinitionId(definitionId, getState()).map(reloadUrl => resolveNew({
|
|
166
|
+
url: reloadUrl,
|
|
167
|
+
isReloading: true,
|
|
168
|
+
appearance
|
|
169
|
+
}));
|
|
170
|
+
} else {
|
|
171
|
+
resolveNew({
|
|
172
|
+
url,
|
|
173
|
+
isReloading: true,
|
|
174
|
+
appearance
|
|
175
|
+
});
|
|
176
|
+
}
|
|
124
177
|
} else {
|
|
125
|
-
|
|
178
|
+
if (definitionId) {
|
|
179
|
+
getByDefinitionId(definitionId, getState()).map(reloadUrl => resolve(reloadUrl, true));
|
|
180
|
+
} else {
|
|
181
|
+
resolve(url, true);
|
|
182
|
+
}
|
|
126
183
|
}
|
|
127
|
-
}, [getSmartLinkState, url, getState, resolve]);
|
|
184
|
+
}, [getSmartLinkState, url, getState, resolve, resolveNew]);
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Load metadata for hover card preview.
|
|
188
|
+
* This always requests 'block' appearance to get full data including summary.
|
|
189
|
+
*
|
|
190
|
+
* Inline optimized and SSR-resolved links keep metadataStatus pending until hover
|
|
191
|
+
* requests the full block response.
|
|
192
|
+
*/
|
|
128
193
|
const loadMetadata = useCallback(() => {
|
|
129
194
|
const {
|
|
130
195
|
metadataStatus
|
|
131
196
|
} = getSmartLinkState();
|
|
132
|
-
|
|
133
|
-
if (
|
|
197
|
+
const needsBlockData = metadataStatus === undefined || metadataStatus === 'pending' && fg('platform_smartlink_inline_resolve_optimization');
|
|
198
|
+
if (needsBlockData) {
|
|
134
199
|
setMetadataStatus('pending');
|
|
200
|
+
if (fg('platform_smartlink_inline_resolve_optimization')) {
|
|
201
|
+
// Always request 'block' appearance for hover card metadata to get full data
|
|
202
|
+
return resolveNew({
|
|
203
|
+
url,
|
|
204
|
+
isMetadataRequest: true,
|
|
205
|
+
appearance: 'block'
|
|
206
|
+
});
|
|
207
|
+
}
|
|
135
208
|
return resolve(url, false, true);
|
|
136
209
|
}
|
|
137
|
-
}, [getSmartLinkState, resolve, setMetadataStatus, url]);
|
|
210
|
+
}, [getSmartLinkState, resolve, resolveNew, setMetadataStatus, url]);
|
|
138
211
|
const authorize = useCallback(appearance => {
|
|
139
212
|
const {
|
|
140
213
|
details,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { isEntityPresent } from '@atlaskit/link-extractors';
|
|
3
3
|
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
5
|
import { SmartLinkStatus } from '../../../constants';
|
|
5
6
|
import { addMetadataToExperience } from '../../analytics';
|
|
6
7
|
import useResponse from '../use-response';
|
|
@@ -20,7 +21,14 @@ const useResolve = () => {
|
|
|
20
21
|
handleResolvedLinkResponse,
|
|
21
22
|
handleResolvedLinkError
|
|
22
23
|
} = useResponse();
|
|
23
|
-
return useCallback(async
|
|
24
|
+
return useCallback(async params => {
|
|
25
|
+
const {
|
|
26
|
+
url,
|
|
27
|
+
isReloading = false,
|
|
28
|
+
isMetadataRequest = false,
|
|
29
|
+
id = '',
|
|
30
|
+
appearance
|
|
31
|
+
} = params;
|
|
24
32
|
const {
|
|
25
33
|
details
|
|
26
34
|
} = getState()[url] || {
|
|
@@ -29,7 +37,8 @@ const useResolve = () => {
|
|
|
29
37
|
};
|
|
30
38
|
const hasData = !!(details && details.data || isEntityPresent(details));
|
|
31
39
|
if (isReloading || !hasData || isMetadataRequest) {
|
|
32
|
-
|
|
40
|
+
const metadataStatus = appearance === 'inline' && !isMetadataRequest && fg('platform_smartlink_inline_resolve_optimization') ? 'pending' : undefined;
|
|
41
|
+
return connections.client.fetchData(url, isReloading, appearance).then(response => handleResolvedLinkResponse(url, response, isReloading, isMetadataRequest, metadataStatus)).catch(error => handleResolvedLinkError(url, error, undefined, isMetadataRequest));
|
|
33
42
|
} else {
|
|
34
43
|
addMetadataToExperience('smart-link-rendered', id, {
|
|
35
44
|
cached: true
|
|
@@ -2,6 +2,7 @@ import { useCallback, useMemo } from 'react';
|
|
|
2
2
|
import { unstable_batchedUpdates } from 'react-dom';
|
|
3
3
|
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
4
4
|
import { ACTION_ERROR, ACTION_ERROR_FALLBACK, ACTION_RELOADING, ACTION_RESOLVED, ACTION_UPDATE_METADATA_STATUS, APIError, cardAction, getStatus } from '@atlaskit/linking-common';
|
|
5
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
6
|
import { SmartLinkStatus } from '../../../constants';
|
|
6
7
|
import { getUnauthorizedJsonLd } from '../../../utils/jsonld';
|
|
7
8
|
import { ERROR_MESSAGE_FATAL, ERROR_MESSAGE_METADATA, ERROR_MESSAGE_OAUTH } from '../../actions/constants';
|
|
@@ -74,9 +75,9 @@ const useResponse = () => {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
}, [getState, setMetadataStatus, dispatch]);
|
|
77
|
-
const handleResolvedLinkSuccess = useCallback((resourceUrl, response, isReloading, isMetadataRequest) => {
|
|
78
|
-
//
|
|
79
|
-
setMetadataStatus(resourceUrl, 'resolved');
|
|
78
|
+
const handleResolvedLinkSuccess = useCallback((resourceUrl, response, isReloading, isMetadataRequest, metadataStatus = 'resolved') => {
|
|
79
|
+
// Some optimized resolves intentionally leave metadata pending so hover can fetch it.
|
|
80
|
+
setMetadataStatus(resourceUrl, fg('platform_smartlink_inline_resolve_optimization') ? metadataStatus : 'resolved');
|
|
80
81
|
// Dispatch Analytics and resolved card action - including unauthorized states.
|
|
81
82
|
if (isReloading) {
|
|
82
83
|
dispatch(cardAction(ACTION_RELOADING, {
|
|
@@ -88,7 +89,10 @@ const useResponse = () => {
|
|
|
88
89
|
}, response, undefined, undefined, isMetadataRequest));
|
|
89
90
|
}
|
|
90
91
|
}, [setMetadataStatus, dispatch]);
|
|
91
|
-
const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false, isMetadataRequest) => {
|
|
92
|
+
const handleResolvedLinkResponse = useCallback((resourceUrl, response, isReloading = false, isMetadataRequest, metadataStatus) => {
|
|
93
|
+
if (!resourceUrl) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
92
96
|
const hostname = new URL(resourceUrl).hostname;
|
|
93
97
|
const nextStatus = response ? getStatus(response) : 'fatal';
|
|
94
98
|
|
|
@@ -118,7 +122,7 @@ const useResponse = () => {
|
|
|
118
122
|
* https://react-redux.js.org/api/batch
|
|
119
123
|
*/
|
|
120
124
|
unstable_batchedUpdates(() => {
|
|
121
|
-
handleResolvedLinkSuccess(resourceUrl, response, isReloading, isMetadataRequest);
|
|
125
|
+
handleResolvedLinkSuccess(resourceUrl, response, isReloading, isMetadataRequest, metadataStatus);
|
|
122
126
|
});
|
|
123
127
|
}, [handleResolvedLinkError, handleResolvedLinkSuccess, hasAuthFlowSupported]);
|
|
124
128
|
return useMemo(() => ({
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
3
3
|
import { ACTION_UPDATE_METADATA_STATUS, cardAction } from '@atlaskit/linking-common';
|
|
4
|
-
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
|
+
export function usePrefetch(url, appearance) {
|
|
5
6
|
const {
|
|
6
7
|
store,
|
|
7
8
|
prefetchStore,
|
|
@@ -40,7 +41,7 @@ export function usePrefetch(url) {
|
|
|
40
41
|
// requests by domain (as usual) to ensure we minimize the amount of connections
|
|
41
42
|
// we create between browser -> ORS when making network requests.
|
|
42
43
|
try {
|
|
43
|
-
const response = await client.prefetchData(url);
|
|
44
|
+
const response = await client.prefetchData(url, appearance);
|
|
44
45
|
// Once the data comes back, we put the link in the `resolved` status. This ensures
|
|
45
46
|
// that when the link enters the viewport and is rendered, we immediately show it as
|
|
46
47
|
// a Smart Link, rather than rendering a loading spinner -> immediate Smart Link.
|
|
@@ -50,18 +51,18 @@ export function usePrefetch(url) {
|
|
|
50
51
|
url,
|
|
51
52
|
payload: response
|
|
52
53
|
});
|
|
53
|
-
// Put the metadata
|
|
54
|
-
//
|
|
54
|
+
// Put the metadata status: 'pending' for inline appearance when FG is on, so HoverCard
|
|
55
|
+
// can upgrade to full block data. Otherwise 'resolved' preserves existing behaviour.
|
|
55
56
|
dispatch(cardAction(ACTION_UPDATE_METADATA_STATUS, {
|
|
56
57
|
url
|
|
57
|
-
}, undefined, undefined, 'resolved'));
|
|
58
|
+
}, undefined, undefined, appearance === 'inline' && fg('platform_smartlink_inline_resolve_optimization') ? 'pending' : 'resolved'));
|
|
58
59
|
}
|
|
59
|
-
} catch
|
|
60
|
+
} catch {
|
|
60
61
|
// Do nothing, link will be retried under the hood with exponential backoff.
|
|
61
62
|
// If it does not succeed even after those retries, the normal resolve flow
|
|
62
63
|
// will start when the link is in view. Since we have not performed any store
|
|
63
64
|
// mutations yet, the link will behave like a 'brand new' link.
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
|
-
}, [store, prefetchStore, connections, url, getState, client, dispatch]);
|
|
67
|
+
}, [store, prefetchStore, connections, url, getState, client, dispatch, appearance]);
|
|
67
68
|
}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
import { useSmartCardActions as useSmartLinkActions } from '../actions';
|
|
4
5
|
import { useSmartLinkConfig } from '../config';
|
|
5
6
|
import { useSmartLinkRenderers } from '../renderers';
|
|
6
7
|
import { useSmartCardState as useSmartLinkState } from '../store';
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook for smart link state and actions.
|
|
11
|
+
* @param id - Unique identifier for the smart link
|
|
12
|
+
* @param url - The URL to resolve
|
|
13
|
+
* @param appearance - Card appearance hint for ORS to optimize response payload.
|
|
14
|
+
* When 'inline', ORS returns minimal data (title, status).
|
|
15
|
+
* When 'block' or 'embed', ORS returns full data including summary.
|
|
16
|
+
*/
|
|
17
|
+
export function useSmartLink(id, url, appearance) {
|
|
8
18
|
const state = useSmartLinkState(url);
|
|
9
19
|
const {
|
|
10
20
|
store,
|
|
@@ -17,9 +27,9 @@ export function useSmartLink(id, url) {
|
|
|
17
27
|
|
|
18
28
|
// NB: used to propagate errors from hooks to error boundaries.
|
|
19
29
|
const [error, setError] = useState(null);
|
|
20
|
-
// Register the current card.
|
|
30
|
+
// Register the current card with appearance hint for optimized ORS response.
|
|
21
31
|
const register = () => {
|
|
22
|
-
actions.register().catch(err => setError(err));
|
|
32
|
+
actions.register(fg('platform_smartlink_inline_resolve_optimization') ? appearance : undefined).catch(err => setError(err));
|
|
23
33
|
};
|
|
24
34
|
// AFP-2511 TODO: Fix automatic suppressions below
|
|
25
35
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -40,7 +40,9 @@ export function useSmartLinkActions({
|
|
|
40
40
|
details: linkState.details
|
|
41
41
|
});
|
|
42
42
|
if (expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') && prefetch && !linkState.details) {
|
|
43
|
-
resolve(
|
|
43
|
+
resolve({
|
|
44
|
+
url
|
|
45
|
+
});
|
|
44
46
|
}
|
|
45
47
|
if (linkState.details && !(actionOptions !== null && actionOptions !== void 0 && actionOptions.hide)) {
|
|
46
48
|
const actions = [];
|
|
@@ -2,7 +2,7 @@ export const ANALYTICS_CHANNEL = 'media';
|
|
|
2
2
|
export const context = {
|
|
3
3
|
componentName: 'smart-cards',
|
|
4
4
|
packageName: "@atlaskit/smart-card" || '',
|
|
5
|
-
packageVersion: "44.24.
|
|
5
|
+
packageVersion: "44.24.2" || ''
|
|
6
6
|
};
|
|
7
7
|
export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
|
|
8
8
|
TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
|
|
@@ -24,7 +24,7 @@ function LazyIntersectionObserverCardOld(props) {
|
|
|
24
24
|
url,
|
|
25
25
|
id
|
|
26
26
|
} = props;
|
|
27
|
-
const prefetch = usePrefetch(url);
|
|
27
|
+
const prefetch = usePrefetch(url, appearance);
|
|
28
28
|
const Component = appearance === 'inline' ? 'span' : 'div';
|
|
29
29
|
const ComponentObserver = Component;
|
|
30
30
|
const onIntersection = useCallback((entries, observer) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import { useAnalyticsEvents as useAnalyticsEventsNext } from '@atlaskit/analytics-next';
|
|
3
3
|
import { extractSmartLinkEmbed } from '@atlaskit/link-extractors';
|
|
4
4
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
@@ -66,6 +66,9 @@ function Component({
|
|
|
66
66
|
let isFlexibleUi = useMemo(() => isFlexibleUiCard(children, ui), [children, ui]);
|
|
67
67
|
|
|
68
68
|
// Get state, actions for this card.
|
|
69
|
+
// appearance is pre-resolved by the caller (loader.tsx for Card, ssr.tsx for CardSSR):
|
|
70
|
+
// FlexibleCards are always passed appearance='block' when FG is on, so component.tsx
|
|
71
|
+
// simply consumes whatever appearance it receives.
|
|
69
72
|
const {
|
|
70
73
|
state,
|
|
71
74
|
actions,
|
|
@@ -74,7 +77,7 @@ function Component({
|
|
|
74
77
|
error,
|
|
75
78
|
isPreviewPanelAvailable,
|
|
76
79
|
openPreviewPanel
|
|
77
|
-
} = useSmartLink(id, url);
|
|
80
|
+
} = useSmartLink(id, url, appearance);
|
|
78
81
|
const ari = getObjectAri(state.details);
|
|
79
82
|
const name = getObjectName(state.details);
|
|
80
83
|
const definitionId = getDefinitionId(state.details);
|
|
@@ -261,10 +264,31 @@ function Component({
|
|
|
261
264
|
});
|
|
262
265
|
}
|
|
263
266
|
}, [fire3PClickEvent, shouldFire3PClickEvent]);
|
|
267
|
+
const {
|
|
268
|
+
reload
|
|
269
|
+
} = actions;
|
|
264
270
|
const handleAuthorize = useCallback(() => actions.authorize(appearance), [actions, appearance]);
|
|
265
271
|
const handleRetry = useCallback(() => {
|
|
266
|
-
|
|
267
|
-
}, [
|
|
272
|
+
reload();
|
|
273
|
+
}, [reload]);
|
|
274
|
+
const hasMounted = useRef(false);
|
|
275
|
+
const prevAppearance = useRef(appearance);
|
|
276
|
+
|
|
277
|
+
// When appearance changes from inline to non-inline on a mounted card
|
|
278
|
+
// (e.g. direct consumer changes inline → block/embed), reload with the new appearance
|
|
279
|
+
// so ORS can return the appropriate full data. We intentionally do NOT reload on
|
|
280
|
+
// block → embed or embed → block transitions since both already have full ORS data.
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
if (!hasMounted.current) {
|
|
283
|
+
hasMounted.current = true;
|
|
284
|
+
prevAppearance.current = appearance;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (prevAppearance.current === 'inline' && appearance !== 'inline' && fg('platform_smartlink_inline_resolve_optimization')) {
|
|
288
|
+
reload(appearance);
|
|
289
|
+
}
|
|
290
|
+
prevAppearance.current = appearance;
|
|
291
|
+
}, [appearance, reload]);
|
|
268
292
|
const handleInvoke = useCallback(opts => actions.invoke(opts, appearance), [actions, appearance]);
|
|
269
293
|
const experimentMetaEventAttributes = useExperimentMetaEventAttributes({
|
|
270
294
|
appearance,
|
|
@@ -3,6 +3,7 @@ import { ErrorBoundary } from 'react-error-boundary';
|
|
|
3
3
|
import { di } from 'react-magnetic-di';
|
|
4
4
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
5
5
|
import uuid from 'uuid';
|
|
6
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
7
|
import { useAnalyticsEvents } from '../../common/analytics/generated/use-analytics-events';
|
|
7
8
|
import { failUfoExperience, startUfoExperience } from '../../state/analytics';
|
|
8
9
|
import { importWithRetry } from '../../utils';
|
|
@@ -103,10 +104,15 @@ export function CardWithURLRenderer(props) {
|
|
|
103
104
|
const defaultFallBackComponent = () => null;
|
|
104
105
|
const FallbackComponent = fallbackComponent !== null && fallbackComponent !== void 0 ? fallbackComponent : defaultFallBackComponent;
|
|
105
106
|
const ErrorFallback = () => /*#__PURE__*/React.createElement(FallbackComponent, null);
|
|
107
|
+
|
|
108
|
+
// FlexibleCards always need full ORS data regardless of appearance prop,
|
|
109
|
+
// because they render custom blocks (TitleBlock etc.) requiring complete response.
|
|
110
|
+
// Override appearance to 'block' for all FlexibleCards when FG is enabled.
|
|
111
|
+
const effectiveAppearance = isFlexibleUi && fg('platform_smartlink_inline_resolve_optimization') ? 'block' : appearance;
|
|
106
112
|
const cardWithUrlProps = {
|
|
107
113
|
id,
|
|
108
114
|
url,
|
|
109
|
-
appearance,
|
|
115
|
+
appearance: effectiveAppearance,
|
|
110
116
|
onClick,
|
|
111
117
|
isSelected,
|
|
112
118
|
isHovered,
|
|
@@ -13,7 +13,10 @@ export const useEmbedResolvePostMessageListener = ({
|
|
|
13
13
|
}
|
|
14
14
|
const isFromExpectedIframe = embedIframeRef && event.source === ((_embedIframeRef$curre = embedIframeRef.current) === null || _embedIframeRef$curre === void 0 ? void 0 : _embedIframeRef$curre.contentWindow);
|
|
15
15
|
if (event.data === 'force-resolve-smart-link' && isFromExpectedIframe) {
|
|
16
|
-
resolve(
|
|
16
|
+
resolve({
|
|
17
|
+
url,
|
|
18
|
+
isReloading: true
|
|
19
|
+
});
|
|
17
20
|
}
|
|
18
21
|
};
|
|
19
22
|
window.addEventListener('message', messageCallback);
|
|
@@ -38,7 +38,11 @@ const ServerAction = ({
|
|
|
38
38
|
smartLinkActionType
|
|
39
39
|
});
|
|
40
40
|
if (action.reload && action.reload.url) {
|
|
41
|
-
await reload(
|
|
41
|
+
await reload({
|
|
42
|
+
url: action.reload.url,
|
|
43
|
+
isReloading: true,
|
|
44
|
+
id: action.reload.id
|
|
45
|
+
});
|
|
42
46
|
}
|
|
43
47
|
setIsLoading(false);
|
|
44
48
|
if (onClick) {
|
|
@@ -116,7 +116,11 @@ const LozengeAction = ({
|
|
|
116
116
|
smartLinkActionType: TrackQuickActionType.StatusUpdate
|
|
117
117
|
});
|
|
118
118
|
if (url) {
|
|
119
|
-
await reload(
|
|
119
|
+
await reload({
|
|
120
|
+
url,
|
|
121
|
+
isReloading: true,
|
|
122
|
+
id: linkId
|
|
123
|
+
});
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
} catch (err) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
import Popup from '@atlaskit/popup';
|
|
4
5
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
5
6
|
import { ActionName, CardDisplay } from '../../../constants';
|
|
@@ -121,7 +122,7 @@ export const HoverCardComponent = ({
|
|
|
121
122
|
// to minimize the loading state
|
|
122
123
|
const initResolve = useCallback(() => {
|
|
123
124
|
// this check covers both non-SSR (status) & SSR case (metadataStatus)
|
|
124
|
-
const isLinkUnresolved = linkState.status === 'pending' || !linkState.metadataStatus;
|
|
125
|
+
const isLinkUnresolved = linkState.status === 'pending' || !linkState.metadataStatus || linkState.status === 'resolved' && linkState.metadataStatus === 'pending' && fg('platform_smartlink_inline_resolve_optimization');
|
|
125
126
|
if (!resolveTimeOutId.current && isLinkUnresolved) {
|
|
126
127
|
resolveTimeOutId.current = setTimeout(() => {
|
|
127
128
|
if (linkState.status === 'pending') {
|
|
@@ -9,7 +9,7 @@ import LinkWarningModal from './LinkWarningModal';
|
|
|
9
9
|
import { useLinkWarningModal } from './LinkWarningModal/hooks/use-link-warning-modal';
|
|
10
10
|
const PACKAGE_DATA = {
|
|
11
11
|
packageName: "@atlaskit/smart-card",
|
|
12
|
-
packageVersion: "44.24.
|
|
12
|
+
packageVersion: "44.24.2",
|
|
13
13
|
componentName: 'linkUrl'
|
|
14
14
|
};
|
|
15
15
|
const LinkUrl = ({
|
|
@@ -44,7 +44,10 @@ var extractAction = function extractAction(response, id, actionOptions, appearan
|
|
|
44
44
|
fireEvent: fireEvent,
|
|
45
45
|
id: id,
|
|
46
46
|
onClose: resolve ? function () {
|
|
47
|
-
return url && resolve(
|
|
47
|
+
return url && resolve({
|
|
48
|
+
url: url,
|
|
49
|
+
isReloading: true
|
|
50
|
+
});
|
|
48
51
|
} : undefined,
|
|
49
52
|
origin: origin,
|
|
50
53
|
response: response,
|
package/dist/esm/ssr.js
CHANGED
|
@@ -9,6 +9,7 @@ import uuid from 'uuid';
|
|
|
9
9
|
import { AnalyticsContext } from '@atlaskit/analytics-next';
|
|
10
10
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
11
11
|
import { context } from './utils/analytics/analytics';
|
|
12
|
+
import { isFlexibleUiCard } from './utils/flexible';
|
|
12
13
|
import CardErrorBoundary from './view/CardWithUrl/card-error-boundary';
|
|
13
14
|
import { CardWithUrl, CardWithUrlContent } from './view/CardWithUrl/component';
|
|
14
15
|
import { LoadingCardLink } from './view/CardWithUrl/component-lazy/LoadingCardLink';
|
|
@@ -23,8 +24,13 @@ var CardSSROld = function CardSSROld(props) {
|
|
|
23
24
|
}),
|
|
24
25
|
_useState2 = _slicedToArray(_useState, 1),
|
|
25
26
|
id = _useState2[0];
|
|
27
|
+
// FlexibleCards always need full ORS data regardless of appearance prop,
|
|
28
|
+
// because they render custom blocks (TitleBlock etc.) requiring a complete response.
|
|
29
|
+
// Override appearance to 'block' for FlexibleCards when FG is enabled.
|
|
30
|
+
var effectiveAppearance = isFlexibleUiCard(props.children, props.ui) && fg('platform_smartlink_inline_resolve_optimization') ? 'block' : props.appearance;
|
|
26
31
|
var cardProps = _objectSpread(_objectSpread({}, props), {}, {
|
|
27
|
-
id: id
|
|
32
|
+
id: id,
|
|
33
|
+
appearance: effectiveAppearance
|
|
28
34
|
});
|
|
29
35
|
var ErrorFallbackComponent = cardProps.fallbackComponent;
|
|
30
36
|
var errorBoundaryFallbackComponent = function errorBoundaryFallbackComponent() {
|
|
@@ -33,7 +39,7 @@ var CardSSROld = function CardSSROld(props) {
|
|
|
33
39
|
}
|
|
34
40
|
return /*#__PURE__*/React.createElement(LoadingCardLink, cardProps);
|
|
35
41
|
};
|
|
36
|
-
var Component =
|
|
42
|
+
var Component = effectiveAppearance === 'inline' ? 'span' : 'div';
|
|
37
43
|
return /*#__PURE__*/React.createElement(AnalyticsContext, {
|
|
38
44
|
data: context
|
|
39
45
|
}, /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
@@ -54,8 +60,13 @@ var CardSSRNew = function CardSSRNew(props) {
|
|
|
54
60
|
}),
|
|
55
61
|
_useState4 = _slicedToArray(_useState3, 1),
|
|
56
62
|
id = _useState4[0];
|
|
63
|
+
// FlexibleCards always need full ORS data regardless of appearance prop,
|
|
64
|
+
// because they render custom blocks (TitleBlock etc.) requiring a complete response.
|
|
65
|
+
// Override appearance to 'block' for FlexibleCards when FG is enabled.
|
|
66
|
+
var effectiveAppearance = isFlexibleUiCard(props.children, props.ui) && fg('platform_smartlink_inline_resolve_optimization') ? 'block' : props.appearance;
|
|
57
67
|
var propsWithId = _objectSpread(_objectSpread({}, props), {}, {
|
|
58
|
-
id: id
|
|
68
|
+
id: id,
|
|
69
|
+
appearance: effectiveAppearance
|
|
59
70
|
});
|
|
60
71
|
return /*#__PURE__*/React.createElement(AnalyticsContext, {
|
|
61
72
|
data: context
|