@atlaskit/smart-card 44.5.0 → 44.5.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 +18 -0
- package/dist/cjs/extractors/flexible/actions/extract-rovo-chat-action.js +3 -4
- package/dist/cjs/state/hooks/use-current-site-cloud-id/index.js +71 -0
- package/dist/cjs/state/hooks/use-social-proof/index.js +60 -0
- package/dist/cjs/state/services/current-site-cloud-id/index.js +182 -0
- package/dist/cjs/state/services/personalization/index.js +267 -0
- package/dist/cjs/state/services/personalization/types.js +1 -0
- package/dist/cjs/utils/analytics/analytics.js +1 -1
- package/dist/cjs/view/LinkUrl/index.js +1 -1
- package/dist/es2019/extractors/flexible/actions/extract-rovo-chat-action.js +3 -4
- package/dist/es2019/state/hooks/use-current-site-cloud-id/index.js +28 -0
- package/dist/es2019/state/hooks/use-social-proof/index.js +45 -0
- package/dist/es2019/state/services/current-site-cloud-id/index.js +118 -0
- package/dist/es2019/state/services/personalization/index.js +164 -0
- package/dist/es2019/state/services/personalization/types.js +0 -0
- package/dist/es2019/utils/analytics/analytics.js +1 -1
- package/dist/es2019/view/LinkUrl/index.js +1 -1
- package/dist/esm/extractors/flexible/actions/extract-rovo-chat-action.js +3 -4
- package/dist/esm/state/hooks/use-current-site-cloud-id/index.js +35 -0
- package/dist/esm/state/hooks/use-social-proof/index.js +53 -0
- package/dist/esm/state/services/current-site-cloud-id/index.js +174 -0
- package/dist/esm/state/services/personalization/index.js +258 -0
- package/dist/esm/state/services/personalization/types.js +0 -0
- package/dist/esm/utils/analytics/analytics.js +1 -1
- package/dist/esm/view/LinkUrl/index.js +1 -1
- package/dist/types/common/ui/icons/blog-icon.d.ts +1 -1
- package/dist/types/common/ui/icons/live-document-icon.d.ts +1 -1
- package/dist/types/state/hooks/use-current-site-cloud-id/index.d.ts +6 -0
- package/dist/types/state/hooks/use-social-proof/index.d.ts +13 -0
- package/dist/types/state/services/current-site-cloud-id/index.d.ts +46 -0
- package/dist/types/state/services/personalization/index.d.ts +41 -0
- package/dist/types/state/services/personalization/types.d.ts +10 -0
- package/dist/types/view/FlexibleCard/assets/ai-chapter-icon.d.ts +3 -2
- package/dist/types/view/FlexibleCard/assets/ai-edit-icon.d.ts +3 -2
- package/dist/types/view/FlexibleCard/assets/ai-search-icon.d.ts +3 -2
- package/dist/types/view/FlexibleCard/assets/rovo-hex-logo.d.ts +4 -3
- package/dist/types-ts4.5/common/ui/icons/blog-icon.d.ts +1 -1
- package/dist/types-ts4.5/common/ui/icons/live-document-icon.d.ts +1 -1
- package/dist/types-ts4.5/state/hooks/use-current-site-cloud-id/index.d.ts +6 -0
- package/dist/types-ts4.5/state/hooks/use-social-proof/index.d.ts +13 -0
- package/dist/types-ts4.5/state/services/current-site-cloud-id/index.d.ts +46 -0
- package/dist/types-ts4.5/state/services/personalization/index.d.ts +41 -0
- package/dist/types-ts4.5/state/services/personalization/types.d.ts +10 -0
- package/dist/types-ts4.5/view/FlexibleCard/assets/ai-chapter-icon.d.ts +3 -2
- package/dist/types-ts4.5/view/FlexibleCard/assets/ai-edit-icon.d.ts +3 -2
- package/dist/types-ts4.5/view/FlexibleCard/assets/ai-search-icon.d.ts +3 -2
- package/dist/types-ts4.5/view/FlexibleCard/assets/rovo-hex-logo.d.ts +4 -3
- package/package.json +2 -2
- package/smart-card.docs.tsx +35 -15
|
@@ -6,7 +6,7 @@ import { getDefinitionId, getExtensionKey, getResourceType } from '../../../stat
|
|
|
6
6
|
import { canShowAction } from '../../../utils/actions/can-show-action';
|
|
7
7
|
import { getIsRovoChatEnabled } from '../../../utils/rovo';
|
|
8
8
|
import { CardAction } from '../../../view/Card/types';
|
|
9
|
-
// For rovogrowth-640 post auth inline experiment
|
|
9
|
+
// For rovogrowth-640 post auth inline experiment and block card experiment (NAVX-4814)
|
|
10
10
|
const ELIGIBLE_EXTENSION_KEYS = new Set(['slack-object-provider', 'google-object-provider', 'onedrive-object-provider', 'github-object-provider', 'ms-teams-object-provider', 'gitlab-object-provider', 'salesforce-object-provider']);
|
|
11
11
|
const extractRovoChatAction = ({
|
|
12
12
|
actionOptions,
|
|
@@ -16,7 +16,7 @@ const extractRovoChatAction = ({
|
|
|
16
16
|
response,
|
|
17
17
|
rovoConfig
|
|
18
18
|
}) => {
|
|
19
|
-
var
|
|
19
|
+
var _actionOptions$rovoCh;
|
|
20
20
|
if (!canShowAction(CardAction.RovoChatAction, actionOptions)) {
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
@@ -24,12 +24,11 @@ const extractRovoChatAction = ({
|
|
|
24
24
|
if (!isRovoChatEnabled) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const supportsRovoActions = response === null || response === void 0 ? void 0 : (_response$meta = response.meta) === null || _response$meta === void 0 ? void 0 : (_response$meta$suppor = _response$meta.supportedFeature) === null || _response$meta$suppor === void 0 ? void 0 : _response$meta$suppor.includes('RovoActions');
|
|
28
27
|
const extensionKey = getExtensionKey(response);
|
|
29
28
|
const isGoogleProvider = extensionKey === 'google-object-provider';
|
|
30
29
|
const is3PAuthRovoActionEnabled = isGoogleProvider && fg('platform_sl_3p_auth_rovo_action_kill_switch');
|
|
31
30
|
const is3PInlinePostAuthActionsEnabled = extensionKey !== undefined && ELIGIBLE_EXTENSION_KEYS.has(extensionKey) && fg('rovogrowth-640-inline-action-nudge-fg') && expValEqualsNoExposure('rovogrowth-640-inline-action-nudge-exp', 'isEnabled', true);
|
|
32
|
-
const is3PBlockPostAuthActionsEnabled =
|
|
31
|
+
const is3PBlockPostAuthActionsEnabled = extensionKey !== undefined && ELIGIBLE_EXTENSION_KEYS.has(extensionKey) && fg('platform_sl_3p_auth_rovo_block_card_kill_switch');
|
|
33
32
|
const isSupportedFeature = is3PInlinePostAuthActionsEnabled || is3PAuthRovoActionEnabled || is3PBlockPostAuthActionsEnabled;
|
|
34
33
|
const isOptIn = (actionOptions === null || actionOptions === void 0 ? void 0 : (_actionOptions$rovoCh = actionOptions.rovoChatAction) === null || _actionOptions$rovoCh === void 0 ? void 0 : _actionOptions$rovoCh.optIn) === true;
|
|
35
34
|
const url = extractSmartLinkUrl(response);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { getCurrentSiteCloudId } from '../../services/current-site-cloud-id';
|
|
3
|
+
export { CURRENT_SITE_CLOUD_ID_LOCAL_STORAGE_KEY, CURRENT_SITE_CLOUD_ID_STORAGE_ITEM_KEY, currentSiteCloudIdService, getCurrentSiteCloudId, getCachedCurrentSiteCloudIdAndRefresh } from '../../services/current-site-cloud-id';
|
|
4
|
+
const useCurrentSiteCloudId = () => {
|
|
5
|
+
const [cloudId, setCloudId] = useState(undefined);
|
|
6
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
let cancelled = false;
|
|
9
|
+
setIsLoading(true);
|
|
10
|
+
void getCurrentSiteCloudId().then(id => {
|
|
11
|
+
if (!cancelled) {
|
|
12
|
+
setCloudId(id);
|
|
13
|
+
}
|
|
14
|
+
}).finally(() => {
|
|
15
|
+
if (!cancelled) {
|
|
16
|
+
setIsLoading(false);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return () => {
|
|
20
|
+
cancelled = true;
|
|
21
|
+
};
|
|
22
|
+
}, []);
|
|
23
|
+
return {
|
|
24
|
+
cloudId,
|
|
25
|
+
isLoading
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export default useCurrentSiteCloudId;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { getProviderPctMap } from '../../services/personalization';
|
|
3
|
+
const NOT_ENABLED_RESULT = {
|
|
4
|
+
connectedPct: undefined,
|
|
5
|
+
isEnabled: false,
|
|
6
|
+
isLoading: false
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Fetches provider usage percentage from the TAP Delivery personalization service when the
|
|
11
|
+
* killswitch allows it. Callers decide separately (e.g. via Statsig experiment) whether to
|
|
12
|
+
* surface that data in the UI.
|
|
13
|
+
*/
|
|
14
|
+
const useSocialProof = (traitName, extensionKey, isKillswitchOn = false) => {
|
|
15
|
+
const isEnabled = isKillswitchOn;
|
|
16
|
+
const [providerPctMap, setProviderPctMap] = useState(undefined);
|
|
17
|
+
const [isPersonalizationLoading, setIsPersonalizationLoading] = useState(false);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!isEnabled) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
let cancelled = false;
|
|
23
|
+
setIsPersonalizationLoading(true);
|
|
24
|
+
getProviderPctMap(traitName).then(pctMap => {
|
|
25
|
+
if (!cancelled) {
|
|
26
|
+
setProviderPctMap(pctMap);
|
|
27
|
+
setIsPersonalizationLoading(false);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return () => {
|
|
31
|
+
cancelled = true;
|
|
32
|
+
};
|
|
33
|
+
}, [isEnabled, traitName]);
|
|
34
|
+
return useMemo(() => {
|
|
35
|
+
if (!isEnabled) {
|
|
36
|
+
return NOT_ENABLED_RESULT;
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
connectedPct: extensionKey && providerPctMap ? providerPctMap[extensionKey] : undefined,
|
|
40
|
+
isEnabled,
|
|
41
|
+
isLoading: isPersonalizationLoading
|
|
42
|
+
};
|
|
43
|
+
}, [extensionKey, isEnabled, isPersonalizationLoading, providerPctMap]);
|
|
44
|
+
};
|
|
45
|
+
export default useSocialProof;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import { StorageClient } from '@atlaskit/frontend-utilities/storage-client';
|
|
3
|
+
import { request } from '@atlaskit/linking-common';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Logical key shape matches smart-card storage conventions (see personalization-service). {@link StorageClient}
|
|
7
|
+
* stores rows as `<clientKey>_<itemKey>` with `clientKey === '@atlaskit/smart-card'` and
|
|
8
|
+
* `itemKey === 'site-cloud-id:v1'` (no further scope segments; unlike `pct-map:v1:`, this is a single fixed row).
|
|
9
|
+
*/
|
|
10
|
+
const SMART_CARD_STORAGE_SCOPE = '@atlaskit/smart-card';
|
|
11
|
+
export const CURRENT_SITE_CLOUD_ID_STORAGE_ITEM_KEY = 'site-cloud-id:v1';
|
|
12
|
+
const smartCardStorage = new StorageClient(SMART_CARD_STORAGE_SCOPE);
|
|
13
|
+
|
|
14
|
+
/** Keys written by this service in localStorage when using {@link smartCardStorage}. */
|
|
15
|
+
export const CURRENT_SITE_CLOUD_ID_LOCAL_STORAGE_KEY = `${SMART_CARD_STORAGE_SCOPE}_${CURRENT_SITE_CLOUD_ID_STORAGE_ITEM_KEY}`;
|
|
16
|
+
export class CurrentSiteCloudIdService {
|
|
17
|
+
constructor() {
|
|
18
|
+
/**
|
|
19
|
+
* Holds the shared tenant_info work: one in-flight fetch, then (on success) a settled promise for the session cloud
|
|
20
|
+
* id so later callers never trigger another `tenant_info` in the same page lifetime (until {@link clearCache}).
|
|
21
|
+
*/
|
|
22
|
+
_defineProperty(this, "tenantInfoInflightPromise", null);
|
|
23
|
+
}
|
|
24
|
+
readStoredCloudId() {
|
|
25
|
+
try {
|
|
26
|
+
const cloudId = smartCardStorage.getItem(CURRENT_SITE_CLOUD_ID_STORAGE_ITEM_KEY);
|
|
27
|
+
if (typeof cloudId !== 'string' || !cloudId || cloudId === 'undefined') {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
return cloudId;
|
|
31
|
+
} catch {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
writeStoredCloudId(cloudId) {
|
|
36
|
+
if (!cloudId) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
smartCardStorage.setItemWithExpiry(CURRENT_SITE_CLOUD_ID_STORAGE_ITEM_KEY, cloudId);
|
|
41
|
+
} catch {
|
|
42
|
+
// Quota, private-mode, SSR, etc. — same intent as personalization-service.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
ensureTenantInfoInflightStarted(baseUriWithNoTrailingSlash) {
|
|
46
|
+
if (this.tenantInfoInflightPromise !== null) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.tenantInfoInflightPromise = (async () => {
|
|
50
|
+
try {
|
|
51
|
+
const response = await request('get', baseUriWithNoTrailingSlash + '/_edge/tenant_info');
|
|
52
|
+
const cloudId = response === null || response === void 0 ? void 0 : response.cloudId;
|
|
53
|
+
if (cloudId) {
|
|
54
|
+
this.writeStoredCloudId(cloudId);
|
|
55
|
+
}
|
|
56
|
+
return cloudId ? cloudId : this.readStoredCloudId();
|
|
57
|
+
} catch {
|
|
58
|
+
this.tenantInfoInflightPromise = null;
|
|
59
|
+
return this.readStoredCloudId();
|
|
60
|
+
}
|
|
61
|
+
})();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Returns the currently cached cloud id synchronously and starts a background refresh.
|
|
66
|
+
* The refresh result is persisted for future calls but is not awaited by this call.
|
|
67
|
+
*/
|
|
68
|
+
getCachedCloudIdAndRefresh() {
|
|
69
|
+
this.ensureTenantInfoInflightStarted('');
|
|
70
|
+
return this.readStoredCloudId();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Writes tenant cloud id for tests or callers that intentionally warm storage before edge resolves. */
|
|
74
|
+
persistStoredCloudId(cloudId) {
|
|
75
|
+
this.writeStoredCloudId(cloudId);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* When local storage already has a tenant cloud id, it is returned immediately; a background tenant_info refresh
|
|
80
|
+
* is still kicked off unless one is already in flight.
|
|
81
|
+
*
|
|
82
|
+
* Without storage, this awaits the deduped in-flight tenant_info (first concurrent caller chooses the URL;
|
|
83
|
+
* all share one promise regardless of subsequent `baseUriWithNoTrailingSlash`).
|
|
84
|
+
*
|
|
85
|
+
* On network success with no cloud id, or on failure: falls back via {@link readStoredCloudId}.
|
|
86
|
+
*/
|
|
87
|
+
async get(baseUriWithNoTrailingSlash = '') {
|
|
88
|
+
const fromStorage = this.readStoredCloudId();
|
|
89
|
+
this.ensureTenantInfoInflightStarted(baseUriWithNoTrailingSlash);
|
|
90
|
+
if (fromStorage) {
|
|
91
|
+
return fromStorage;
|
|
92
|
+
}
|
|
93
|
+
return this.tenantInfoInflightPromise;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Clears the session pin so the next {@link get} may run `tenant_info` again (e.g. tests). */
|
|
97
|
+
clearCache() {
|
|
98
|
+
this.tenantInfoInflightPromise = null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export const currentSiteCloudIdService = new CurrentSiteCloudIdService();
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Resolves the current site cloud id through the module-level {@link currentSiteCloudIdService}.
|
|
105
|
+
* Returns a stored cloud id immediately when one exists; otherwise waits for the shared
|
|
106
|
+
* `tenant_info` request and persists the result for subsequent cached reads.
|
|
107
|
+
*/
|
|
108
|
+
export const getCurrentSiteCloudId = (baseUriWithNoTrailingSlash = '') => currentSiteCloudIdService.get(baseUriWithNoTrailingSlash);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Reads the current site cloud id from browser storage (the `site-cloud-id:v1` row) via the
|
|
112
|
+
* module-level {@link currentSiteCloudIdService} singleton, without awaiting network work.
|
|
113
|
+
* Calling this also starts the shared `tenant_info` refresh in the background when one is not
|
|
114
|
+
* already running, so a later call can observe a refreshed value when available.
|
|
115
|
+
*/
|
|
116
|
+
export function getCachedCurrentSiteCloudIdAndRefresh() {
|
|
117
|
+
return currentSiteCloudIdService.getCachedCloudIdAndRefresh();
|
|
118
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import { StorageClient } from '@atlaskit/frontend-utilities/storage-client';
|
|
3
|
+
import { getCurrentSiteCloudId, getCachedCurrentSiteCloudIdAndRefresh } from '../current-site-cloud-id';
|
|
4
|
+
const BASE_URL = '/gateway/api/tap-delivery/api/v3/personalization';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Logical key shape: `@atlaskit/smart-card:<feature>:<schema-version>:<scope>` (see smart-card
|
|
8
|
+
* storage conventions). {@link StorageClient} narrows the localStorage key to
|
|
9
|
+
* `<clientKey>_<itemKey>` with `clientKey === '@atlaskit/smart-card'` and
|
|
10
|
+
* `itemKey === 'pct-map:v1:<cloudId>:<traitName>'` (scope segments URI-encoded).
|
|
11
|
+
*/
|
|
12
|
+
export const PERSONALIZATION_STORAGE_SCOPE = '@atlaskit/smart-card';
|
|
13
|
+
export const PERSONALIZATION_STORAGE_ITEM_KEY_PREFIX = 'pct-map:v1:';
|
|
14
|
+
const smartCardStorage = new StorageClient(PERSONALIZATION_STORAGE_SCOPE);
|
|
15
|
+
|
|
16
|
+
/** Keys written by this service in localStorage when using {@link smartCardStorage}. */
|
|
17
|
+
const LOCAL_STORAGE_ROW_KEY_PREFIX = `${PERSONALIZATION_STORAGE_SCOPE}_${PERSONALIZATION_STORAGE_ITEM_KEY_PREFIX}`;
|
|
18
|
+
function pctMapStorageItemKey(cloudId, traitName) {
|
|
19
|
+
return `${PERSONALIZATION_STORAGE_ITEM_KEY_PREFIX}${encodeURIComponent(cloudId)}:${encodeURIComponent(traitName)}`;
|
|
20
|
+
}
|
|
21
|
+
async function fetchSiteTraits(cloudId) {
|
|
22
|
+
var _data$attributes;
|
|
23
|
+
const response = await fetch(`${BASE_URL}/site/${cloudId}`, {
|
|
24
|
+
method: 'GET',
|
|
25
|
+
credentials: 'include',
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/json'
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
const data = await response.json();
|
|
34
|
+
return (_data$attributes = data === null || data === void 0 ? void 0 : data.attributes) !== null && _data$attributes !== void 0 ? _data$attributes : [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Service for fetching site-level traits from the TAP Delivery personalization API.
|
|
39
|
+
*/
|
|
40
|
+
export class PersonalizationService {
|
|
41
|
+
constructor() {
|
|
42
|
+
_defineProperty(this, "cache", new Map());
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Returns the currently cached provider percentage map synchronously and starts a background refresh.
|
|
46
|
+
* The refresh result is persisted for future calls but is not awaited by this call.
|
|
47
|
+
*/
|
|
48
|
+
getCachedProviderPctMapAndRefresh(traitName) {
|
|
49
|
+
const cloudId = getCachedCurrentSiteCloudIdAndRefresh();
|
|
50
|
+
const fromStorage = cloudId && this.readStoredProviderPctMap(cloudId, traitName) || null;
|
|
51
|
+
void this.getProviderPctMap(traitName);
|
|
52
|
+
return fromStorage;
|
|
53
|
+
}
|
|
54
|
+
async getProviderPctMap(traitName) {
|
|
55
|
+
const cachedPromise = this.cache.get(traitName);
|
|
56
|
+
if (cachedPromise) {
|
|
57
|
+
return cachedPromise;
|
|
58
|
+
}
|
|
59
|
+
const promise = (async () => {
|
|
60
|
+
try {
|
|
61
|
+
const cloudId = await getCurrentSiteCloudId();
|
|
62
|
+
if (!cloudId) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const traits = await fetchSiteTraits(cloudId);
|
|
66
|
+
const trait = traits.find(t => t.name === traitName);
|
|
67
|
+
const mapped = this.parseTraitValue(trait === null || trait === void 0 ? void 0 : trait.value);
|
|
68
|
+
if (mapped !== undefined) {
|
|
69
|
+
this.writeStoredProviderPctMap(cloudId, traitName, mapped);
|
|
70
|
+
}
|
|
71
|
+
return mapped;
|
|
72
|
+
} catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
})();
|
|
76
|
+
this.cache.set(traitName, promise);
|
|
77
|
+
return promise;
|
|
78
|
+
}
|
|
79
|
+
readStoredProviderPctMap(cloudId, traitName) {
|
|
80
|
+
try {
|
|
81
|
+
const stored = smartCardStorage.getItem(pctMapStorageItemKey(cloudId, traitName));
|
|
82
|
+
if (stored === undefined || stored === null) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return this.normalizeProviderPctMap(stored);
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
writeStoredProviderPctMap(cloudId, traitName, map) {
|
|
91
|
+
try {
|
|
92
|
+
smartCardStorage.setItemWithExpiry(pctMapStorageItemKey(cloudId, traitName), map);
|
|
93
|
+
} catch {
|
|
94
|
+
// Quota, private-mode, etc.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
normalizeProviderPctMap(value) {
|
|
98
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const map = {};
|
|
102
|
+
const entries = Object.entries(value);
|
|
103
|
+
for (const [providerKey, percentageRaw] of entries) {
|
|
104
|
+
if (typeof percentageRaw !== 'number' || !Number.isFinite(percentageRaw)) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
map[providerKey] = percentageRaw;
|
|
108
|
+
}
|
|
109
|
+
return map;
|
|
110
|
+
}
|
|
111
|
+
parseTraitValue(raw) {
|
|
112
|
+
if (typeof raw !== 'string') {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const parsed = JSON.parse(raw);
|
|
117
|
+
const normalized = this.normalizeProviderPctMap(parsed);
|
|
118
|
+
return normalized === null ? undefined : normalized;
|
|
119
|
+
} catch {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
clearCache() {
|
|
124
|
+
this.cache.clear();
|
|
125
|
+
this.clearStoredProviderPctMaps();
|
|
126
|
+
}
|
|
127
|
+
clearStoredProviderPctMaps() {
|
|
128
|
+
if (typeof globalThis.localStorage === 'undefined' || globalThis.localStorage === null) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const keysToRemove = [];
|
|
132
|
+
for (let index = 0; index < globalThis.localStorage.length; index += 1) {
|
|
133
|
+
const key = globalThis.localStorage.key(index);
|
|
134
|
+
if (key !== null && key.startsWith(LOCAL_STORAGE_ROW_KEY_PREFIX)) {
|
|
135
|
+
keysToRemove.push(key);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const key of keysToRemove) {
|
|
139
|
+
try {
|
|
140
|
+
globalThis.localStorage.removeItem(key);
|
|
141
|
+
} catch {
|
|
142
|
+
/* ignore */
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export const personalizationService = new PersonalizationService();
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Resolves the provider percentage map for a TAP Delivery trait through the module-level
|
|
151
|
+
* {@link personalizationService}. Work is deduped per trait name for the page lifetime, and a
|
|
152
|
+
* successful response is persisted by cloud id and trait name for later cached reads.
|
|
153
|
+
*/
|
|
154
|
+
export const getProviderPctMap = traitName => personalizationService.getProviderPctMap(traitName);
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Reads the provider percentage map for a trait from browser storage via the module-level
|
|
158
|
+
* {@link personalizationService} singleton, without awaiting network work.
|
|
159
|
+
* Calling this also starts the trait-scoped shared refresh in the background, so a later call can
|
|
160
|
+
* use a refreshed value when it becomes available.
|
|
161
|
+
*/
|
|
162
|
+
export function getCachedProviderPctMapAndRefresh(traitName) {
|
|
163
|
+
return personalizationService.getCachedProviderPctMapAndRefresh(traitName);
|
|
164
|
+
}
|
|
File without changes
|
|
@@ -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.
|
|
5
|
+
packageVersion: "44.5.1" || ''
|
|
6
6
|
};
|
|
7
7
|
export let TrackQuickActionType = /*#__PURE__*/function (TrackQuickActionType) {
|
|
8
8
|
TrackQuickActionType["StatusUpdate"] = "StatusUpdate";
|
|
@@ -12,7 +12,7 @@ import LinkWarningModal from './LinkWarningModal';
|
|
|
12
12
|
import { useLinkWarningModal } from './LinkWarningModal/hooks/use-link-warning-modal';
|
|
13
13
|
const PACKAGE_DATA = {
|
|
14
14
|
packageName: "@atlaskit/smart-card",
|
|
15
|
-
packageVersion: "44.
|
|
15
|
+
packageVersion: "44.5.1",
|
|
16
16
|
componentName: 'linkUrl'
|
|
17
17
|
};
|
|
18
18
|
const Anchor = withLinkClickedEvent('a');
|
|
@@ -6,10 +6,10 @@ import { getDefinitionId, getExtensionKey, getResourceType } from '../../../stat
|
|
|
6
6
|
import { canShowAction } from '../../../utils/actions/can-show-action';
|
|
7
7
|
import { getIsRovoChatEnabled } from '../../../utils/rovo';
|
|
8
8
|
import { CardAction } from '../../../view/Card/types';
|
|
9
|
-
// For rovogrowth-640 post auth inline experiment
|
|
9
|
+
// For rovogrowth-640 post auth inline experiment and block card experiment (NAVX-4814)
|
|
10
10
|
var ELIGIBLE_EXTENSION_KEYS = new Set(['slack-object-provider', 'google-object-provider', 'onedrive-object-provider', 'github-object-provider', 'ms-teams-object-provider', 'gitlab-object-provider', 'salesforce-object-provider']);
|
|
11
11
|
var extractRovoChatAction = function extractRovoChatAction(_ref) {
|
|
12
|
-
var
|
|
12
|
+
var _actionOptions$rovoCh;
|
|
13
13
|
var actionOptions = _ref.actionOptions,
|
|
14
14
|
appearance = _ref.appearance,
|
|
15
15
|
id = _ref.id,
|
|
@@ -23,12 +23,11 @@ var extractRovoChatAction = function extractRovoChatAction(_ref) {
|
|
|
23
23
|
if (!isRovoChatEnabled) {
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
var supportsRovoActions = response === null || response === void 0 || (_response$meta = response.meta) === null || _response$meta === void 0 || (_response$meta = _response$meta.supportedFeature) === null || _response$meta === void 0 ? void 0 : _response$meta.includes('RovoActions');
|
|
27
26
|
var extensionKey = getExtensionKey(response);
|
|
28
27
|
var isGoogleProvider = extensionKey === 'google-object-provider';
|
|
29
28
|
var is3PAuthRovoActionEnabled = isGoogleProvider && fg('platform_sl_3p_auth_rovo_action_kill_switch');
|
|
30
29
|
var is3PInlinePostAuthActionsEnabled = extensionKey !== undefined && ELIGIBLE_EXTENSION_KEYS.has(extensionKey) && fg('rovogrowth-640-inline-action-nudge-fg') && expValEqualsNoExposure('rovogrowth-640-inline-action-nudge-exp', 'isEnabled', true);
|
|
31
|
-
var is3PBlockPostAuthActionsEnabled =
|
|
30
|
+
var is3PBlockPostAuthActionsEnabled = extensionKey !== undefined && ELIGIBLE_EXTENSION_KEYS.has(extensionKey) && fg('platform_sl_3p_auth_rovo_block_card_kill_switch');
|
|
32
31
|
var isSupportedFeature = is3PInlinePostAuthActionsEnabled || is3PAuthRovoActionEnabled || is3PBlockPostAuthActionsEnabled;
|
|
33
32
|
var isOptIn = (actionOptions === null || actionOptions === void 0 || (_actionOptions$rovoCh = actionOptions.rovoChatAction) === null || _actionOptions$rovoCh === void 0 ? void 0 : _actionOptions$rovoCh.optIn) === true;
|
|
34
33
|
var url = extractSmartLinkUrl(response);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { getCurrentSiteCloudId } from '../../services/current-site-cloud-id';
|
|
4
|
+
export { CURRENT_SITE_CLOUD_ID_LOCAL_STORAGE_KEY, CURRENT_SITE_CLOUD_ID_STORAGE_ITEM_KEY, currentSiteCloudIdService, getCurrentSiteCloudId, getCachedCurrentSiteCloudIdAndRefresh } from '../../services/current-site-cloud-id';
|
|
5
|
+
var useCurrentSiteCloudId = function useCurrentSiteCloudId() {
|
|
6
|
+
var _useState = useState(undefined),
|
|
7
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
8
|
+
cloudId = _useState2[0],
|
|
9
|
+
setCloudId = _useState2[1];
|
|
10
|
+
var _useState3 = useState(true),
|
|
11
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
12
|
+
isLoading = _useState4[0],
|
|
13
|
+
setIsLoading = _useState4[1];
|
|
14
|
+
useEffect(function () {
|
|
15
|
+
var cancelled = false;
|
|
16
|
+
setIsLoading(true);
|
|
17
|
+
void getCurrentSiteCloudId().then(function (id) {
|
|
18
|
+
if (!cancelled) {
|
|
19
|
+
setCloudId(id);
|
|
20
|
+
}
|
|
21
|
+
}).finally(function () {
|
|
22
|
+
if (!cancelled) {
|
|
23
|
+
setIsLoading(false);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return function () {
|
|
27
|
+
cancelled = true;
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
return {
|
|
31
|
+
cloudId: cloudId,
|
|
32
|
+
isLoading: isLoading
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export default useCurrentSiteCloudId;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { getProviderPctMap } from '../../services/personalization';
|
|
4
|
+
var NOT_ENABLED_RESULT = {
|
|
5
|
+
connectedPct: undefined,
|
|
6
|
+
isEnabled: false,
|
|
7
|
+
isLoading: false
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Fetches provider usage percentage from the TAP Delivery personalization service when the
|
|
12
|
+
* killswitch allows it. Callers decide separately (e.g. via Statsig experiment) whether to
|
|
13
|
+
* surface that data in the UI.
|
|
14
|
+
*/
|
|
15
|
+
var useSocialProof = function useSocialProof(traitName, extensionKey) {
|
|
16
|
+
var isKillswitchOn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
17
|
+
var isEnabled = isKillswitchOn;
|
|
18
|
+
var _useState = useState(undefined),
|
|
19
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
20
|
+
providerPctMap = _useState2[0],
|
|
21
|
+
setProviderPctMap = _useState2[1];
|
|
22
|
+
var _useState3 = useState(false),
|
|
23
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
24
|
+
isPersonalizationLoading = _useState4[0],
|
|
25
|
+
setIsPersonalizationLoading = _useState4[1];
|
|
26
|
+
useEffect(function () {
|
|
27
|
+
if (!isEnabled) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
var cancelled = false;
|
|
31
|
+
setIsPersonalizationLoading(true);
|
|
32
|
+
getProviderPctMap(traitName).then(function (pctMap) {
|
|
33
|
+
if (!cancelled) {
|
|
34
|
+
setProviderPctMap(pctMap);
|
|
35
|
+
setIsPersonalizationLoading(false);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return function () {
|
|
39
|
+
cancelled = true;
|
|
40
|
+
};
|
|
41
|
+
}, [isEnabled, traitName]);
|
|
42
|
+
return useMemo(function () {
|
|
43
|
+
if (!isEnabled) {
|
|
44
|
+
return NOT_ENABLED_RESULT;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
connectedPct: extensionKey && providerPctMap ? providerPctMap[extensionKey] : undefined,
|
|
48
|
+
isEnabled: isEnabled,
|
|
49
|
+
isLoading: isPersonalizationLoading
|
|
50
|
+
};
|
|
51
|
+
}, [extensionKey, isEnabled, isPersonalizationLoading, providerPctMap]);
|
|
52
|
+
};
|
|
53
|
+
export default useSocialProof;
|