@atlaskit/media-card 77.4.4 → 77.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/cjs/card/card.js +42 -38
- package/dist/cjs/card/getCardPreview/filePreviewStatus.js +2 -0
- package/dist/cjs/card/media-card-analytics-error-boundary.js +1 -1
- package/dist/cjs/card/v2/cardV2.js +1 -1
- package/dist/cjs/card/v2/fileCard.js +120 -521
- package/dist/cjs/card/v2/useFilePreview.js +592 -0
- package/dist/cjs/inline/loader.js +1 -1
- package/dist/cjs/utils/ufoExperiences.js +1 -1
- package/dist/es2019/card/card.js +7 -4
- package/dist/es2019/card/getCardPreview/filePreviewStatus.js +2 -0
- package/dist/es2019/card/media-card-analytics-error-boundary.js +1 -1
- package/dist/es2019/card/v2/cardV2.js +1 -1
- package/dist/es2019/card/v2/fileCard.js +105 -436
- package/dist/es2019/card/v2/useFilePreview.js +499 -0
- package/dist/es2019/inline/loader.js +1 -1
- package/dist/es2019/utils/ufoExperiences.js +1 -1
- package/dist/esm/card/card.js +42 -38
- package/dist/esm/card/getCardPreview/filePreviewStatus.js +2 -0
- package/dist/esm/card/media-card-analytics-error-boundary.js +1 -1
- package/dist/esm/card/v2/cardV2.js +1 -1
- package/dist/esm/card/v2/fileCard.js +125 -526
- package/dist/esm/card/v2/useFilePreview.js +584 -0
- package/dist/esm/inline/loader.js +1 -1
- package/dist/esm/utils/ufoExperiences.js +1 -1
- package/dist/types/card/card.d.ts +1 -1
- package/dist/types/card/v2/useFilePreview.d.ts +38 -0
- package/dist/types-ts4.5/card/card.d.ts +1 -1
- package/dist/types-ts4.5/card/v2/useFilePreview.d.ts +38 -0
- package/package.json +4 -4
- package/tmp/api-report-tmp.d.ts +0 -345
|
@@ -1,31 +1,26 @@
|
|
|
1
1
|
import DownloadIcon from '@atlaskit/icon/glyph/download';
|
|
2
|
-
import { RECENTS_COLLECTION,
|
|
2
|
+
import { RECENTS_COLLECTION, globalMediaEventEmitter, isImageRepresentationReady } from '@atlaskit/media-client';
|
|
3
3
|
import { MediaFileStateError, useFileState } from '@atlaskit/media-client-react';
|
|
4
|
-
import {
|
|
5
|
-
import { getOrientation } from '@atlaskit/media-ui';
|
|
4
|
+
import { getRandomHex, isMimeTypeSupportedByBrowser } from '@atlaskit/media-common';
|
|
6
5
|
import { MediaViewer } from '@atlaskit/media-viewer';
|
|
7
|
-
import React, { Suspense,
|
|
6
|
+
import React, { Suspense, useEffect, useMemo, useRef, useState } from 'react';
|
|
8
7
|
import ReactDOM from 'react-dom';
|
|
9
|
-
import {
|
|
10
|
-
import { extractErrorInfo } from '../../utils/analytics';
|
|
11
|
-
import { isBigger } from '../../utils/dimensionComparer';
|
|
8
|
+
import { MediaCardError } from '../../errors';
|
|
12
9
|
import getDocument from '../../utils/document';
|
|
13
10
|
import { generateUniqueId } from '../../utils/generateUniqueId';
|
|
14
11
|
import { getRequestedDimensions } from '../../utils/getDataURIDimension';
|
|
15
12
|
import { getMediaCardCursor } from '../../utils/getMediaCardCursor';
|
|
16
|
-
import { getSSRData, StoreSSRDataScript } from '../../utils/globalScope';
|
|
17
13
|
import { getFileDetails } from '../../utils/metadata';
|
|
18
14
|
import { abortUfoExperience, completeUfoExperience, startUfoExperience } from '../../utils/ufoExperiences';
|
|
19
15
|
import { useCurrentValueRef } from '../../utils/useCurrentValueRef';
|
|
20
16
|
import { usePrevious } from '../../utils/usePrevious';
|
|
21
17
|
import { videoIsPlayable } from '../../utils/videoIsPlayable';
|
|
22
|
-
import { takeSnapshot } from '../../utils/videoSnapshot';
|
|
23
18
|
import { ViewportDetector } from '../../utils/viewportDetector';
|
|
24
19
|
import { fireCommencedEvent, fireCopiedEvent, fireNonCriticalErrorEvent, fireOperationalEvent, fireScreenEvent } from '../cardAnalytics';
|
|
25
|
-
import {
|
|
26
|
-
import cardPreviewCache from '../getCardPreview/cache';
|
|
20
|
+
import { isSSRPreview } from '../getCardPreview';
|
|
27
21
|
import { CardViewV2 } from './cardViewV2';
|
|
28
22
|
import { InlinePlayerLazyV2 } from './inlinePlayerLazyV2';
|
|
23
|
+
import { useFilePreview } from './useFilePreview';
|
|
29
24
|
export const FileCard = ({
|
|
30
25
|
appearance = 'auto',
|
|
31
26
|
resizeMode = 'crop',
|
|
@@ -56,98 +51,18 @@ export const FileCard = ({
|
|
|
56
51
|
onMouseEnter,
|
|
57
52
|
createAnalyticsEvent
|
|
58
53
|
}) => {
|
|
59
|
-
var _ssrReliabilityRef$cu;
|
|
60
54
|
//----------------------------------------------------------------//
|
|
61
|
-
|
|
55
|
+
//------------ State, Refs & Initial Values ----------------------//
|
|
62
56
|
//----------------------------------------------------------------//
|
|
63
57
|
|
|
64
|
-
const ssrDataRef = useRef();
|
|
65
|
-
const ssrReliabilityRef = useRef({
|
|
66
|
-
server: {
|
|
67
|
-
status: 'unknown'
|
|
68
|
-
},
|
|
69
|
-
client: {
|
|
70
|
-
status: 'unknown'
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
58
|
const [cardElement, setCardElement] = useState(null);
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
allowAnimated: true
|
|
82
|
-
}), [cardElement, dimensions, identifier.collectionName, resizeMode]);
|
|
83
|
-
const getMediaBlobUrlAttrs = useCallback(fileState => {
|
|
84
|
-
const {
|
|
85
|
-
id,
|
|
86
|
-
collectionName: collection
|
|
87
|
-
} = identifier;
|
|
88
|
-
const {
|
|
89
|
-
mimeType,
|
|
90
|
-
name,
|
|
91
|
-
size
|
|
92
|
-
} = getFileDetails(identifier, fileState);
|
|
93
|
-
return contextId ? {
|
|
94
|
-
id,
|
|
95
|
-
collection,
|
|
96
|
-
contextId,
|
|
97
|
-
mimeType,
|
|
98
|
-
name,
|
|
99
|
-
size,
|
|
100
|
-
...(originalDimensions || getRequestedDimensions({
|
|
101
|
-
dimensions,
|
|
102
|
-
element: cardElement
|
|
103
|
-
})),
|
|
104
|
-
alt
|
|
105
|
-
} : undefined;
|
|
106
|
-
}, [alt, cardElement, contextId, dimensions, identifier, originalDimensions]);
|
|
107
|
-
const getSSRPreview = (ssr, identifier, mediaClient) => {
|
|
108
|
-
var _ssrDataRef$current, _ssrDataRef$current2;
|
|
109
|
-
ssrDataRef.current = getSSRData(identifier);
|
|
110
|
-
if ((_ssrDataRef$current = ssrDataRef.current) !== null && _ssrDataRef$current !== void 0 && _ssrDataRef$current.error) {
|
|
111
|
-
ssrReliabilityRef.current.server = {
|
|
112
|
-
status: 'fail',
|
|
113
|
-
...ssrDataRef.current.error
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
if (!((_ssrDataRef$current2 = ssrDataRef.current) !== null && _ssrDataRef$current2 !== void 0 && _ssrDataRef$current2.dataURI)) {
|
|
117
|
-
try {
|
|
118
|
-
return getSSRCardPreview(ssr, mediaClient, identifier.id, imageURLParams, getMediaBlobUrlAttrs(fileStateValue));
|
|
119
|
-
} catch (e) {
|
|
120
|
-
ssrReliabilityRef.current[ssr] = {
|
|
121
|
-
status: 'fail',
|
|
122
|
-
...extractErrorInfo(e)
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
} else {
|
|
126
|
-
return {
|
|
127
|
-
dataURI: ssrDataRef.current.dataURI,
|
|
128
|
-
source: 'ssr-data'
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
const cardPreviewInitializer = () => {
|
|
133
|
-
let cardPreview;
|
|
134
|
-
const {
|
|
135
|
-
id
|
|
136
|
-
} = identifier;
|
|
137
|
-
const fileImageMode = imageResizeModeToFileImageMode(resizeMode);
|
|
138
|
-
cardPreview = getCardPreviewFromCache(id, fileImageMode);
|
|
139
|
-
if (!cardPreview && ssr) {
|
|
140
|
-
cardPreview = getSSRPreview(ssr, identifier, mediaClient);
|
|
141
|
-
}
|
|
142
|
-
return cardPreview;
|
|
143
|
-
};
|
|
144
|
-
const [cardPreview, setCardPreview] = useState(cardPreviewInitializer);
|
|
145
|
-
|
|
146
|
-
// If cardPreview is available from local cache or external, `isCardVisible`
|
|
147
|
-
// should be true to avoid flickers during re-mount of the component
|
|
148
|
-
// should not be visible for SSR preview, otherwise we'll fire the metadata fetch from
|
|
149
|
-
// outside the viewport
|
|
150
|
-
const [isCardVisible, setIsCardVisible] = useState(() => !isLazy || cardPreview && !isSSRPreview(cardPreview));
|
|
59
|
+
const requestedDimensions = useMemo(() =>
|
|
60
|
+
// requested dimensions is eventually an expensive operation if the dimensions are a percentage
|
|
61
|
+
getRequestedDimensions({
|
|
62
|
+
dimensions,
|
|
63
|
+
element: cardElement
|
|
64
|
+
}), [dimensions, cardElement]);
|
|
65
|
+
const [isCardVisible, setIsCardVisible] = useState(!isLazy);
|
|
151
66
|
const {
|
|
152
67
|
fileState
|
|
153
68
|
} = useFileState(identifier.id, {
|
|
@@ -182,10 +97,58 @@ export const FileCard = ({
|
|
|
182
97
|
const [status, setStatus] = useState('loading');
|
|
183
98
|
const [isPlayingFile, setIsPlayingFile] = useState(false);
|
|
184
99
|
const [shouldAutoplay, setShouldAutoplay] = useState(false);
|
|
100
|
+
|
|
101
|
+
// CXP-2723 TODO: remove isBannedLocalPreview
|
|
185
102
|
const [isBannedLocalPreview, setIsBannedLocalPreview] = useState(false);
|
|
186
103
|
const [previewDidRender, setPreviewDidRender] = useState(false);
|
|
104
|
+
|
|
105
|
+
// CXP-2723 TODO: Do we have tests to validate the use of the below attributes
|
|
106
|
+
const mediaBlobUrlAttrs = useMemo(() => {
|
|
107
|
+
const {
|
|
108
|
+
id,
|
|
109
|
+
collectionName: collection
|
|
110
|
+
} = identifier;
|
|
111
|
+
const {
|
|
112
|
+
mimeType,
|
|
113
|
+
name,
|
|
114
|
+
size
|
|
115
|
+
} = getFileDetails(identifier, fileStateValue);
|
|
116
|
+
return contextId ? {
|
|
117
|
+
id,
|
|
118
|
+
collection,
|
|
119
|
+
contextId,
|
|
120
|
+
mimeType,
|
|
121
|
+
name,
|
|
122
|
+
size,
|
|
123
|
+
...(originalDimensions || requestedDimensions),
|
|
124
|
+
alt
|
|
125
|
+
} : undefined;
|
|
126
|
+
}, [alt, requestedDimensions, contextId, fileStateValue, identifier, originalDimensions]);
|
|
127
|
+
const {
|
|
128
|
+
cardPreview,
|
|
129
|
+
error: previewError,
|
|
130
|
+
nonCriticalError,
|
|
131
|
+
ssrReliabilityRef,
|
|
132
|
+
onImageError: onImageErrorBase,
|
|
133
|
+
onImageLoad: onImageLoadBase,
|
|
134
|
+
StoreSSRDataScript
|
|
135
|
+
} = useFilePreview({
|
|
136
|
+
mediaBlobUrlAttrs,
|
|
137
|
+
resizeMode,
|
|
138
|
+
identifier,
|
|
139
|
+
ssr,
|
|
140
|
+
mediaClient,
|
|
141
|
+
dimensions,
|
|
142
|
+
requestedDimensions,
|
|
143
|
+
traceContext,
|
|
144
|
+
previewDidRender,
|
|
145
|
+
skipRemote: !isCardVisible
|
|
146
|
+
});
|
|
187
147
|
const [error, setError] = useState();
|
|
188
|
-
|
|
148
|
+
|
|
149
|
+
// CXP-2723 TODO: TEMPORARY VARIABLES
|
|
150
|
+
const finalError = error || previewError;
|
|
151
|
+
const finalStatus = finalError ? 'error' : status;
|
|
189
152
|
const [mediaViewerSelectedItem, setMediaViewerSelectedItem] = useState(null);
|
|
190
153
|
const uploadProgressRef = useRef();
|
|
191
154
|
const metadata = useMemo(() => {
|
|
@@ -225,7 +188,7 @@ export const FileCard = ({
|
|
|
225
188
|
};
|
|
226
189
|
}, [fileStateValue === null || fileStateValue === void 0 ? void 0 : fileStateValue.status, metadata.id, metadata.mediaType, metadata.mimeType, metadata.size]);
|
|
227
190
|
const computedActions = useMemo(() => {
|
|
228
|
-
if (
|
|
191
|
+
if (finalStatus === 'failed-processing' || shouldEnableDownloadButton) {
|
|
229
192
|
const downloadAction = {
|
|
230
193
|
label: 'Download',
|
|
231
194
|
icon: /*#__PURE__*/React.createElement(DownloadIcon, {
|
|
@@ -237,7 +200,7 @@ export const FileCard = ({
|
|
|
237
200
|
} else {
|
|
238
201
|
return actions;
|
|
239
202
|
}
|
|
240
|
-
}, [actions, identifier.collectionName, identifier.id, mediaClient.file, metadata.name, shouldEnableDownloadButton,
|
|
203
|
+
}, [actions, identifier.collectionName, identifier.id, mediaClient.file, metadata.name, shouldEnableDownloadButton, finalStatus]);
|
|
241
204
|
|
|
242
205
|
//----------------------------------------------------------------//
|
|
243
206
|
//---------------------- Analytics ------------------------------//
|
|
@@ -252,12 +215,17 @@ export const FileCard = ({
|
|
|
252
215
|
durationSinceCommenced
|
|
253
216
|
}
|
|
254
217
|
};
|
|
255
|
-
createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent,
|
|
256
|
-
completeUfoExperience(internalOccurrenceKey,
|
|
218
|
+
createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent, finalStatus, fileAttributes, performanceAttributes, ssrReliabilityRef.current, finalError, traceContext, fileStateValue === null || fileStateValue === void 0 ? void 0 : fileStateValue.metadataTraceContext);
|
|
219
|
+
completeUfoExperience(internalOccurrenceKey, finalStatus, fileAttributes, fileStateFlagsRef.current, ssrReliabilityRef.current, finalError);
|
|
257
220
|
});
|
|
258
221
|
const fireNonCriticalErrorEventRef = useCurrentValueRef(error => {
|
|
259
|
-
createAnalyticsEvent && fireNonCriticalErrorEvent(createAnalyticsEvent,
|
|
222
|
+
createAnalyticsEvent && fireNonCriticalErrorEvent(createAnalyticsEvent, finalStatus, fileAttributes, ssrReliabilityRef.current, error, traceContext, fileStateValue === null || fileStateValue === void 0 ? void 0 : fileStateValue.metadataTraceContext);
|
|
260
223
|
});
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
if (nonCriticalError) {
|
|
226
|
+
fireNonCriticalErrorEventRef.current(nonCriticalError);
|
|
227
|
+
}
|
|
228
|
+
}, [nonCriticalError, fireNonCriticalErrorEventRef]);
|
|
261
229
|
const fireScreenEventRef = useCurrentValueRef(() => {
|
|
262
230
|
createAnalyticsEvent && fireScreenEvent(createAnalyticsEvent, fileAttributes);
|
|
263
231
|
});
|
|
@@ -283,73 +251,10 @@ export const FileCard = ({
|
|
|
283
251
|
//----------------------------------------------------------------//
|
|
284
252
|
|
|
285
253
|
const onImageError = newCardPreview => {
|
|
286
|
-
|
|
287
|
-
const failedSSRObject = {
|
|
288
|
-
status: 'fail',
|
|
289
|
-
...extractErrorInfo(new ImageLoadError(newCardPreview.source))
|
|
290
|
-
};
|
|
291
|
-
if (isSSRClientPreview(newCardPreview)) {
|
|
292
|
-
ssrReliabilityRef.current.client = failedSSRObject;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/*
|
|
296
|
-
If the cardPreview failed and it comes from server (global scope / ssrData), it means that we have reused it in client and the error counts for both: server & client.
|
|
297
|
-
*/
|
|
298
|
-
|
|
299
|
-
if (isSSRDataPreview(newCardPreview)) {
|
|
300
|
-
ssrReliabilityRef.current.server = failedSSRObject;
|
|
301
|
-
ssrReliabilityRef.current.client = failedSSRObject;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// If the dataURI has been replaced, we can dismiss this error
|
|
306
|
-
if ((newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.dataURI) !== (cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI)) {
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
const error = new ImageLoadError(newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.source);
|
|
310
|
-
const isLocal = newCardPreview && isLocalPreview(newCardPreview);
|
|
311
|
-
const isSSR = newCardPreview && (isSSRClientPreview(newCardPreview) || isSSRDataPreview(newCardPreview));
|
|
312
|
-
if (isLocal || isSSR) {
|
|
313
|
-
if (isLocal) {
|
|
314
|
-
setIsBannedLocalPreview(true);
|
|
315
|
-
fireNonCriticalErrorEventRef.current && fireNonCriticalErrorEventRef.current(error);
|
|
316
|
-
}
|
|
317
|
-
const fileImageMode = imageResizeModeToFileImageMode(resizeMode);
|
|
318
|
-
isFileIdentifier(identifier) && removeCardPreviewFromCache(identifier.id, fileImageMode);
|
|
319
|
-
setCardPreview(undefined);
|
|
320
|
-
} else {
|
|
321
|
-
if (!['complete', 'error', 'failed-processing'].includes(status)) {
|
|
322
|
-
setStatus('error');
|
|
323
|
-
setError(error);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
254
|
+
onImageErrorBase(newCardPreview);
|
|
326
255
|
};
|
|
327
256
|
const onImageLoad = newCardPreview => {
|
|
328
|
-
|
|
329
|
-
if (isSSRClientPreview(newCardPreview) && ssrReliabilityRef.current.client.status === 'unknown') {
|
|
330
|
-
ssrReliabilityRef.current.client = {
|
|
331
|
-
status: 'success'
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/*
|
|
336
|
-
If the image loads successfully and it comes from server (global scope / ssrData), it means that we have reused it in client and the success counts for both: server & client.
|
|
337
|
-
*/
|
|
338
|
-
|
|
339
|
-
if (isSSRDataPreview(newCardPreview) && ssrReliabilityRef.current.server.status === 'unknown') {
|
|
340
|
-
ssrReliabilityRef.current.server = {
|
|
341
|
-
status: 'success'
|
|
342
|
-
};
|
|
343
|
-
ssrReliabilityRef.current.client = {
|
|
344
|
-
status: 'success'
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// If the dataURI has been replaced, we can dismiss this callback
|
|
350
|
-
if ((newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.dataURI) !== (cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI)) {
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
257
|
+
onImageLoadBase(newCardPreview);
|
|
353
258
|
setPreviewDidRender(true);
|
|
354
259
|
};
|
|
355
260
|
const onCardClick = (event, analyticsEvent) => {
|
|
@@ -367,7 +272,7 @@ export const FileCard = ({
|
|
|
367
272
|
return;
|
|
368
273
|
}
|
|
369
274
|
const isVideo = metadata && metadata.mediaType === 'video';
|
|
370
|
-
if (useInlinePlayer && isVideo && !!cardPreview) {
|
|
275
|
+
if (useInlinePlayer && isVideo && !!cardPreview && finalStatus !== 'error') {
|
|
371
276
|
setIsPlayingFile(true);
|
|
372
277
|
setShouldAutoplay(true);
|
|
373
278
|
} else if (shouldOpenMediaViewer) {
|
|
@@ -380,196 +285,6 @@ export const FileCard = ({
|
|
|
380
285
|
}
|
|
381
286
|
};
|
|
382
287
|
|
|
383
|
-
//----------------------------------------------------------------//
|
|
384
|
-
//---------------------- Helper Functions -----------------------//
|
|
385
|
-
//----------------------------------------------------------------//
|
|
386
|
-
|
|
387
|
-
const fetchRemotePreviewRef = useCurrentValueRef(identifier => {
|
|
388
|
-
return fetchAndCacheRemotePreview(mediaClient, identifier.id, dimensions !== null && dimensions !== void 0 ? dimensions : {}, imageURLParams, getMediaBlobUrlAttrs(fileStateValue));
|
|
389
|
-
});
|
|
390
|
-
const resolvePreviewRef = useCurrentValueRef(async (identifier, fileState) => {
|
|
391
|
-
const filePreview = isBannedLocalPreview ? undefined : fileState.status !== 'error' && 'mimeType' in fileState && isMimeTypeSupportedByBrowser(fileState.mimeType) ? fileState.preview : undefined;
|
|
392
|
-
const isRemotePreviewReady = isImageRepresentationReady(fileState);
|
|
393
|
-
try {
|
|
394
|
-
const mode = imageURLParams.mode;
|
|
395
|
-
const cachedPreview = cardPreviewCache.get(identifier.id, mode);
|
|
396
|
-
const dimensionsAreBigger = isBigger(cachedPreview === null || cachedPreview === void 0 ? void 0 : cachedPreview.dimensions, dimensions);
|
|
397
|
-
if (cachedPreview && !dimensionsAreBigger) {
|
|
398
|
-
return cachedPreview;
|
|
399
|
-
}
|
|
400
|
-
let localPreview;
|
|
401
|
-
try {
|
|
402
|
-
if (filePreview) {
|
|
403
|
-
let value;
|
|
404
|
-
try {
|
|
405
|
-
const resolvedFilePreview = await filePreview;
|
|
406
|
-
value = resolvedFilePreview.value;
|
|
407
|
-
} catch (e) {
|
|
408
|
-
throw new LocalPreviewError('local-preview-rejected', e instanceof Error ? e : undefined);
|
|
409
|
-
}
|
|
410
|
-
if (typeof value === 'string') {
|
|
411
|
-
localPreview = {
|
|
412
|
-
dataURI: value,
|
|
413
|
-
orientation: 1,
|
|
414
|
-
source: 'local'
|
|
415
|
-
};
|
|
416
|
-
} else if (value instanceof Blob) {
|
|
417
|
-
const {
|
|
418
|
-
type
|
|
419
|
-
} = value;
|
|
420
|
-
const mediaType = getMediaTypeFromMimeType(type);
|
|
421
|
-
switch (mediaType) {
|
|
422
|
-
case 'image':
|
|
423
|
-
try {
|
|
424
|
-
const orientation = await getOrientation(value);
|
|
425
|
-
const dataURI = URL.createObjectURL(value);
|
|
426
|
-
localPreview = {
|
|
427
|
-
dataURI,
|
|
428
|
-
orientation,
|
|
429
|
-
source: 'local'
|
|
430
|
-
};
|
|
431
|
-
} catch (e) {
|
|
432
|
-
throw new LocalPreviewError('local-preview-image', e instanceof Error ? e : undefined);
|
|
433
|
-
}
|
|
434
|
-
break;
|
|
435
|
-
case 'video':
|
|
436
|
-
try {
|
|
437
|
-
const dataURI = await takeSnapshot(value);
|
|
438
|
-
localPreview = {
|
|
439
|
-
dataURI,
|
|
440
|
-
orientation: 1,
|
|
441
|
-
source: 'local'
|
|
442
|
-
};
|
|
443
|
-
} catch (e) {
|
|
444
|
-
throw new LocalPreviewError('local-preview-video', e instanceof Error ? e : undefined);
|
|
445
|
-
}
|
|
446
|
-
break;
|
|
447
|
-
default:
|
|
448
|
-
throw new LocalPreviewError('local-preview-unsupported');
|
|
449
|
-
}
|
|
450
|
-
} else {
|
|
451
|
-
throw new LocalPreviewError('local-preview-unsupported');
|
|
452
|
-
}
|
|
453
|
-
const preview = {
|
|
454
|
-
...localPreview,
|
|
455
|
-
dimensions
|
|
456
|
-
};
|
|
457
|
-
let source;
|
|
458
|
-
switch (preview.source) {
|
|
459
|
-
case 'local':
|
|
460
|
-
source = 'cache-local';
|
|
461
|
-
break;
|
|
462
|
-
case 'remote':
|
|
463
|
-
source = 'cache-remote';
|
|
464
|
-
break;
|
|
465
|
-
case 'ssr-server':
|
|
466
|
-
source = 'cache-ssr-server';
|
|
467
|
-
break;
|
|
468
|
-
case 'ssr-client':
|
|
469
|
-
source = 'cache-ssr-client';
|
|
470
|
-
break;
|
|
471
|
-
default:
|
|
472
|
-
source = preview.source;
|
|
473
|
-
}
|
|
474
|
-
// We want to embed some meta context into dataURI for Copy/Paste to work.
|
|
475
|
-
const mediaBlobUrlAttrs = getMediaBlobUrlAttrs(fileStateValue);
|
|
476
|
-
const dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(preview.dataURI, mediaBlobUrlAttrs) : preview.dataURI;
|
|
477
|
-
// We store new cardPreview into cache
|
|
478
|
-
cardPreviewCache.set(identifier.id, mode, {
|
|
479
|
-
...preview,
|
|
480
|
-
source,
|
|
481
|
-
dataURI
|
|
482
|
-
});
|
|
483
|
-
setCardPreview({
|
|
484
|
-
...preview,
|
|
485
|
-
dataURI
|
|
486
|
-
});
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
} catch (e) {
|
|
490
|
-
/**
|
|
491
|
-
* We report the error if:
|
|
492
|
-
* - local preview is supported and fails
|
|
493
|
-
* - local preview is unsupported and remote preview is NOT READY
|
|
494
|
-
* i.e. the function was called for "no reason".
|
|
495
|
-
* We DON'T report the error if:
|
|
496
|
-
* - local preview is unsupported and remote preview IS READY
|
|
497
|
-
* i.e. local preview is available and not supported,
|
|
498
|
-
* but we are after the remote preview instead.
|
|
499
|
-
*/
|
|
500
|
-
if (!isUnsupportedLocalPreviewError(e) || isUnsupportedLocalPreviewError(e) && !isRemotePreviewReady) {
|
|
501
|
-
fireNonCriticalErrorEventRef.current && fireNonCriticalErrorEventRef.current(e);
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* No matter the reason why the local preview failed, we break the process
|
|
505
|
-
* if there is no remote preview available
|
|
506
|
-
*/
|
|
507
|
-
if (!isRemotePreviewReady) {
|
|
508
|
-
throw e;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
if (!isRemotePreviewReady) {
|
|
512
|
-
/**
|
|
513
|
-
* We throw this in case this function has been called
|
|
514
|
-
* without checking isRemotePreviewReady first.
|
|
515
|
-
* If remote preview is not ready, the call to getCardPreviewFromBackend
|
|
516
|
-
* will generate a console error due to a 404 code
|
|
517
|
-
*/
|
|
518
|
-
throw new MediaCardError('remote-preview-not-ready');
|
|
519
|
-
}
|
|
520
|
-
const remotePreview = await fetchAndCacheRemotePreview(mediaClient, identifier.id, dimensions !== null && dimensions !== void 0 ? dimensions : {}, imageURLParams, getMediaBlobUrlAttrs(fileStateValue), traceContext);
|
|
521
|
-
setCardPreview(remotePreview);
|
|
522
|
-
return;
|
|
523
|
-
} catch (e) {
|
|
524
|
-
const wrappedError = ensureMediaCardError('preview-fetch', e);
|
|
525
|
-
// If remote preview fails, we set status 'error'
|
|
526
|
-
// If local preview fails (i.e, no remote preview available),
|
|
527
|
-
// we can stay in the same status until there is a remote preview available
|
|
528
|
-
// If it's any other error we set status 'error'
|
|
529
|
-
if (isLocalPreviewError(wrappedError)) {
|
|
530
|
-
// This error should already been logged inside the getCardPreview. No need to log it here.
|
|
531
|
-
setIsBannedLocalPreview(true);
|
|
532
|
-
} else {
|
|
533
|
-
if (!['complete', 'error', 'failed-processing'].includes(status)) {
|
|
534
|
-
setStatus('error');
|
|
535
|
-
setError(wrappedError);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
//----------------------------------------------------------------//
|
|
542
|
-
//------------ resolveUpfrontPreview useEffect -------------------//
|
|
543
|
-
//----------------------------------------------------------------//
|
|
544
|
-
const prevCardPreview = usePrevious(cardPreview);
|
|
545
|
-
const dimensionsRef = useCurrentValueRef(dimensions);
|
|
546
|
-
useEffect(() => {
|
|
547
|
-
const resolveUpfrontPreview = async identifier => {
|
|
548
|
-
// We block any possible future call to this method regardless of the outcome (success or fail)
|
|
549
|
-
// If it fails, the normal preview fetch should occur after the file state is fetched anyways
|
|
550
|
-
wasResolvedUpfrontPreviewRef.current = true;
|
|
551
|
-
try {
|
|
552
|
-
const requestedDimensions = {
|
|
553
|
-
...dimensions
|
|
554
|
-
};
|
|
555
|
-
const newCardPreview = await fetchRemotePreviewRef.current(identifier);
|
|
556
|
-
const areValidRequestedDimensions = !isBigger(requestedDimensions, dimensionsRef.current);
|
|
557
|
-
|
|
558
|
-
// If there are new and bigger dimensions in the props, and the upfront preview is still resolving,
|
|
559
|
-
// the fetched preview is no longer valid, and thus, we dismiss it
|
|
560
|
-
if (areValidRequestedDimensions) {
|
|
561
|
-
setCardPreview(newCardPreview);
|
|
562
|
-
}
|
|
563
|
-
} catch (e) {
|
|
564
|
-
// NO need to log error. If this call fails, a refetch will happen after
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
const hadSSRCardPreview = ssr === 'client' && !!prevCardPreview && isSSRClientPreview(prevCardPreview);
|
|
568
|
-
if ((isCardVisible || hadSSRCardPreview) && !cardPreview && !wasResolvedUpfrontPreviewRef.current) {
|
|
569
|
-
resolveUpfrontPreview(identifier);
|
|
570
|
-
}
|
|
571
|
-
}, [cardPreview, dimensions, dimensionsRef, fetchRemotePreviewRef, identifier, isCardVisible, prevCardPreview, ssr]);
|
|
572
|
-
|
|
573
288
|
//----------------------------------------------------------------//
|
|
574
289
|
//------------------------ handle fireCopiedEvent --------------//
|
|
575
290
|
//----------------------------------------------------------------//
|
|
@@ -607,64 +322,19 @@ export const FileCard = ({
|
|
|
607
322
|
//---------------- fetch and resolve card preview ----------------//
|
|
608
323
|
//----------------------------------------------------------------//
|
|
609
324
|
|
|
610
|
-
const
|
|
325
|
+
const prevStatus = usePrevious(finalStatus);
|
|
611
326
|
const prevIsCardVisible = usePrevious(isCardVisible);
|
|
612
|
-
const prevStatus = usePrevious(status);
|
|
613
327
|
useEffect(() => {
|
|
614
|
-
if (prevStatus !== undefined &&
|
|
328
|
+
if (prevStatus !== undefined && finalStatus !== prevStatus) {
|
|
615
329
|
fireOperationalEventRef.current();
|
|
616
330
|
}
|
|
617
|
-
}, [fireOperationalEventRef, prevStatus,
|
|
331
|
+
}, [fireOperationalEventRef, prevStatus, finalStatus]);
|
|
618
332
|
useEffect(() => {
|
|
619
|
-
var _ssrDataRef$current3;
|
|
620
|
-
/**
|
|
621
|
-
* Variable turnedVisible should only be true when media card
|
|
622
|
-
* was invisible in the previous state and is visible in the current one
|
|
623
|
-
*
|
|
624
|
-
* prevIsCardVisible | isCardVisible | turnedVisible
|
|
625
|
-
* ----------------------------------------------------
|
|
626
|
-
* false | false | false
|
|
627
|
-
* false | true | true
|
|
628
|
-
* true | true | false
|
|
629
|
-
* true | false | false (unreachable case)
|
|
630
|
-
* ----------------------------------------------------
|
|
631
|
-
*/
|
|
632
|
-
|
|
633
333
|
const turnedVisible = !prevIsCardVisible && isCardVisible;
|
|
634
334
|
if (turnedVisible) {
|
|
635
335
|
fireCommencedEventRef.current();
|
|
636
336
|
}
|
|
637
|
-
|
|
638
|
-
// If dimensions from Server have changed and are bigger,
|
|
639
|
-
// we need to refetch
|
|
640
|
-
// refetchSRRPreview
|
|
641
|
-
fetchRemotePreviewRef.current(identifier).then(setCardPreview).catch(e => {
|
|
642
|
-
const wrappedError = ensureMediaCardError('remote-preview-fetch-ssr', e, true);
|
|
643
|
-
fireNonCriticalErrorEventRef.current(wrappedError);
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
if (fileStateValue && shouldResolvePreview({
|
|
647
|
-
status,
|
|
648
|
-
fileState: fileStateValue,
|
|
649
|
-
prevDimensions,
|
|
650
|
-
dimensions,
|
|
651
|
-
hasCardPreview: !!cardPreview,
|
|
652
|
-
isBannedLocalPreview,
|
|
653
|
-
wasResolvedUpfrontPreview: wasResolvedUpfrontPreviewRef.current
|
|
654
|
-
})) {
|
|
655
|
-
resolvePreviewRef.current(identifier, fileStateValue);
|
|
656
|
-
}
|
|
657
|
-
if (turnedVisible && ssr && !!cardPreview && isSSRClientPreview(cardPreview)) {
|
|
658
|
-
// Since the SSR preview brings the token in the query params,
|
|
659
|
-
// We need to fetch the remote preview to be able to cache it,
|
|
660
|
-
fetchRemotePreviewRef.current(identifier).catch(() => {
|
|
661
|
-
// No need to log this error.
|
|
662
|
-
// If preview fails, it will be refetched later
|
|
663
|
-
//TODO: test this catch
|
|
664
|
-
// https://product-fabric.atlassian.net/browse/MEX-1071
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
}, [cardPreview, dimensions, fetchRemotePreviewRef, fileStateValue, fireCommencedEventRef, fireNonCriticalErrorEventRef, identifier, isBannedLocalPreview, isCardVisible, prevDimensions, prevIsCardVisible, resolvePreviewRef, ssr, status]);
|
|
337
|
+
}, [fireCommencedEventRef, isCardVisible, prevIsCardVisible]);
|
|
668
338
|
|
|
669
339
|
//----------------------------------------------------------------//
|
|
670
340
|
//----------------- set complete status --------------------------//
|
|
@@ -673,12 +343,12 @@ export const FileCard = ({
|
|
|
673
343
|
useEffect(() => {
|
|
674
344
|
if (previewDidRender &&
|
|
675
345
|
// We should't complete if status is uploading
|
|
676
|
-
['loading-preview', 'processing'].includes(
|
|
346
|
+
['loading-preview', 'processing'].includes(finalStatus)) {
|
|
677
347
|
setStatus('complete');
|
|
678
348
|
// TODO MEX-788: add test for "do not remove the card preview when unsubscribing".
|
|
679
349
|
setIsBannedLocalPreview(false);
|
|
680
350
|
}
|
|
681
|
-
}, [previewDidRender,
|
|
351
|
+
}, [previewDidRender, finalStatus]);
|
|
682
352
|
|
|
683
353
|
//----------------------------------------------------------------//
|
|
684
354
|
//----------------- set isPlayingFile state ----------------------//
|
|
@@ -696,22 +366,22 @@ export const FileCard = ({
|
|
|
696
366
|
* in order to avoid race conditions of the ViewportDector being unmounted before
|
|
697
367
|
* it is able to set isCardVisible to true.
|
|
698
368
|
*/
|
|
699
|
-
isCardVisible && isVideo && !isPlayingFile && disableOverlay && useInlinePlayer && isVideoPlayable) {
|
|
369
|
+
isCardVisible && isVideo && !isPlayingFile && disableOverlay && useInlinePlayer && isVideoPlayable && finalStatus !== 'error') {
|
|
700
370
|
setIsPlayingFile(true);
|
|
701
371
|
}
|
|
702
|
-
}, [isCardVisible, disableOverlay, fileAttributes.fileMediatype, fileStateValue, identifier, isBannedLocalPreview, isPlayingFile, useInlinePlayer]);
|
|
372
|
+
}, [isCardVisible, disableOverlay, fileAttributes.fileMediatype, fileStateValue, identifier, isBannedLocalPreview, isPlayingFile, finalStatus, useInlinePlayer]);
|
|
703
373
|
|
|
704
374
|
//----------------------------------------------------------------//
|
|
705
375
|
//----------------- fireScreenEvent ------------------------------//
|
|
706
376
|
//----------------------------------------------------------------//
|
|
707
377
|
|
|
708
378
|
useEffect(() => {
|
|
709
|
-
if (prevStatus !== undefined &&
|
|
710
|
-
if (
|
|
379
|
+
if (prevStatus !== undefined && finalStatus !== prevStatus) {
|
|
380
|
+
if (finalStatus === 'complete' || fileAttributes.fileMediatype === 'video' && !!cardPreview && finalStatus === 'processing') {
|
|
711
381
|
fireScreenEventRef.current();
|
|
712
382
|
}
|
|
713
383
|
}
|
|
714
|
-
}, [
|
|
384
|
+
}, [finalStatus, prevStatus, fileAttributes, cardPreview, fireScreenEventRef]);
|
|
715
385
|
|
|
716
386
|
//----------------------------------------------------------------//
|
|
717
387
|
//----------------- abort UFO experience -------------------------//
|
|
@@ -731,7 +401,7 @@ export const FileCard = ({
|
|
|
731
401
|
const updateFileStateRef = useCurrentValueRef(() => {
|
|
732
402
|
if (fileState) {
|
|
733
403
|
// do not update the card status if the status is final
|
|
734
|
-
if (['complete', 'error', 'failed-processing'].includes(
|
|
404
|
+
if (['complete', 'error', 'failed-processing'].includes(finalStatus)) {
|
|
735
405
|
return;
|
|
736
406
|
}
|
|
737
407
|
if (fileState.status !== 'error') {
|
|
@@ -739,7 +409,9 @@ export const FileCard = ({
|
|
|
739
409
|
const isPreviewable = !!mediaType && ['audio', 'video', 'image', 'doc'].indexOf(mediaType) > -1;
|
|
740
410
|
const isPreviewableFileState = !!fileState.preview;
|
|
741
411
|
const isSupportedLocalPreview = mediaType === 'image' || mediaType === 'video';
|
|
742
|
-
const hasLocalPreview = !isBannedLocalPreview && isPreviewableFileState &&
|
|
412
|
+
const hasLocalPreview = !isBannedLocalPreview && isPreviewableFileState &&
|
|
413
|
+
// CXP-2723 TODO: isPreviewableFileState is most likely redundant
|
|
414
|
+
isSupportedLocalPreview && !!fileState.mimeType && isMimeTypeSupportedByBrowser(fileState.mimeType);
|
|
743
415
|
const hasRemotePreview = isImageRepresentationReady(fileState);
|
|
744
416
|
const hasPreview = hasLocalPreview || hasRemotePreview;
|
|
745
417
|
let newStatus;
|
|
@@ -764,7 +436,7 @@ export const FileCard = ({
|
|
|
764
436
|
uploadProgressRef.current = newProgress;
|
|
765
437
|
} else {
|
|
766
438
|
const e = new MediaFileStateError(fileState.id, fileState.reason, fileState.message, fileState.details);
|
|
767
|
-
const errorReason =
|
|
439
|
+
const errorReason = finalStatus === 'uploading' ? 'upload' : 'metadata-fetch';
|
|
768
440
|
setError(new MediaCardError(errorReason, e));
|
|
769
441
|
setStatus('error');
|
|
770
442
|
}
|
|
@@ -784,15 +456,18 @@ export const FileCard = ({
|
|
|
784
456
|
} = identifier;
|
|
785
457
|
const isLazyWithOverride = izLazyOverride === undefined ? isLazy : izLazyOverride;
|
|
786
458
|
|
|
787
|
-
//
|
|
788
|
-
//
|
|
789
|
-
|
|
459
|
+
// We should natively lazy load an SSR preview when card is not visible,
|
|
460
|
+
// otherwise we'll fire the metadata fetch from outside the viewport
|
|
461
|
+
// Side note: We should not lazy load if the cardPreview is available from local cache,
|
|
462
|
+
// in order to avoid flickers during re-mount of the component
|
|
463
|
+
// CXP-2723 TODO: Create test cases for the above scenarios
|
|
464
|
+
const nativeLazyLoad = isLazyWithOverride && !isCardVisible && cardPreview && isSSRPreview(cardPreview);
|
|
790
465
|
// Force Media Image to always display img for SSR
|
|
791
466
|
const forceSyncDisplay = !!ssr;
|
|
792
|
-
const mediaCardCursor = getMediaCardCursor(!!useInlinePlayer, !!shouldOpenMediaViewer,
|
|
467
|
+
const mediaCardCursor = getMediaCardCursor(!!useInlinePlayer, !!shouldOpenMediaViewer, finalStatus === 'error' || finalStatus === 'failed-processing', !!cardPreview, metadata.mediaType);
|
|
793
468
|
const card = /*#__PURE__*/React.createElement(CardViewV2, {
|
|
794
|
-
status: cardStatusOverride ||
|
|
795
|
-
error:
|
|
469
|
+
status: cardStatusOverride || finalStatus,
|
|
470
|
+
error: finalError,
|
|
796
471
|
mediaItemType: mediaItemType,
|
|
797
472
|
metadata: metadata,
|
|
798
473
|
cardPreview: cardPreview,
|
|
@@ -856,7 +531,9 @@ export const FileCard = ({
|
|
|
856
531
|
identifier: identifier,
|
|
857
532
|
autoplay: !!shouldAutoplay,
|
|
858
533
|
onFullscreenChange: onFullscreenChange,
|
|
859
|
-
onError:
|
|
534
|
+
onError: e => {
|
|
535
|
+
setError(new MediaCardError('error-file-state', e));
|
|
536
|
+
setStatus('error');
|
|
860
537
|
setIsPlayingFile(false);
|
|
861
538
|
},
|
|
862
539
|
onClick: onCardClick,
|
|
@@ -874,13 +551,5 @@ export const FileCard = ({
|
|
|
874
551
|
},
|
|
875
552
|
contextId: contextId,
|
|
876
553
|
featureFlags: featureFlags
|
|
877
|
-
}), document.body) : null, ssr === 'server' && /*#__PURE__*/React.createElement(StoreSSRDataScript,
|
|
878
|
-
identifier: identifier,
|
|
879
|
-
dataURI: cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI,
|
|
880
|
-
dimensions: getRequestedDimensions({
|
|
881
|
-
dimensions,
|
|
882
|
-
element: cardElement
|
|
883
|
-
}),
|
|
884
|
-
error: ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined
|
|
885
|
-
}));
|
|
554
|
+
}), document.body) : null, ssr === 'server' && /*#__PURE__*/React.createElement(StoreSSRDataScript, null));
|
|
886
555
|
};
|