@atlaskit/smart-card 45.21.0 → 45.21.3
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 +36 -0
- package/dist/cjs/extractors/action/extract-invoke-view-action.js +2 -8
- package/dist/cjs/extractors/flexible/actions/index.js +2 -3
- package/dist/cjs/extractors/flexible/extract-state.js +3 -4
- package/dist/cjs/extractors/flexible/index.js +3 -4
- package/dist/cjs/state/hooks/use-destination-url/index.js +6 -11
- package/dist/cjs/state/hooks/use-smart-link-cross-product-url-wrapper/index.js +49 -10
- package/dist/cjs/state/hooks-external/useSmartLinkActions.js +5 -6
- package/dist/cjs/utils/analytics/analytics.js +1 -1
- package/dist/cjs/view/CardWithUrl/component.js +62 -111
- package/dist/cjs/view/FlexibleCard/index.js +2 -3
- package/dist/cjs/view/HoverCard/components/HoverCardContent.js +16 -23
- package/dist/cjs/view/LinkUrl/index.js +1 -1
- package/dist/es2019/extractors/action/extract-invoke-view-action.js +3 -7
- package/dist/es2019/extractors/flexible/actions/index.js +1 -3
- package/dist/es2019/extractors/flexible/extract-state.js +2 -4
- package/dist/es2019/extractors/flexible/index.js +2 -4
- package/dist/es2019/state/hooks/use-destination-url/index.js +4 -7
- package/dist/es2019/state/hooks/use-smart-link-cross-product-url-wrapper/index.js +47 -5
- package/dist/es2019/state/hooks-external/useSmartLinkActions.js +5 -7
- package/dist/es2019/utils/analytics/analytics.js +1 -1
- package/dist/es2019/view/CardWithUrl/component.js +64 -113
- package/dist/es2019/view/FlexibleCard/index.js +3 -4
- package/dist/es2019/view/HoverCard/components/HoverCardContent.js +16 -20
- package/dist/es2019/view/LinkUrl/index.js +1 -1
- package/dist/esm/extractors/action/extract-invoke-view-action.js +2 -8
- package/dist/esm/extractors/flexible/actions/index.js +2 -3
- package/dist/esm/extractors/flexible/extract-state.js +3 -4
- package/dist/esm/extractors/flexible/index.js +3 -4
- package/dist/esm/state/hooks/use-destination-url/index.js +4 -9
- package/dist/esm/state/hooks/use-smart-link-cross-product-url-wrapper/index.js +47 -9
- package/dist/esm/state/hooks-external/useSmartLinkActions.js +6 -7
- package/dist/esm/utils/analytics/analytics.js +1 -1
- package/dist/esm/view/CardWithUrl/component.js +63 -112
- package/dist/esm/view/FlexibleCard/index.js +3 -4
- package/dist/esm/view/HoverCard/components/HoverCardContent.js +17 -24
- package/dist/esm/view/LinkUrl/index.js +1 -1
- package/dist/types/state/hooks/use-destination-url/index.d.ts +18 -1
- package/dist/types/state/hooks/use-smart-link-cross-product-url-wrapper/index.d.ts +5 -2
- package/package.json +3 -5
- package/dist/cjs/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.js +0 -54
- package/dist/es2019/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.js +0 -47
- package/dist/esm/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.js +0 -47
- package/dist/types/state/hooks/use-smart-link-cross-product-url-wrapper/useSmartLinkCrossProductUrlWrapper.d.ts +0 -5
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { extractLink } from '@atlaskit/link-extractors/extract-link';
|
|
2
|
-
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
3
2
|
import { CardAction } from '../../constants';
|
|
4
3
|
import { getDefinitionId } from '../../state/getDefinitionId';
|
|
5
4
|
import { getExtensionKey } from '../../state/getExtensionKey';
|
|
@@ -26,12 +25,9 @@ export const extractInvokeViewAction = ({
|
|
|
26
25
|
if (url && (viewActionExists || force)) {
|
|
27
26
|
return {
|
|
28
27
|
actionFn: async () => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return openUrl(destinationUrl);
|
|
33
|
-
}
|
|
34
|
-
return openUrl(url);
|
|
28
|
+
var _transformUrl;
|
|
29
|
+
const destinationUrl = (_transformUrl = transformUrl === null || transformUrl === void 0 ? void 0 : transformUrl(url)) !== null && _transformUrl !== void 0 ? _transformUrl : url;
|
|
30
|
+
return openUrl(destinationUrl);
|
|
35
31
|
},
|
|
36
32
|
actionSubjectId: 'shortcutGoToLink',
|
|
37
33
|
actionType: 'ViewAction',
|
|
@@ -50,9 +50,7 @@ export const extractFlexibleCardActions = ({
|
|
|
50
50
|
isPreviewRestricted
|
|
51
51
|
} : undefined),
|
|
52
52
|
openPreviewPanel,
|
|
53
|
-
|
|
54
|
-
transformUrl
|
|
55
|
-
} : undefined)
|
|
53
|
+
transformUrl
|
|
56
54
|
}),
|
|
57
55
|
[ActionName.AutomationAction]: extractAutomationAction(response),
|
|
58
56
|
[InternalActionName.AISummaryAction]: extractAISummaryAction(response, url, actionOptions, aiSummaryConfig),
|
|
@@ -49,9 +49,7 @@ const extractAction = (response, id, actionOptions, appearance, origin, fireEven
|
|
|
49
49
|
isPreviewRestricted
|
|
50
50
|
} : undefined),
|
|
51
51
|
openPreviewPanel,
|
|
52
|
-
|
|
53
|
-
transformUrl
|
|
54
|
-
} : undefined)
|
|
52
|
+
transformUrl
|
|
55
53
|
})) === null || _extractInvokePreview === void 0 ? void 0 : _extractInvokePreview.invokeAction : undefined;
|
|
56
54
|
const details = {
|
|
57
55
|
id,
|
|
@@ -75,7 +73,7 @@ const extractState = (response, actionOptions, id, appearance, origin, fireEvent
|
|
|
75
73
|
if (!canShowAction(CardAction.ChangeStatusAction, actionOptions)) {
|
|
76
74
|
return lozenge;
|
|
77
75
|
}
|
|
78
|
-
const action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel,
|
|
76
|
+
const action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined);
|
|
79
77
|
return {
|
|
80
78
|
...lozenge,
|
|
81
79
|
action
|
|
@@ -89,9 +89,7 @@ const extractFlexibleUiContext = ({
|
|
|
89
89
|
isPreviewRestricted
|
|
90
90
|
} : undefined),
|
|
91
91
|
openPreviewPanel,
|
|
92
|
-
|
|
93
|
-
transformUrl
|
|
94
|
-
} : undefined)
|
|
92
|
+
transformUrl
|
|
95
93
|
}),
|
|
96
94
|
appliedToComponentsCount: extractAppliedToComponentsCount(data),
|
|
97
95
|
assignedToGroup: extractPersonAssignedToAsArray(data),
|
|
@@ -124,7 +122,7 @@ const extractFlexibleUiContext = ({
|
|
|
124
122
|
snippet: extractSmartLinkSummary(response) || undefined,
|
|
125
123
|
// Explicitly set here to remove an empty string
|
|
126
124
|
sourceBranch: extractSourceBranch(data),
|
|
127
|
-
state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel,
|
|
125
|
+
state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined),
|
|
128
126
|
subscriberCount: extractSubscriberCount(data),
|
|
129
127
|
subTasksProgress: extractSubTasksProgress(data),
|
|
130
128
|
storyPoints: extractStoryPoints(data),
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getClickUrl } from '../../getClickUrl';
|
|
1
|
+
import { getClickUrl } from '../../helpers';
|
|
3
2
|
import { useSmartCardState } from '../../store';
|
|
4
|
-
import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-product-url-wrapper
|
|
3
|
+
import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-product-url-wrapper';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Returns the resolved destination URL for a Smart Link, with cross-product analytics
|
|
8
|
-
* parameters appended when
|
|
7
|
+
* parameters appended when applicable.
|
|
9
8
|
*
|
|
10
9
|
* This is the same URL that SmartCard would navigate to when clicked. Use this as an `href`
|
|
11
10
|
* wherever you render a link to a Smart Link URL outside of the SmartCard component itself
|
|
@@ -13,7 +12,6 @@ import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-prod
|
|
|
13
12
|
*
|
|
14
13
|
* Falls back to the raw `url` when:
|
|
15
14
|
* - The link has not yet resolved
|
|
16
|
-
* - The feature gate is disabled
|
|
17
15
|
* - The link is not a first-party Atlassian link
|
|
18
16
|
*
|
|
19
17
|
* @example
|
|
@@ -21,7 +19,7 @@ import { useSmartLinkCrossProductUrlWrapper } from '../use-smart-link-cross-prod
|
|
|
21
19
|
*
|
|
22
20
|
* Use as <a href={href} target="_blank">Open link</a>
|
|
23
21
|
*/
|
|
24
|
-
const
|
|
22
|
+
const useDestinationUrl = url => {
|
|
25
23
|
const state = useSmartCardState(url);
|
|
26
24
|
const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
|
|
27
25
|
details: state.details
|
|
@@ -29,7 +27,6 @@ const useDestinationUrlImplementation = url => {
|
|
|
29
27
|
const resolvedUrl = getClickUrl(url, state.details);
|
|
30
28
|
return appendCrossProductAnalyticsParams(resolvedUrl);
|
|
31
29
|
};
|
|
32
|
-
export const useDestinationUrl = functionWithFG('platform_smartlink_xpc_url_wrapping', useDestinationUrlImplementation, url => url);
|
|
33
30
|
|
|
34
31
|
// Public API aliases preserved from an eliminated entry-point (volt-migrate-package).
|
|
35
32
|
export { useDestinationUrl as useSmartLinkDestinationUrl };
|
|
@@ -1,5 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { useCrossProductUrlWrapper } from '@atlaskit/analytics-cross-product/useCrossProductUrlWrapper';
|
|
3
|
+
import { useSmartLinkContext } from '@atlaskit/link-provider';
|
|
4
|
+
import { XPC_CONSTANTS } from './constants';
|
|
5
|
+
import { getIsFirstPartyLink } from './getIsFirstPartyLink';
|
|
6
|
+
export const useSmartLinkCrossProductUrlWrapper = ({
|
|
7
|
+
details
|
|
8
|
+
}) => {
|
|
9
|
+
var _effectiveProduct$toL;
|
|
10
|
+
const {
|
|
11
|
+
product,
|
|
12
|
+
bridgeProduct,
|
|
13
|
+
xpcProduct,
|
|
14
|
+
xpcSubProduct
|
|
15
|
+
} = useSmartLinkContext();
|
|
16
|
+
// xpcProduct takes precedence over product — it identifies the host product for XPC analytics
|
|
17
|
+
// without affecting link resolution (which uses the `product` prop separately).
|
|
18
|
+
const effectiveProduct = xpcProduct !== null && xpcProduct !== void 0 ? xpcProduct : product;
|
|
19
|
+
const effectiveBridge = bridgeProduct !== null && bridgeProduct !== void 0 ? bridgeProduct : XPC_CONSTANTS.SMART_LINKS_XPC_BRIDGE;
|
|
20
|
+
const effectiveProductForWrapper = (_effectiveProduct$toL = effectiveProduct === null || effectiveProduct === void 0 ? void 0 : effectiveProduct.toLowerCase()) !== null && _effectiveProduct$toL !== void 0 ? _effectiveProduct$toL : 'unknown';
|
|
21
|
+
const wrapUrl = useCrossProductUrlWrapper({
|
|
22
|
+
bridge: effectiveBridge,
|
|
23
|
+
product: effectiveProductForWrapper,
|
|
24
|
+
...(xpcSubProduct ? {
|
|
25
|
+
subProduct: xpcSubProduct
|
|
26
|
+
} : {})
|
|
27
|
+
});
|
|
28
|
+
return useCallback(url => {
|
|
29
|
+
if (typeof window === 'undefined' || !getIsFirstPartyLink(details) || !effectiveProduct) {
|
|
30
|
+
return url;
|
|
31
|
+
}
|
|
32
|
+
let parsedUrl;
|
|
33
|
+
try {
|
|
34
|
+
parsedUrl = new URL(url);
|
|
35
|
+
} catch {
|
|
36
|
+
return url;
|
|
37
|
+
}
|
|
38
|
+
if (parsedUrl.searchParams.has(XPC_CONSTANTS.QUERY_PARAM)) {
|
|
39
|
+
return url;
|
|
40
|
+
}
|
|
41
|
+
return wrapUrl(url);
|
|
42
|
+
},
|
|
43
|
+
// Keep bridge/subproduct in the dependency array so consumers that memoize this callback
|
|
44
|
+
// refresh when mini-modal context updates from smartLinks to rovo-chat.
|
|
45
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
46
|
+
[details, effectiveBridge, effectiveProduct, wrapUrl, xpcSubProduct]);
|
|
47
|
+
};
|
|
@@ -13,7 +13,7 @@ import { messages } from '../../messages';
|
|
|
13
13
|
import { toAction } from '../../utils/actions/to-action';
|
|
14
14
|
import useInvokeClientAction from '../hooks/use-invoke-client-action';
|
|
15
15
|
import useResolve from '../hooks/use-resolve';
|
|
16
|
-
import {
|
|
16
|
+
import { useSmartLinkCrossProductUrlWrapper } from '../hooks/use-smart-link-cross-product-url-wrapper';
|
|
17
17
|
import { useSmartCardState as useLinkState } from '../store';
|
|
18
18
|
export function useSmartLinkActions({
|
|
19
19
|
url,
|
|
@@ -37,7 +37,7 @@ export function useSmartLinkActions({
|
|
|
37
37
|
fireEvent
|
|
38
38
|
});
|
|
39
39
|
const resolve = useResolve();
|
|
40
|
-
const appendCrossProductAnalyticsParams =
|
|
40
|
+
const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
|
|
41
41
|
details: linkState.details
|
|
42
42
|
});
|
|
43
43
|
if (expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') && prefetch && !linkState.details) {
|
|
@@ -57,10 +57,10 @@ export function useSmartLinkActions({
|
|
|
57
57
|
if (downloadActionProps) {
|
|
58
58
|
actions.push(toAction(downloadActionProps, invokeClientAction, messages.download, 'download-content'));
|
|
59
59
|
}
|
|
60
|
-
const viewActionProps =
|
|
60
|
+
const viewActionProps = extractInvokeViewAction({
|
|
61
61
|
...invokeParam,
|
|
62
62
|
transformUrl: (destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl)
|
|
63
|
-
})
|
|
63
|
+
});
|
|
64
64
|
if (viewActionProps) {
|
|
65
65
|
actions.push(toAction(viewActionProps, invokeClientAction, messages.view, 'view-content'));
|
|
66
66
|
}
|
|
@@ -73,9 +73,7 @@ export function useSmartLinkActions({
|
|
|
73
73
|
isPreviewRestricted
|
|
74
74
|
} : undefined),
|
|
75
75
|
openPreviewPanel,
|
|
76
|
-
|
|
77
|
-
transformUrl: (destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl)
|
|
78
|
-
} : undefined)
|
|
76
|
+
transformUrl: (destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl)
|
|
79
77
|
});
|
|
80
78
|
if (previewActionProps) {
|
|
81
79
|
actions.push(toAction(previewActionProps.invokeAction, invokeClientAction, messages.preview_improved, 'preview-content'));
|
|
@@ -3,7 +3,7 @@ export const ANALYTICS_CHANNEL = 'media';
|
|
|
3
3
|
export const context = {
|
|
4
4
|
componentName: 'smart-cards',
|
|
5
5
|
packageName: "@atlaskit/smart-card" || '',
|
|
6
|
-
packageVersion: "45.
|
|
6
|
+
packageVersion: "45.21.2" || ''
|
|
7
7
|
};
|
|
8
8
|
export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
|
|
9
9
|
TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
|
|
@@ -16,7 +16,7 @@ import { getObjectName } from '../../state/getObjectName';
|
|
|
16
16
|
import { getResourceType } from '../../state/getResourceType';
|
|
17
17
|
import { getServices } from '../../state/getServices';
|
|
18
18
|
import { getThirdPartyARI } from '../../state/getThirdPartyARI';
|
|
19
|
-
import {
|
|
19
|
+
import { useSmartLinkCrossProductUrlWrapper } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
|
|
20
20
|
import { useSmartLink } from '../../state/hooks/useSmartLink';
|
|
21
21
|
import { isFinalState } from '../../state/isFinalState';
|
|
22
22
|
import { SmartLinkModalProvider } from '../../state/modal/SmartLinkModalProvider';
|
|
@@ -100,7 +100,7 @@ function Component({
|
|
|
100
100
|
const services = getServices(state.details);
|
|
101
101
|
const thirdPartyARI = getThirdPartyARI(state.details);
|
|
102
102
|
const firstPartyIdentifier = getFirstPartyIdentifier();
|
|
103
|
-
const appendCrossProductAnalyticsParams =
|
|
103
|
+
const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
|
|
104
104
|
details: state.details
|
|
105
105
|
});
|
|
106
106
|
const actionOptions = combineActionOptions({
|
|
@@ -137,127 +137,80 @@ function Component({
|
|
|
137
137
|
// please reach out to the 3P Workflows Team via Slack in #help-3p-connector-workflow
|
|
138
138
|
fire3PClickEvent === null || fire3PClickEvent === void 0 ? void 0 : fire3PClickEvent();
|
|
139
139
|
}
|
|
140
|
-
if (fg('platform_smartlink_xpc_url_wrapping')) {
|
|
141
|
-
// FIXME: InlineCard, BlockCard and EmbedCard call event.preventDefault() internally
|
|
142
|
-
// before the event bubbles up to this handler. This forces us to snapshot
|
|
143
|
-
// event.defaultPrevented before calling onClick to detect whether the consumer
|
|
144
|
-
// specifically prevented navigation. Ideally those components should not call
|
|
145
|
-
// preventDefault so this workaround can be removed.
|
|
146
|
-
const isEventDefaultPrevented = event.defaultPrevented;
|
|
147
|
-
const canOpenPreviewPanel = !isModifierKeyPressed && ari && name && openPreviewPanel && (isPreviewPanelAvailable === null || isPreviewPanelAvailable === void 0 ? void 0 : isPreviewPanelAvailable({
|
|
148
|
-
ari
|
|
149
|
-
})) && !disablePreviewPanel;
|
|
150
140
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
iconUrl: getObjectIconUrl(state.details),
|
|
161
|
-
panelData: {
|
|
162
|
-
embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
fireLinkClickedEvent(createAnalyticsEvent)(event, {
|
|
166
|
-
attributes: {
|
|
167
|
-
clickOutcome: 'previewPanel'
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
const destinationUrl = getDestinationUrl();
|
|
173
|
-
updateAnchorHref(event, destinationUrl);
|
|
141
|
+
// FIXME: InlineCard, BlockCard and EmbedCard call event.preventDefault() internally
|
|
142
|
+
// before the event bubbles up to this handler. This forces us to snapshot
|
|
143
|
+
// event.defaultPrevented before calling onClick to detect whether the consumer
|
|
144
|
+
// specifically prevented navigation. Ideally those components should not call
|
|
145
|
+
// preventDefault so this workaround can be removed.
|
|
146
|
+
const isEventDefaultPrevented = event.defaultPrevented;
|
|
147
|
+
const canOpenPreviewPanel = !isModifierKeyPressed && ari && name && openPreviewPanel && (isPreviewPanelAvailable === null || isPreviewPanelAvailable === void 0 ? void 0 : isPreviewPanelAvailable({
|
|
148
|
+
ari
|
|
149
|
+
})) && !disablePreviewPanel;
|
|
174
150
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
onClick === null || onClick === void 0 ? void 0 : onClick(event, {
|
|
151
|
+
// Preview panel takes priority over link navigation when available.
|
|
152
|
+
if (canOpenPreviewPanel) {
|
|
153
|
+
var _extractSmartLinkEmbe;
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
event.stopPropagation();
|
|
156
|
+
openPreviewPanel({
|
|
182
157
|
url,
|
|
183
|
-
|
|
158
|
+
ari,
|
|
159
|
+
name,
|
|
160
|
+
iconUrl: getObjectIconUrl(state.details),
|
|
161
|
+
panelData: {
|
|
162
|
+
embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe === void 0 ? void 0 : _extractSmartLinkEmbe.src : undefined
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
fireLinkClickedEvent(createAnalyticsEvent)(event, {
|
|
166
|
+
attributes: {
|
|
167
|
+
clickOutcome: 'previewPanel'
|
|
168
|
+
}
|
|
184
169
|
});
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const destinationUrl = getDestinationUrl();
|
|
173
|
+
updateAnchorHref(event, destinationUrl);
|
|
185
174
|
|
|
186
|
-
|
|
187
|
-
|
|
175
|
+
// For FlexibleCard, read target from the clicked anchor element (e.g. _blank for links
|
|
176
|
+
// rendered with explicit target). For classic cards, default to _self
|
|
177
|
+
const {
|
|
178
|
+
target: anchorTarget
|
|
179
|
+
} = getAnchorAttributesFromEvent(event);
|
|
180
|
+
const target = isSpecialEvent(event) ? '_blank' : isFlexibleUi ? anchorTarget : '_self';
|
|
181
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event, {
|
|
182
|
+
url,
|
|
183
|
+
destinationUrl
|
|
184
|
+
});
|
|
188
185
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// FlexibleCard's anchor is prevented from native navigation, so this handler always
|
|
192
|
-
// opens the link for FlexibleCard unless the consumer's onClick called preventDefault.
|
|
193
|
-
const shouldOpenLink = isFlexibleUi || !onClick;
|
|
194
|
-
const doOpenLink = shouldOpenLink && !consumerPreventedNavigation;
|
|
195
|
-
if (doOpenLink) {
|
|
196
|
-
event.preventDefault();
|
|
197
|
-
window.open(destinationUrl, target);
|
|
198
|
-
}
|
|
186
|
+
// Check if the event is prevented via onClick callback
|
|
187
|
+
const consumerPreventedNavigation = event.defaultPrevented && !isEventDefaultPrevented;
|
|
199
188
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (!isModifierKeyPressed && ari && name && openPreviewPanel && isPreviewPanelAvailable !== null && isPreviewPanelAvailable !== void 0 && isPreviewPanelAvailable({
|
|
211
|
-
ari
|
|
212
|
-
}) && !disablePreviewPanel) {
|
|
213
|
-
var _extractSmartLinkEmbe2;
|
|
214
|
-
event.preventDefault();
|
|
215
|
-
event.stopPropagation();
|
|
216
|
-
openPreviewPanel({
|
|
217
|
-
url,
|
|
218
|
-
ari,
|
|
219
|
-
name,
|
|
220
|
-
iconUrl: getObjectIconUrl(state.details),
|
|
221
|
-
panelData: {
|
|
222
|
-
embedUrl: expValEquals('platform_hover_card_preview_panel', 'cohort', 'test') ? (_extractSmartLinkEmbe2 = extractSmartLinkEmbed(state.details)) === null || _extractSmartLinkEmbe2 === void 0 ? void 0 : _extractSmartLinkEmbe2.src : undefined
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
fireLinkClickedEvent(createAnalyticsEvent)(event, {
|
|
226
|
-
attributes: {
|
|
227
|
-
clickOutcome: 'previewPanel'
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
return;
|
|
231
|
-
} else if (!onClick && !isFlexibleUi) {
|
|
232
|
-
const clickUrl = getClickUrl(url, state.details);
|
|
189
|
+
// Classic cards (InlineCard, BlockCard, EmbedCard) rely on their own anchor navigation
|
|
190
|
+
// when onClick is provided, so this handler should not open the link for them.
|
|
191
|
+
// FlexibleCard's anchor is prevented from native navigation, so this handler always
|
|
192
|
+
// opens the link for FlexibleCard unless the consumer's onClick called preventDefault.
|
|
193
|
+
const shouldOpenLink = isFlexibleUi || !onClick;
|
|
194
|
+
const doOpenLink = shouldOpenLink && !consumerPreventedNavigation;
|
|
195
|
+
if (doOpenLink) {
|
|
196
|
+
event.preventDefault();
|
|
197
|
+
window.open(destinationUrl, target);
|
|
198
|
+
}
|
|
233
199
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
window.open(clickUrl, target);
|
|
240
|
-
fireLinkClickedEvent(createAnalyticsEvent)(event, {
|
|
241
|
-
attributes: {
|
|
242
|
-
clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
} else {
|
|
246
|
-
if (onClick) {
|
|
247
|
-
onClick(event);
|
|
248
|
-
}
|
|
249
|
-
fireLinkClickedEvent(createAnalyticsEvent)(event);
|
|
200
|
+
// Only set clickOutcome when this handler actually opened the link.
|
|
201
|
+
// If a parent onClick handled navigation, fire a generic click event instead.
|
|
202
|
+
fireLinkClickedEvent(createAnalyticsEvent)(event, doOpenLink ? {
|
|
203
|
+
attributes: {
|
|
204
|
+
clickOutcome: target === '_blank' ? 'clickThroughNewTabOrWindow' : 'clickThrough'
|
|
250
205
|
}
|
|
251
|
-
}
|
|
206
|
+
} : undefined);
|
|
252
207
|
}, [fireEvent, id, isFlexibleUi, appearance, definitionId, getDestinationUrl, onClick, url, state.details, ari, name, fire3PClickEvent, shouldFire3PClickEvent, isPreviewPanelAvailable, openPreviewPanel, createAnalyticsEvent, disablePreviewPanel]);
|
|
253
208
|
|
|
254
209
|
// Middle-click handler to trigger fire3PClickEvent on middle-clicks.
|
|
255
210
|
// Scope is limited to 3P click analytics.
|
|
256
211
|
const handleFrameAuxClick = useCallback(event => {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
updateAnchorHref(event, destinationUrl);
|
|
260
|
-
}
|
|
212
|
+
const destinationUrl = getDestinationUrl();
|
|
213
|
+
updateAnchorHref(event, destinationUrl);
|
|
261
214
|
|
|
262
215
|
// isAuxClick filters Windows right-clicks (button === 2) that also fire onAuxClick.
|
|
263
216
|
if (isAuxClick(event) && shouldFire3PClickEvent) {
|
|
@@ -270,10 +223,8 @@ function Component({
|
|
|
270
223
|
// Right-click handler to trigger fire3PClickEvent on right-clicks.
|
|
271
224
|
// Scope is limited to 3P click analytics.
|
|
272
225
|
const handleFrameContextMenu = useCallback(event => {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
updateAnchorHref(event, destinationUrl);
|
|
276
|
-
}
|
|
226
|
+
const destinationUrl = getDestinationUrl();
|
|
227
|
+
updateAnchorHref(event, destinationUrl);
|
|
277
228
|
if (shouldFire3PClickEvent) {
|
|
278
229
|
fire3PClickEvent === null || fire3PClickEvent === void 0 ? void 0 : fire3PClickEvent({
|
|
279
230
|
isContextMenu: true
|
|
@@ -10,7 +10,7 @@ import { FlexibleCardContext } from '../../state/flexible-ui-context';
|
|
|
10
10
|
import { useAISummaryConfig } from '../../state/hooks/use-ai-summary-config';
|
|
11
11
|
import useResolve from '../../state/hooks/use-resolve';
|
|
12
12
|
import useRovoConfig from '../../state/hooks/use-rovo-config';
|
|
13
|
-
import {
|
|
13
|
+
import { useSmartLinkCrossProductUrlWrapper } from '../../state/hooks/use-smart-link-cross-product-url-wrapper';
|
|
14
14
|
import Container from './components/container';
|
|
15
15
|
import { getContextByStatus } from './getContextByStatus';
|
|
16
16
|
const PENDING_LINK_STATUSES = [SmartLinkStatus.Pending, SmartLinkStatus.Resolving];
|
|
@@ -61,11 +61,10 @@ const FlexibleCard = ({
|
|
|
61
61
|
details
|
|
62
62
|
} = cardState;
|
|
63
63
|
const status = cardType;
|
|
64
|
-
const appendCrossProductAnalyticsParams =
|
|
64
|
+
const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
|
|
65
65
|
details
|
|
66
66
|
});
|
|
67
|
-
const
|
|
68
|
-
const transformUrl = fg('platform_smartlink_xpc_url_wrapping') ? transformUrlCallback : undefined;
|
|
67
|
+
const transformUrl = useCallback((destinationUrl = url) => appendCrossProductAnalyticsParams(destinationUrl), [appendCrossProductAnalyticsParams, url]);
|
|
69
68
|
|
|
70
69
|
// if we have placeholder state it means we can internally use it
|
|
71
70
|
// as temporary resolved data until the actual data comes back as one of the final statuses
|
|
@@ -13,7 +13,7 @@ import { getDefinitionId } from '../../../state/getDefinitionId';
|
|
|
13
13
|
import { getExtensionKey } from '../../../state/getExtensionKey';
|
|
14
14
|
import { getServices } from '../../../state/getServices';
|
|
15
15
|
import useRovoConfig from '../../../state/hooks/use-rovo-config';
|
|
16
|
-
import {
|
|
16
|
+
import { useSmartLinkCrossProductUrlWrapper } from '../../../state/hooks/use-smart-link-cross-product-url-wrapper';
|
|
17
17
|
import { useSmartCardState } from '../../../state/store';
|
|
18
18
|
import { isSpecialEvent } from '../../../utils/is-special-event';
|
|
19
19
|
import { fireLinkClickedEvent } from '../../../utils/analytics/fireLinkClickedEvent';
|
|
@@ -90,7 +90,7 @@ const HoverCardContent = ({
|
|
|
90
90
|
} = useSmartLinkContext();
|
|
91
91
|
const isAISummaryEnabled = getIsAISummaryEnabled(isAdminHubAIEnabled, cardState.details);
|
|
92
92
|
const services = getServices(linkState.details);
|
|
93
|
-
const appendCrossProductAnalyticsParams =
|
|
93
|
+
const appendCrossProductAnalyticsParams = useSmartLinkCrossProductUrlWrapper({
|
|
94
94
|
details: linkState.details
|
|
95
95
|
});
|
|
96
96
|
const statusRef = useRef(linkStatus);
|
|
@@ -154,20 +154,18 @@ const HoverCardContent = ({
|
|
|
154
154
|
updateAnchorHref(event, destinationUrl);
|
|
155
155
|
}, [getDestinationUrl]);
|
|
156
156
|
const onClick = useCallback(event => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
window.open(destinationUrl, target);
|
|
170
|
-
}
|
|
157
|
+
// Prevent the anchor's native navigation so we can open the destination URL
|
|
158
|
+
// with cross-product analytics query parameters appended.
|
|
159
|
+
// The cross-product params are client-only and cannot be rendered
|
|
160
|
+
// server-side. Falls back to the original `url` prop if the event target is
|
|
161
|
+
// not an anchor element.
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
const {
|
|
164
|
+
target
|
|
165
|
+
} = getAnchorAttributesFromEvent(event);
|
|
166
|
+
const destinationUrl = getDestinationUrl();
|
|
167
|
+
updateAnchorHref(event, destinationUrl);
|
|
168
|
+
window.open(destinationUrl, target);
|
|
171
169
|
const isModifierKeyPressed = isSpecialEvent(event);
|
|
172
170
|
fireEvent('ui.smartLink.clicked.titleGoToLink', {
|
|
173
171
|
id,
|
|
@@ -195,10 +193,8 @@ const HoverCardContent = ({
|
|
|
195
193
|
appearance: CardDisplay.HoverCardPreview,
|
|
196
194
|
cardState: cardState,
|
|
197
195
|
onClick: onClick,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
onContextMenu
|
|
201
|
-
} : undefined),
|
|
196
|
+
onAuxClick,
|
|
197
|
+
onContextMenu,
|
|
202
198
|
onResolve: onResolve,
|
|
203
199
|
origin: 'smartLinkPreviewHoverCard',
|
|
204
200
|
renderers: renderers,
|
|
@@ -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: "45.
|
|
12
|
+
packageVersion: "45.21.2",
|
|
13
13
|
componentName: 'linkUrl'
|
|
14
14
|
};
|
|
15
15
|
const LinkUrl = ({
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
2
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
3
|
import { extractLink } from '@atlaskit/link-extractors/extract-link';
|
|
4
|
-
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
5
4
|
import { CardAction } from '../../constants';
|
|
6
5
|
import { getDefinitionId } from '../../state/getDefinitionId';
|
|
7
6
|
import { getExtensionKey } from '../../state/getExtensionKey';
|
|
@@ -30,19 +29,14 @@ export var extractInvokeViewAction = function extractInvokeViewAction(_ref, forc
|
|
|
30
29
|
return {
|
|
31
30
|
actionFn: function () {
|
|
32
31
|
var _actionFn = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
33
|
-
var _transformUrl
|
|
32
|
+
var _transformUrl;
|
|
33
|
+
var destinationUrl;
|
|
34
34
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
35
35
|
while (1) switch (_context.prev = _context.next) {
|
|
36
36
|
case 0:
|
|
37
|
-
if (!fg('platform_smartlink_xpc_url_wrapping')) {
|
|
38
|
-
_context.next = 1;
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
37
|
destinationUrl = (_transformUrl = transformUrl === null || transformUrl === void 0 ? void 0 : transformUrl(url)) !== null && _transformUrl !== void 0 ? _transformUrl : url;
|
|
42
38
|
return _context.abrupt("return", openUrl(destinationUrl));
|
|
43
39
|
case 1:
|
|
44
|
-
return _context.abrupt("return", openUrl(url));
|
|
45
|
-
case 2:
|
|
46
40
|
case "end":
|
|
47
41
|
return _context.stop();
|
|
48
42
|
}
|
|
@@ -47,10 +47,9 @@ export var extractFlexibleCardActions = function extractFlexibleCardActions(_ref
|
|
|
47
47
|
}, fg('preview_panel_unit_check') ? {
|
|
48
48
|
isPreviewRestricted: isPreviewRestricted
|
|
49
49
|
} : undefined), {}, {
|
|
50
|
-
openPreviewPanel: openPreviewPanel
|
|
51
|
-
}, fg('platform_smartlink_xpc_url_wrapping') ? {
|
|
50
|
+
openPreviewPanel: openPreviewPanel,
|
|
52
51
|
transformUrl: transformUrl
|
|
53
|
-
}
|
|
52
|
+
}))), ActionName.AutomationAction, extractAutomationAction(response)), InternalActionName.AISummaryAction, extractAISummaryAction(response, url, actionOptions, aiSummaryConfig)), ActionName.RovoChatAction, extractRovoChatAction({
|
|
54
53
|
actionOptions: actionOptions,
|
|
55
54
|
appearance: appearance,
|
|
56
55
|
id: id,
|
|
@@ -55,10 +55,9 @@ var extractAction = function extractAction(response, id, actionOptions, appearan
|
|
|
55
55
|
}, fg('preview_panel_unit_check') ? {
|
|
56
56
|
isPreviewRestricted: isPreviewRestricted
|
|
57
57
|
} : undefined), {}, {
|
|
58
|
-
openPreviewPanel: openPreviewPanel
|
|
59
|
-
}, fg('platform_smartlink_xpc_url_wrapping') ? {
|
|
58
|
+
openPreviewPanel: openPreviewPanel,
|
|
60
59
|
transformUrl: transformUrl
|
|
61
|
-
}
|
|
60
|
+
}))) === null || _extractInvokePreview === void 0 ? void 0 : _extractInvokePreview.invokeAction : undefined;
|
|
62
61
|
var details = {
|
|
63
62
|
id: id,
|
|
64
63
|
url: url,
|
|
@@ -81,7 +80,7 @@ var extractState = function extractState(response, actionOptions, id, appearance
|
|
|
81
80
|
if (!canShowAction(CardAction.ChangeStatusAction, actionOptions)) {
|
|
82
81
|
return lozenge;
|
|
83
82
|
}
|
|
84
|
-
var action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel,
|
|
83
|
+
var action = extractAction(response, id, actionOptions, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined);
|
|
85
84
|
return _objectSpread(_objectSpread({}, lozenge), {}, {
|
|
86
85
|
action: action
|
|
87
86
|
});
|
|
@@ -93,10 +93,9 @@ var extractFlexibleUiContext = function extractFlexibleUiContext() {
|
|
|
93
93
|
}, fg('preview_panel_unit_check') ? {
|
|
94
94
|
isPreviewRestricted: isPreviewRestricted
|
|
95
95
|
} : undefined), {}, {
|
|
96
|
-
openPreviewPanel: openPreviewPanel
|
|
97
|
-
}, fg('platform_smartlink_xpc_url_wrapping') ? {
|
|
96
|
+
openPreviewPanel: openPreviewPanel,
|
|
98
97
|
transformUrl: transformUrl
|
|
99
|
-
}
|
|
98
|
+
})),
|
|
100
99
|
appliedToComponentsCount: extractAppliedToComponentsCount(data),
|
|
101
100
|
assignedToGroup: extractPersonAssignedToAsArray(data),
|
|
102
101
|
attachmentCount: extractAttachmentCount(data),
|
|
@@ -128,7 +127,7 @@ var extractFlexibleUiContext = function extractFlexibleUiContext() {
|
|
|
128
127
|
snippet: extractSmartLinkSummary(response) || undefined,
|
|
129
128
|
// Explicitly set here to remove an empty string
|
|
130
129
|
sourceBranch: extractSourceBranch(data),
|
|
131
|
-
state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel,
|
|
130
|
+
state: extractState(response, actionOptions, id, appearance, origin, fireEvent, resolve, isPreviewPanelAvailable, openPreviewPanel, transformUrl, fg('preview_panel_unit_check') ? isPreviewRestricted : undefined),
|
|
132
131
|
subscriberCount: extractSubscriberCount(data),
|
|
133
132
|
subTasksProgress: extractSubTasksProgress(data),
|
|
134
133
|
storyPoints: extractStoryPoints(data),
|