@atlaskit/smart-card 15.5.0 → 16.2.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 +78 -0
- package/dist/cjs/client/index.js +30 -30
- package/dist/cjs/client/utils/environments.js +1 -1
- package/dist/cjs/extractors/block/index.js +4 -4
- package/dist/cjs/extractors/common/actions/extractPreviewAction.js +4 -3
- package/dist/cjs/in-product.js +43 -0
- package/dist/cjs/index.js +66 -4
- package/dist/cjs/providers/editor/index.js +113 -78
- package/dist/cjs/providers/editor/transformer.js +1 -1
- package/dist/cjs/state/actions/constants.js +1 -5
- package/dist/cjs/state/actions/helpers.js +1 -3
- package/dist/cjs/state/actions/index.js +16 -13
- package/dist/cjs/state/analytics/index.js +32 -84
- package/dist/cjs/state/analytics/ufoExperiences.js +60 -0
- package/dist/cjs/state/analytics/useSmartLinkAnalytics.js +106 -0
- package/dist/cjs/state/context/provider.js +3 -16
- package/dist/cjs/state/helpers.js +1 -2
- package/dist/cjs/state/hooks/useSmartLink.js +6 -6
- package/dist/cjs/state/reducers/index.js +3 -8
- package/dist/cjs/utils/analytics/analytics.js +31 -1
- package/dist/cjs/version.json +1 -1
- package/dist/cjs/view/BlockCard/index.js +3 -2
- package/dist/cjs/view/CardWithUrl/component-lazy/LazyFallback.js +6 -2
- package/dist/cjs/view/CardWithUrl/component-lazy/index.js +1 -1
- package/dist/cjs/view/CardWithUrl/component.js +10 -4
- package/dist/cjs/view/CardWithUrl/loader.js +110 -133
- package/dist/cjs/view/EmbedCard/{IframelyResizeMessageListener.js → EmbedResizeMessageListener.js} +11 -19
- package/dist/cjs/view/SmartLinkEvents/useSmartLinkEvents.js +21 -0
- package/dist/es2019/client/index.js +47 -43
- package/dist/es2019/client/utils/environments.js +1 -1
- package/dist/es2019/extractors/block/index.js +4 -4
- package/dist/es2019/extractors/common/actions/extractPreviewAction.js +4 -4
- package/dist/es2019/in-product.js +1 -0
- package/dist/es2019/index.js +7 -2
- package/dist/es2019/providers/editor/index.js +18 -6
- package/dist/es2019/providers/editor/transformer.js +1 -1
- package/dist/es2019/state/actions/constants.js +0 -2
- package/dist/es2019/state/actions/helpers.js +1 -3
- package/dist/es2019/state/actions/index.js +12 -11
- package/dist/es2019/state/analytics/index.js +2 -40
- package/dist/es2019/state/analytics/ufoExperiences.js +40 -0
- package/dist/es2019/state/analytics/useSmartLinkAnalytics.js +62 -0
- package/dist/es2019/state/context/provider.js +2 -8
- package/dist/es2019/state/helpers.js +1 -2
- package/dist/es2019/state/hooks/useSmartLink.js +4 -5
- package/dist/es2019/state/reducers/index.js +3 -8
- package/dist/es2019/utils/analytics/analytics.js +16 -0
- package/dist/es2019/version.json +1 -1
- package/dist/es2019/view/BlockCard/index.js +3 -2
- package/dist/es2019/view/CardWithUrl/component-lazy/LazyFallback.js +3 -1
- package/dist/es2019/view/CardWithUrl/component-lazy/index.js +1 -1
- package/dist/es2019/view/CardWithUrl/component.js +10 -4
- package/dist/es2019/view/CardWithUrl/loader.js +87 -89
- package/dist/es2019/view/EmbedCard/{IframelyResizeMessageListener.js → EmbedResizeMessageListener.js} +3 -10
- package/dist/es2019/view/SmartLinkEvents/useSmartLinkEvents.js +10 -0
- package/dist/esm/client/index.js +30 -31
- package/dist/esm/client/utils/environments.js +1 -1
- package/dist/esm/extractors/block/index.js +4 -4
- package/dist/esm/extractors/common/actions/extractPreviewAction.js +4 -3
- package/dist/esm/in-product.js +1 -0
- package/dist/esm/index.js +7 -2
- package/dist/esm/providers/editor/index.js +110 -78
- package/dist/esm/providers/editor/transformer.js +1 -1
- package/dist/esm/state/actions/constants.js +0 -2
- package/dist/esm/state/actions/helpers.js +1 -3
- package/dist/esm/state/actions/index.js +15 -13
- package/dist/esm/state/analytics/index.js +2 -80
- package/dist/esm/state/analytics/ufoExperiences.js +40 -0
- package/dist/esm/state/analytics/useSmartLinkAnalytics.js +94 -0
- package/dist/esm/state/context/provider.js +3 -15
- package/dist/esm/state/helpers.js +1 -2
- package/dist/esm/state/hooks/useSmartLink.js +6 -6
- package/dist/esm/state/reducers/index.js +3 -8
- package/dist/esm/utils/analytics/analytics.js +26 -0
- package/dist/esm/version.json +1 -1
- package/dist/esm/view/BlockCard/index.js +3 -2
- package/dist/esm/view/CardWithUrl/component-lazy/LazyFallback.js +3 -1
- package/dist/esm/view/CardWithUrl/component-lazy/index.js +1 -1
- package/dist/esm/view/CardWithUrl/component.js +10 -4
- package/dist/esm/view/CardWithUrl/loader.js +103 -127
- package/dist/esm/view/EmbedCard/{IframelyResizeMessageListener.js → EmbedResizeMessageListener.js} +9 -16
- package/dist/esm/view/SmartLinkEvents/useSmartLinkEvents.js +12 -0
- package/dist/types/__tests_external__/index.d.ts +6 -0
- package/dist/types/__tests_external__/page-objects/BaseCard.d.ts +18 -0
- package/dist/types/__tests_external__/page-objects/BlockCard.d.ts +6 -0
- package/dist/types/__tests_external__/page-objects/EmbedCard.d.ts +6 -0
- package/dist/types/__tests_external__/page-objects/InlineCard.d.ts +6 -0
- package/dist/types/__tests_external__/test-cases/card.d.ts +3 -0
- package/dist/types/__tests_external__/test-cases/embed.d.ts +3 -0
- package/dist/types/__tests_external__/test-cases/inline.d.ts +3 -0
- package/dist/types/__tests_external__/test-cases/types.d.ts +5 -0
- package/dist/types/client/index.d.ts +1 -0
- package/dist/types/extractors/block/index.d.ts +2 -2
- package/dist/types/extractors/common/__mocks__/jsonld.d.ts +61 -0
- package/dist/types/extractors/common/actions/extractPreviewAction.d.ts +1 -1
- package/dist/types/in-product.d.ts +1 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/providers/editor/index.d.ts +3 -0
- package/dist/types/state/actions/constants.d.ts +0 -2
- package/dist/types/state/actions/types.d.ts +0 -2
- package/dist/types/state/analytics/index.d.ts +3 -32
- package/dist/types/state/analytics/ufoExperiences.d.ts +7 -0
- package/dist/types/state/analytics/useSmartLinkAnalytics.d.ts +30 -0
- package/dist/types/state/context/provider.d.ts +1 -1
- package/dist/types/state/context/types.d.ts +4 -2
- package/dist/types/state/hooks/useSmartLink.d.ts +4 -5
- package/dist/types/state/store/types.d.ts +2 -1
- package/dist/types/utils/analytics/analytics.d.ts +3 -0
- package/dist/types/utils/types.d.ts +1 -1
- package/dist/types/view/BlockCard/types.d.ts +2 -1
- package/dist/types/view/CardWithUrl/component-lazy/LazyFallback.d.ts +1 -0
- package/dist/types/view/CardWithUrl/component-lazy/index.d.ts +1 -1
- package/dist/types/view/CardWithUrl/loader.d.ts +1 -15
- package/dist/types/view/EmbedCard/{IframelyResizeMessageListener.d.ts → EmbedResizeMessageListener.d.ts} +1 -1
- package/dist/types/view/SmartLinkEvents/useSmartLinkEvents.d.ts +2 -0
- package/in-product/package.json +7 -0
- package/package.json +25 -20
|
@@ -7,6 +7,7 @@ import { useSmartLinkContext } from '../context';
|
|
|
7
7
|
import * as measure from '../../utils/performance';
|
|
8
8
|
import { APIError } from '../../client/errors';
|
|
9
9
|
import { getUnauthorizedJsonLd } from '../../utils/jsonld';
|
|
10
|
+
import { addMetadataToExperience } from '../analytics';
|
|
10
11
|
export const useSmartCardActions = (id, url, analytics) => {
|
|
11
12
|
const {
|
|
12
13
|
store,
|
|
@@ -19,16 +20,13 @@ export const useSmartCardActions = (id, url, analytics) => {
|
|
|
19
20
|
} = store;
|
|
20
21
|
const {
|
|
21
22
|
details,
|
|
22
|
-
lastUpdatedAt,
|
|
23
23
|
status
|
|
24
24
|
} = getState()[url] || {
|
|
25
25
|
status: 'pending',
|
|
26
|
-
lastUpdatedAt: Date.now(),
|
|
27
26
|
details: undefined
|
|
28
27
|
};
|
|
29
28
|
const hasAuthFlowSupported = config.authFlow !== 'disabled';
|
|
30
29
|
const hasData = !!(details && details.data);
|
|
31
|
-
const hasExpired = Date.now() - lastUpdatedAt >= config.maxAge;
|
|
32
30
|
const handleResolvedLinkError = useCallback((url, error) => {
|
|
33
31
|
if (error.kind === 'fatal') {
|
|
34
32
|
// If there's no previous data in the store for this URL, then bail
|
|
@@ -85,18 +83,21 @@ export const useSmartCardActions = (id, url, analytics) => {
|
|
|
85
83
|
|
|
86
84
|
|
|
87
85
|
dispatch(cardAction(ACTION_RESOLVED, {
|
|
88
|
-
url: resourceUrl
|
|
89
|
-
hasExpired: hasExpired && !hasData
|
|
86
|
+
url: resourceUrl
|
|
90
87
|
}, response));
|
|
91
|
-
}, [dispatch, handleResolvedLinkError,
|
|
88
|
+
}, [dispatch, handleResolvedLinkError, hasAuthFlowSupported]);
|
|
92
89
|
const resolve = useCallback(async (resourceUrl = url, isReloading = false) => {
|
|
93
90
|
// Request JSON-LD data for the card from ORS, iff it has extended
|
|
94
91
|
// its cache lifespan OR there is no data for it currently. Once the data
|
|
95
92
|
// has come back asynchronously, dispatch the resolved action for the card.
|
|
96
|
-
if (isReloading ||
|
|
93
|
+
if (isReloading || !hasData) {
|
|
97
94
|
return connections.client.fetchData(resourceUrl).then(response => handleResolvedLinkResponse(resourceUrl, response)).catch(error => handleResolvedLinkError(resourceUrl, error));
|
|
95
|
+
} else {
|
|
96
|
+
addMetadataToExperience('smart-link-rendered', id, {
|
|
97
|
+
cached: true
|
|
98
|
+
});
|
|
98
99
|
}
|
|
99
|
-
}, [url, hasData,
|
|
100
|
+
}, [url, hasData, connections.client, handleResolvedLinkResponse, handleResolvedLinkError, id]);
|
|
100
101
|
const register = useCallback(() => {
|
|
101
102
|
if (!details) {
|
|
102
103
|
dispatch(cardAction(ACTION_PENDING, {
|
|
@@ -132,10 +133,10 @@ export const useSmartCardActions = (id, url, analytics) => {
|
|
|
132
133
|
analytics.screen.authPopupEvent(definitionId, extensionKey);
|
|
133
134
|
auth(services[0].url).then(() => {
|
|
134
135
|
analytics.track.appAccountConnected(definitionId, extensionKey);
|
|
135
|
-
analytics.operational.connectSucceededEvent(definitionId, extensionKey);
|
|
136
|
+
analytics.operational.connectSucceededEvent(id, definitionId, extensionKey);
|
|
136
137
|
reload();
|
|
137
138
|
}, err => {
|
|
138
|
-
analytics.operational.connectFailedEvent(definitionId, extensionKey, err.type);
|
|
139
|
+
analytics.operational.connectFailedEvent(id, definitionId, extensionKey, err.type);
|
|
139
140
|
|
|
140
141
|
if (err.type === 'auth_window_closed') {
|
|
141
142
|
analytics.ui.closedAuthEvent(appearance, definitionId, extensionKey);
|
|
@@ -144,7 +145,7 @@ export const useSmartCardActions = (id, url, analytics) => {
|
|
|
144
145
|
reload();
|
|
145
146
|
});
|
|
146
147
|
}
|
|
147
|
-
}, [analytics.ui, analytics.screen, analytics.track, analytics.operational, reload, details, status]);
|
|
148
|
+
}, [analytics.ui, analytics.screen, analytics.track, analytics.operational, id, reload, details, status]);
|
|
148
149
|
const invoke = useCallback(async (opts, appearance) => {
|
|
149
150
|
const {
|
|
150
151
|
key,
|
|
@@ -1,40 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const useSmartLinkAnalytics = dispatchAnalytics => {
|
|
4
|
-
const ui = useMemo(() => ({
|
|
5
|
-
authEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthEvent(display, definitionId, extensionKey)),
|
|
6
|
-
authAlternateAccountEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthAlternateAccountEvent(display, definitionId, extensionKey)),
|
|
7
|
-
cardClickedEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiCardClickedEvent(display, definitionId, extensionKey)),
|
|
8
|
-
actionClickedEvent: (providerKey, actionType, display) => dispatchAnalytics(uiActionClickedEvent(providerKey, actionType, display)),
|
|
9
|
-
closedAuthEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiClosedAuthEvent(display, definitionId, extensionKey)),
|
|
10
|
-
renderSuccessEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiRenderSuccessEvent(display, definitionId, extensionKey)),
|
|
11
|
-
renderFailedEvent: (display, error, errorInfo) => dispatchAnalytics(uiRenderFailedEvent(display, error, errorInfo))
|
|
12
|
-
}), [dispatchAnalytics]);
|
|
13
|
-
const operational = useMemo(() => ({
|
|
14
|
-
resolvedEvent: (id, definitionId, extensionKey, resourceType) => dispatchAnalytics(resolvedEvent(id, definitionId, extensionKey, resourceType)),
|
|
15
|
-
unresolvedEvent: (id, status, definitionId, extensionKey, resourceType) => dispatchAnalytics(unresolvedEvent(id, status, definitionId, extensionKey, resourceType)),
|
|
16
|
-
invokeSucceededEvent: (id, providerKey, actionType, display) => dispatchAnalytics(invokeSucceededEvent(id, providerKey, actionType, display)),
|
|
17
|
-
invokeFailedEvent: (id, providerKey, actionType, display, reason) => dispatchAnalytics(invokeFailedEvent(id, providerKey, actionType, display, reason)),
|
|
18
|
-
connectSucceededEvent: (definitionId, extensionKey) => dispatchAnalytics(connectSucceededEvent(definitionId, extensionKey)),
|
|
19
|
-
connectFailedEvent: (definitionId, extensionKey, reason) => dispatchAnalytics(connectFailedEvent(definitionId, extensionKey, reason)),
|
|
20
|
-
instrument: (id, status, definitionId, extensionKey, resourceType, error) => {
|
|
21
|
-
const event = instrumentEvent(id, status, definitionId, extensionKey, resourceType, error);
|
|
22
|
-
|
|
23
|
-
if (event) {
|
|
24
|
-
dispatchAnalytics(event);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}), [dispatchAnalytics]);
|
|
28
|
-
const track = useMemo(() => ({
|
|
29
|
-
appAccountConnected: (definitionId, extensionKey) => dispatchAnalytics(trackAppAccountConnected(definitionId, extensionKey))
|
|
30
|
-
}), [dispatchAnalytics]);
|
|
31
|
-
const screen = useMemo(() => ({
|
|
32
|
-
authPopupEvent: (definitionId, extensionKey) => dispatchAnalytics(screenAuthPopupEvent(definitionId, extensionKey))
|
|
33
|
-
}), [dispatchAnalytics]);
|
|
34
|
-
return useMemo(() => ({
|
|
35
|
-
ui,
|
|
36
|
-
operational,
|
|
37
|
-
track,
|
|
38
|
-
screen
|
|
39
|
-
}), [ui, operational, track, screen]);
|
|
40
|
-
};
|
|
1
|
+
export { startUfoExperience, succeedUfoExperience, failUfoExperience, addMetadataToExperience } from './ufoExperiences';
|
|
2
|
+
export { useSmartLinkAnalytics } from './useSmartLinkAnalytics';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ConcurrentExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atlaskit/ufo';
|
|
2
|
+
const ufoExperiences = {
|
|
3
|
+
'smart-link-rendered': new ConcurrentExperience('smart-link-rendered', {
|
|
4
|
+
type: ExperienceTypes.Load,
|
|
5
|
+
performanceType: ExperiencePerformanceTypes.PageSegmentLoad,
|
|
6
|
+
platform: {
|
|
7
|
+
component: 'smart-links'
|
|
8
|
+
}
|
|
9
|
+
}),
|
|
10
|
+
'smart-link-authenticated': new ConcurrentExperience('smart-link-authenticated', {
|
|
11
|
+
type: ExperienceTypes.Load,
|
|
12
|
+
performanceType: ExperiencePerformanceTypes.PageSegmentLoad,
|
|
13
|
+
platform: {
|
|
14
|
+
component: 'smart-links'
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
};
|
|
18
|
+
export const startUfoExperience = (experienceName, id, properties) => {
|
|
19
|
+
const experience = ufoExperiences[experienceName].getInstance(id);
|
|
20
|
+
experience.start();
|
|
21
|
+
|
|
22
|
+
if (properties) {
|
|
23
|
+
experience.addMetadata(properties);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
export const succeedUfoExperience = (experienceName, id, properties) => {
|
|
27
|
+
const experience = ufoExperiences[experienceName].getInstance(id);
|
|
28
|
+
experience.success({
|
|
29
|
+
metadata: properties
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
export const failUfoExperience = (experienceName, id, properties) => {
|
|
33
|
+
const experience = ufoExperiences[experienceName].getInstance(id);
|
|
34
|
+
experience.failure({
|
|
35
|
+
metadata: properties
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
export const addMetadataToExperience = (experienceName, id, properties) => {
|
|
39
|
+
ufoExperiences[experienceName].getInstance(id).addMetadata(properties);
|
|
40
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { uiAuthEvent, uiAuthAlternateAccountEvent, uiCardClickedEvent, uiActionClickedEvent, uiClosedAuthEvent, uiRenderSuccessEvent, resolvedEvent, unresolvedEvent, invokeSucceededEvent, invokeFailedEvent, connectSucceededEvent, connectFailedEvent, trackAppAccountConnected, screenAuthPopupEvent, instrumentEvent } from '../../utils/analytics';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { startUfoExperience, succeedUfoExperience } from './ufoExperiences';
|
|
4
|
+
export const useSmartLinkAnalytics = dispatchAnalytics => {
|
|
5
|
+
const ui = useMemo(() => ({
|
|
6
|
+
authEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthEvent(display, definitionId, extensionKey)),
|
|
7
|
+
authAlternateAccountEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiAuthAlternateAccountEvent(display, definitionId, extensionKey)),
|
|
8
|
+
cardClickedEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiCardClickedEvent(display, definitionId, extensionKey)),
|
|
9
|
+
actionClickedEvent: (providerKey, actionType, display) => dispatchAnalytics(uiActionClickedEvent(providerKey, actionType, display)),
|
|
10
|
+
closedAuthEvent: (display, definitionId, extensionKey) => dispatchAnalytics(uiClosedAuthEvent(display, definitionId, extensionKey)),
|
|
11
|
+
renderSuccessEvent: (display, id, definitionId, extensionKey) => {
|
|
12
|
+
succeedUfoExperience('smart-link-rendered', id, {
|
|
13
|
+
extensionKey,
|
|
14
|
+
display
|
|
15
|
+
}); // UFO will disregard this if authentication experience has not yet been started
|
|
16
|
+
|
|
17
|
+
succeedUfoExperience('smart-link-authenticated', id, {
|
|
18
|
+
display
|
|
19
|
+
});
|
|
20
|
+
dispatchAnalytics(uiRenderSuccessEvent(display, definitionId, extensionKey));
|
|
21
|
+
}
|
|
22
|
+
}), [dispatchAnalytics]);
|
|
23
|
+
const operational = useMemo(() => ({
|
|
24
|
+
resolvedEvent: (id, definitionId, extensionKey, resourceType) => dispatchAnalytics(resolvedEvent(id, definitionId, extensionKey, resourceType)),
|
|
25
|
+
unresolvedEvent: (id, status, definitionId, extensionKey, resourceType) => dispatchAnalytics(unresolvedEvent(id, status, definitionId, extensionKey, resourceType)),
|
|
26
|
+
invokeSucceededEvent: (id, providerKey, actionType, display) => dispatchAnalytics(invokeSucceededEvent(id, providerKey, actionType, display)),
|
|
27
|
+
invokeFailedEvent: (id, providerKey, actionType, display, reason) => dispatchAnalytics(invokeFailedEvent(id, providerKey, actionType, display, reason)),
|
|
28
|
+
connectSucceededEvent: (id, definitionId, extensionKey) => {
|
|
29
|
+
startUfoExperience('smart-link-authenticated', id, {
|
|
30
|
+
extensionKey,
|
|
31
|
+
status: 'success'
|
|
32
|
+
});
|
|
33
|
+
dispatchAnalytics(connectSucceededEvent(definitionId, extensionKey));
|
|
34
|
+
},
|
|
35
|
+
connectFailedEvent: (id, definitionId, extensionKey, status) => {
|
|
36
|
+
startUfoExperience('smart-link-authenticated', id, {
|
|
37
|
+
extensionKey,
|
|
38
|
+
status
|
|
39
|
+
});
|
|
40
|
+
dispatchAnalytics(connectFailedEvent(definitionId, extensionKey, status));
|
|
41
|
+
},
|
|
42
|
+
instrument: (id, status, definitionId, extensionKey, resourceType, error) => {
|
|
43
|
+
const event = instrumentEvent(id, status, definitionId, extensionKey, resourceType, error);
|
|
44
|
+
|
|
45
|
+
if (event) {
|
|
46
|
+
dispatchAnalytics(event);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}), [dispatchAnalytics]);
|
|
50
|
+
const track = useMemo(() => ({
|
|
51
|
+
appAccountConnected: (definitionId, extensionKey) => dispatchAnalytics(trackAppAccountConnected(definitionId, extensionKey))
|
|
52
|
+
}), [dispatchAnalytics]);
|
|
53
|
+
const screen = useMemo(() => ({
|
|
54
|
+
authPopupEvent: (definitionId, extensionKey) => dispatchAnalytics(screenAuthPopupEvent(definitionId, extensionKey))
|
|
55
|
+
}), [dispatchAnalytics]);
|
|
56
|
+
return useMemo(() => ({
|
|
57
|
+
ui,
|
|
58
|
+
operational,
|
|
59
|
+
track,
|
|
60
|
+
screen
|
|
61
|
+
}), [ui, operational, track, screen]);
|
|
62
|
+
};
|
|
@@ -3,14 +3,12 @@ import { useContext, useMemo } from 'react';
|
|
|
3
3
|
import { createStore } from 'redux';
|
|
4
4
|
import { cardReducer } from '../reducers';
|
|
5
5
|
import { SmartCardContext } from '.';
|
|
6
|
-
import { MAX_RELOAD_DELAY, MAX_LOADING_DELAY } from '../actions/constants';
|
|
7
6
|
import CardClient from '../../client';
|
|
8
7
|
import { extractPreview } from '../../extractors/common/preview';
|
|
9
8
|
import { getUrl } from '../helpers';
|
|
10
9
|
export function SmartCardProvider({
|
|
11
10
|
storeOptions,
|
|
12
11
|
client: customClient,
|
|
13
|
-
cacheOptions: customCacheOptions,
|
|
14
12
|
authFlow: customAuthFlow,
|
|
15
13
|
children,
|
|
16
14
|
renderers
|
|
@@ -25,10 +23,6 @@ export function SmartCardProvider({
|
|
|
25
23
|
const client = customClient || new CardClient();
|
|
26
24
|
const store = createStore(cardReducer, initialState);
|
|
27
25
|
const authFlow = customAuthFlow || 'oauth2';
|
|
28
|
-
const cacheOptions = customCacheOptions || {
|
|
29
|
-
maxAge: MAX_RELOAD_DELAY,
|
|
30
|
-
maxLoadingDelay: MAX_LOADING_DELAY
|
|
31
|
-
};
|
|
32
26
|
|
|
33
27
|
const getPreview = (url, platform) => {
|
|
34
28
|
const cardState = getUrl(store, url);
|
|
@@ -42,14 +36,14 @@ export function SmartCardProvider({
|
|
|
42
36
|
connections: {
|
|
43
37
|
client
|
|
44
38
|
},
|
|
45
|
-
config: {
|
|
39
|
+
config: {
|
|
46
40
|
authFlow
|
|
47
41
|
},
|
|
48
42
|
extractors: {
|
|
49
43
|
getPreview
|
|
50
44
|
}
|
|
51
45
|
};
|
|
52
|
-
}, [customClient,
|
|
46
|
+
}, [customClient, customAuthFlow, storeOptions, renderers]);
|
|
53
47
|
return /*#__PURE__*/React.createElement(SmartCardContext.Provider, {
|
|
54
48
|
value: parentContext || providerValue
|
|
55
49
|
}, children);
|
|
@@ -10,8 +10,7 @@ export const getByDefinitionId = (definitionId, store) => {
|
|
|
10
10
|
};
|
|
11
11
|
export const getUrl = (store, url) => {
|
|
12
12
|
return store.getState()[url] || {
|
|
13
|
-
status: 'pending'
|
|
14
|
-
lastUpdatedAt: Date.now()
|
|
13
|
+
status: 'pending'
|
|
15
14
|
};
|
|
16
15
|
};
|
|
17
16
|
export const getClickUrl = (url, jsonLd) => {
|
|
@@ -11,12 +11,10 @@ export function useSmartLink(id, url, dispatchAnalytics) {
|
|
|
11
11
|
const config = useSmartLinkConfig();
|
|
12
12
|
const renderers = useSmartLinkRenderers(); // NB: used to propagate errors from hooks to error boundaries.
|
|
13
13
|
|
|
14
|
-
const [,
|
|
14
|
+
const [error, setError] = useState(null); // Register the current card.
|
|
15
15
|
|
|
16
16
|
const register = () => {
|
|
17
|
-
actions.register().catch(err =>
|
|
18
|
-
throw err;
|
|
19
|
-
}));
|
|
17
|
+
actions.register().catch(err => setError(err));
|
|
20
18
|
}; // AFP-2511 TODO: Fix automatic suppressions below
|
|
21
19
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
22
20
|
|
|
@@ -28,6 +26,7 @@ export function useSmartLink(id, url, dispatchAnalytics) {
|
|
|
28
26
|
actions,
|
|
29
27
|
config,
|
|
30
28
|
analytics,
|
|
31
|
-
renderers
|
|
29
|
+
renderers,
|
|
30
|
+
error
|
|
32
31
|
};
|
|
33
32
|
}
|
|
@@ -5,8 +5,7 @@ const cardReducerMap = {
|
|
|
5
5
|
type
|
|
6
6
|
}) => {
|
|
7
7
|
return {
|
|
8
|
-
status: type
|
|
9
|
-
lastUpdatedAt: Date.now()
|
|
8
|
+
status: type
|
|
10
9
|
};
|
|
11
10
|
},
|
|
12
11
|
[actions.ACTION_RESOLVING]: (state, {
|
|
@@ -33,7 +32,6 @@ const cardReducerMap = {
|
|
|
33
32
|
nextState.status = type;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
nextState.lastUpdatedAt = Date.now();
|
|
37
35
|
return nextState;
|
|
38
36
|
},
|
|
39
37
|
[actions.ACTION_ERROR]: (state, {
|
|
@@ -60,12 +58,9 @@ export const cardReducer = (state, action) => {
|
|
|
60
58
|
const cardState = state[action.url]; // Card may have reached the same state on account of multiple of the same
|
|
61
59
|
// URL being present in an editor session. E.g. page with N links to one resource.
|
|
62
60
|
|
|
63
|
-
const hasSameStatus = cardState && cardState.status === action.type;
|
|
64
|
-
// is described above - this forces a rerender for all links of the same status.
|
|
65
|
-
|
|
66
|
-
const hasExpired = action.hasExpired;
|
|
61
|
+
const hasSameStatus = cardState && cardState.status === action.type;
|
|
67
62
|
|
|
68
|
-
if (
|
|
63
|
+
if (hasSameStatus) {
|
|
69
64
|
return state;
|
|
70
65
|
} else {
|
|
71
66
|
const nextState = cardReducerMap[action.type](cardState, action);
|
|
@@ -6,6 +6,22 @@ export const context = {
|
|
|
6
6
|
packageName,
|
|
7
7
|
packageVersion
|
|
8
8
|
};
|
|
9
|
+
export class SmartLinkEvents {
|
|
10
|
+
insertSmartLink(url, type, createAnalyticsEvent) {
|
|
11
|
+
fireSmartLinkEvent({
|
|
12
|
+
action: 'inserted',
|
|
13
|
+
actionSubject: 'smartLink',
|
|
14
|
+
eventType: 'track',
|
|
15
|
+
attributes: {
|
|
16
|
+
type
|
|
17
|
+
},
|
|
18
|
+
nonPrivacySafeAttributes: {
|
|
19
|
+
domainName: url
|
|
20
|
+
}
|
|
21
|
+
}, createAnalyticsEvent);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
9
25
|
export const fireSmartLinkEvent = (payload, createAnalyticsEvent) => {
|
|
10
26
|
if (createAnalyticsEvent) {
|
|
11
27
|
createAnalyticsEvent(payload).fire(ANALYTICS_CHANNEL);
|
package/dist/es2019/version.json
CHANGED
|
@@ -21,7 +21,8 @@ export const BlockCard = ({
|
|
|
21
21
|
isSelected,
|
|
22
22
|
onResolve,
|
|
23
23
|
testId,
|
|
24
|
-
showActions
|
|
24
|
+
showActions,
|
|
25
|
+
platform
|
|
25
26
|
}) => {
|
|
26
27
|
var _details$meta, _forbiddenViewProps$c;
|
|
27
28
|
|
|
@@ -42,7 +43,7 @@ export const BlockCard = ({
|
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
case 'resolved':
|
|
45
|
-
const resolvedViewProps = extractBlockProps(data, meta, extractorOpts, renderers);
|
|
46
|
+
const resolvedViewProps = extractBlockProps(data, meta, extractorOpts, renderers, platform);
|
|
46
47
|
|
|
47
48
|
if (onResolve) {
|
|
48
49
|
onResolve({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { CardLinkView } from '@atlaskit/media-ui';
|
|
3
|
+
export const loadingPlaceholderClassName = 'smart-link-loading-placeholder';
|
|
3
4
|
export const LoadingCardLink = ({
|
|
4
5
|
isSelected,
|
|
5
6
|
url
|
|
@@ -8,5 +9,6 @@ export const LoadingCardLink = ({
|
|
|
8
9
|
testId: 'lazy-render-placeholder',
|
|
9
10
|
"data-trello-do-not-use-override": "lazy-render-placeholder-trello",
|
|
10
11
|
isSelected: isSelected,
|
|
11
|
-
link: url
|
|
12
|
+
link: url,
|
|
13
|
+
className: loadingPlaceholderClassName
|
|
12
14
|
});
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { isIntersectionObserverSupported } from '@atlaskit/media-ui';
|
|
3
3
|
import { LazyLazilyRenderCard } from './LazyLazilyRenderCard';
|
|
4
4
|
import { LazyIntersectionObserverCard } from './LazyIntersectionObserverCard';
|
|
5
|
-
export function LazyCardWithUrlContent(props) {
|
|
5
|
+
export default function LazyCardWithUrlContent(props) {
|
|
6
6
|
if (isIntersectionObserverSupported()) {
|
|
7
7
|
return /*#__PURE__*/React.createElement(LazyIntersectionObserverCard, props);
|
|
8
8
|
} else {
|
|
@@ -28,7 +28,8 @@ export function CardWithUrlContent({
|
|
|
28
28
|
actions,
|
|
29
29
|
config,
|
|
30
30
|
analytics,
|
|
31
|
-
renderers
|
|
31
|
+
renderers,
|
|
32
|
+
error
|
|
32
33
|
} = useSmartLink(id, url, dispatchAnalytics);
|
|
33
34
|
const definitionId = getDefinitionId(state.details);
|
|
34
35
|
const extensionKey = getExtensionKey(state.details);
|
|
@@ -67,9 +68,13 @@ export function CardWithUrlContent({
|
|
|
67
68
|
|
|
68
69
|
useEffect(() => {
|
|
69
70
|
if (isFinalState(state.status)) {
|
|
70
|
-
analytics.ui.renderSuccessEvent(appearance, definitionId, extensionKey);
|
|
71
|
+
analytics.ui.renderSuccessEvent(appearance, id, definitionId, extensionKey);
|
|
71
72
|
}
|
|
72
|
-
}, [appearance, state.details, state.status, url, definitionId, extensionKey, analytics.ui]);
|
|
73
|
+
}, [appearance, state.details, state.status, url, definitionId, extensionKey, analytics.ui, id]); // We have to keep this last to prevent hook order from being violated
|
|
74
|
+
|
|
75
|
+
if (error) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
73
78
|
|
|
74
79
|
switch (appearance) {
|
|
75
80
|
case 'inline':
|
|
@@ -99,7 +104,8 @@ export function CardWithUrlContent({
|
|
|
99
104
|
isSelected: isSelected,
|
|
100
105
|
onResolve: onResolve,
|
|
101
106
|
testId: testId,
|
|
102
|
-
showActions: showActions
|
|
107
|
+
showActions: showActions,
|
|
108
|
+
platform: platform
|
|
103
109
|
});
|
|
104
110
|
|
|
105
111
|
case 'embed':
|
|
@@ -1,60 +1,32 @@
|
|
|
1
|
-
import
|
|
2
|
-
import React from 'react';
|
|
1
|
+
import React, { lazy, useEffect, useState, Suspense } from 'react';
|
|
3
2
|
import uuid from 'uuid';
|
|
4
3
|
import { CardLinkView } from '@atlaskit/media-ui';
|
|
5
4
|
import { uiRenderFailedEvent, fireSmartLinkEvent } from '../../utils/analytics';
|
|
6
5
|
import { clearMarks, clearMeasures } from '../../utils/performance';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { ErrorBoundary } from 'react-error-boundary';
|
|
7
|
+
import { failUfoExperience, startUfoExperience } from '../../state/analytics/ufoExperiences';
|
|
8
|
+
const LazyCardWithUrlContent = /*#__PURE__*/lazy(() => import(
|
|
9
|
+
/* webpackChunkName: "@atlaskit-internal_smartcard-urlcardcontent" */
|
|
10
|
+
'./component-lazy/index'));
|
|
11
|
+
export function CardWithURLRenderer(props) {
|
|
12
|
+
const [id] = useState(() => uuid()); // Equivalent to ComponentWillMount
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (!analyticsPayload.attributes.display) {
|
|
21
|
-
analyticsPayload.attributes.display = appearance;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
fireSmartLinkEvent(analyticsPayload, createAnalyticsEvent);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
this.state = {
|
|
29
|
-
id: uuid()
|
|
14
|
+
useState(() => {
|
|
15
|
+
// We want to start timing of render event only once and right at the start
|
|
16
|
+
startUfoExperience('smart-link-rendered', id);
|
|
17
|
+
});
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
// ComponentWillUnmount
|
|
20
|
+
return () => {
|
|
21
|
+
clearMarks(id);
|
|
22
|
+
clearMeasures(id);
|
|
30
23
|
};
|
|
31
|
-
}
|
|
24
|
+
}, [id]);
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
import(
|
|
35
|
-
/* webpackChunkName: "@atlaskit-internal_smartcard-urlcardcontent" */
|
|
36
|
-
'./component-lazy/index').then(module => {
|
|
37
|
-
CardWithURLRenderer.CardContent = module.LazyCardWithUrlContent;
|
|
38
|
-
target.forceUpdate();
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
componentDidMount() {
|
|
43
|
-
if (CardWithURLRenderer.CardContent === null) {
|
|
44
|
-
(this.props.importer || CardWithURLRenderer.moduleImporter)(this);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
componentWillUnmount() {
|
|
49
|
-
const id = this.state.id;
|
|
50
|
-
clearMarks(id);
|
|
51
|
-
clearMeasures(id);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
componentDidCatch(error, errorInfo) {
|
|
26
|
+
const logError = (error, info) => {
|
|
55
27
|
const {
|
|
56
|
-
|
|
57
|
-
} =
|
|
28
|
+
componentStack
|
|
29
|
+
} = info; // NB: APIErrors are thrown in response to Object Resolver Service.
|
|
58
30
|
// In these cases, control is handed back to the Editor. We do not
|
|
59
31
|
// fire an event for these, as they do not cover failed UI render events.
|
|
60
32
|
|
|
@@ -64,54 +36,80 @@ export class CardWithURLRenderer extends React.PureComponent {
|
|
|
64
36
|
// to the reliability of the smart-card front-end components. We instrument
|
|
65
37
|
// these in order to measure our front-end reliability.
|
|
66
38
|
else {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
39
|
+
const errorInfo = {
|
|
40
|
+
componentStack
|
|
41
|
+
};
|
|
42
|
+
failUfoExperience('smart-link-rendered', id);
|
|
43
|
+
failUfoExperience('smart-link-authenticated', id);
|
|
44
|
+
dispatchAnalytics(uiRenderFailedEvent(appearance, error, errorInfo));
|
|
45
|
+
}
|
|
46
|
+
}; // Wrapper around analytics.
|
|
70
47
|
|
|
71
48
|
|
|
72
|
-
|
|
49
|
+
const dispatchAnalytics = analyticsPayload => {
|
|
73
50
|
const {
|
|
74
|
-
url,
|
|
75
51
|
appearance,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
onClick,
|
|
79
|
-
container,
|
|
80
|
-
onResolve,
|
|
81
|
-
testId,
|
|
82
|
-
showActions,
|
|
83
|
-
inheritDimensions,
|
|
84
|
-
platform,
|
|
85
|
-
embedIframeRef,
|
|
86
|
-
inlinePreloaderStyle
|
|
87
|
-
} = this.props;
|
|
52
|
+
createAnalyticsEvent
|
|
53
|
+
} = props;
|
|
88
54
|
|
|
89
|
-
if (
|
|
90
|
-
|
|
55
|
+
if (analyticsPayload && analyticsPayload.attributes) {
|
|
56
|
+
// Update if we haven't already set the display - possible
|
|
57
|
+
// in the case of `preview` which is rendered differently.
|
|
58
|
+
if (!analyticsPayload.attributes.display) {
|
|
59
|
+
analyticsPayload.attributes.display = appearance;
|
|
60
|
+
}
|
|
91
61
|
}
|
|
92
62
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
63
|
+
fireSmartLinkEvent(analyticsPayload, createAnalyticsEvent);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
url,
|
|
68
|
+
appearance,
|
|
69
|
+
isSelected,
|
|
70
|
+
isFrameVisible,
|
|
71
|
+
onClick,
|
|
72
|
+
container,
|
|
73
|
+
onResolve,
|
|
74
|
+
testId,
|
|
75
|
+
showActions,
|
|
76
|
+
inheritDimensions,
|
|
77
|
+
platform,
|
|
78
|
+
embedIframeRef,
|
|
79
|
+
inlinePreloaderStyle
|
|
80
|
+
} = props;
|
|
81
|
+
|
|
82
|
+
if (!url) {
|
|
83
|
+
throw new Error('@atlaskit/smart-card: url property is missing.');
|
|
113
84
|
}
|
|
114
85
|
|
|
86
|
+
return /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
87
|
+
FallbackComponent: ErrorFallback,
|
|
88
|
+
onError: logError
|
|
89
|
+
}, /*#__PURE__*/React.createElement(Suspense, {
|
|
90
|
+
fallback: /*#__PURE__*/React.createElement(CardLinkView, {
|
|
91
|
+
key: 'chunk-placeholder',
|
|
92
|
+
link: url
|
|
93
|
+
})
|
|
94
|
+
}, /*#__PURE__*/React.createElement(LazyCardWithUrlContent, {
|
|
95
|
+
id: id,
|
|
96
|
+
url: url,
|
|
97
|
+
appearance: appearance,
|
|
98
|
+
onClick: onClick,
|
|
99
|
+
isSelected: isSelected,
|
|
100
|
+
isFrameVisible: isFrameVisible,
|
|
101
|
+
dispatchAnalytics: dispatchAnalytics,
|
|
102
|
+
container: container,
|
|
103
|
+
onResolve: onResolve,
|
|
104
|
+
testId: testId,
|
|
105
|
+
showActions: showActions,
|
|
106
|
+
inheritDimensions: inheritDimensions,
|
|
107
|
+
platform: platform,
|
|
108
|
+
embedIframeRef: embedIframeRef,
|
|
109
|
+
inlinePreloaderStyle: inlinePreloaderStyle
|
|
110
|
+
})));
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
|
|
113
|
+
const ErrorFallback = () => {
|
|
114
|
+
return /*#__PURE__*/React.createElement("span", null);
|
|
115
|
+
};
|