@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
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { addFileAttrsToUrl, imageResizeModeToFileImageMode, isImageRepresentationReady } from '@atlaskit/media-client';
|
|
3
|
+
import { MediaFileStateError, useFileState } from '@atlaskit/media-client-react';
|
|
4
|
+
import { getMediaTypeFromMimeType, isMimeTypeSupportedByBrowser } from '@atlaskit/media-common';
|
|
5
|
+
import { getOrientation } from '@atlaskit/media-ui';
|
|
6
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
7
|
+
import { ImageLoadError, LocalPreviewError, MediaCardError, ensureMediaCardError, isLocalPreviewError, isUnsupportedLocalPreviewError } from '../../errors';
|
|
8
|
+
import { extractErrorInfo } from '../../utils/analytics';
|
|
9
|
+
import { isBigger } from '../../utils/dimensionComparer';
|
|
10
|
+
import { getSSRData } from '../../utils/globalScope';
|
|
11
|
+
import { useCurrentValueRef } from '../../utils/useCurrentValueRef';
|
|
12
|
+
import { usePrevious } from '../../utils/usePrevious';
|
|
13
|
+
import { takeSnapshot } from '../../utils/videoSnapshot';
|
|
14
|
+
import { fetchAndCacheRemotePreview, getCardPreviewFromCache, getSSRCardPreview, isLocalPreview, isSSRClientPreview, isSSRDataPreview, removeCardPreviewFromCache, shouldResolvePreview } from '../getCardPreview';
|
|
15
|
+
import cardPreviewCache from '../getCardPreview/cache';
|
|
16
|
+
import { StoreSSRDataScript } from '../../utils/globalScope';
|
|
17
|
+
export const useFilePreview = ({
|
|
18
|
+
resizeMode = 'crop',
|
|
19
|
+
identifier,
|
|
20
|
+
ssr,
|
|
21
|
+
mediaClient,
|
|
22
|
+
dimensions,
|
|
23
|
+
requestedDimensions,
|
|
24
|
+
traceContext,
|
|
25
|
+
previewDidRender,
|
|
26
|
+
skipRemote,
|
|
27
|
+
mediaBlobUrlAttrs
|
|
28
|
+
}) => {
|
|
29
|
+
const [error, setError] = useState();
|
|
30
|
+
const [nonCriticalError, setNonCriticalError] = useState();
|
|
31
|
+
//----------------------------------------------------------------//
|
|
32
|
+
//---------------- State Initializer Functions -------------------//
|
|
33
|
+
//----------------------------------------------------------------//
|
|
34
|
+
|
|
35
|
+
const ssrDataRef = useRef();
|
|
36
|
+
const ssrReliabilityRef = useRef({
|
|
37
|
+
server: {
|
|
38
|
+
status: 'unknown'
|
|
39
|
+
},
|
|
40
|
+
client: {
|
|
41
|
+
status: 'unknown'
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const imageURLParams = useMemo(() => ({
|
|
45
|
+
collection: identifier.collectionName,
|
|
46
|
+
mode: resizeMode === 'stretchy-fit' ? 'full-fit' : resizeMode,
|
|
47
|
+
...requestedDimensions,
|
|
48
|
+
allowAnimated: true
|
|
49
|
+
}), [requestedDimensions, identifier.collectionName, resizeMode]);
|
|
50
|
+
const getSSRPreview = (ssr, identifier, mediaClient) => {
|
|
51
|
+
var _ssrDataRef$current, _ssrDataRef$current2;
|
|
52
|
+
ssrDataRef.current = getSSRData(identifier);
|
|
53
|
+
if ((_ssrDataRef$current = ssrDataRef.current) !== null && _ssrDataRef$current !== void 0 && _ssrDataRef$current.error) {
|
|
54
|
+
ssrReliabilityRef.current.server = {
|
|
55
|
+
status: 'fail',
|
|
56
|
+
...ssrDataRef.current.error
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (!((_ssrDataRef$current2 = ssrDataRef.current) !== null && _ssrDataRef$current2 !== void 0 && _ssrDataRef$current2.dataURI)) {
|
|
60
|
+
try {
|
|
61
|
+
return getSSRCardPreview(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
ssrReliabilityRef.current[ssr] = {
|
|
64
|
+
status: 'fail',
|
|
65
|
+
...extractErrorInfo(e)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
return {
|
|
70
|
+
dataURI: ssrDataRef.current.dataURI,
|
|
71
|
+
source: 'ssr-data'
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const cardPreviewInitializer = () => {
|
|
76
|
+
let cardPreview;
|
|
77
|
+
const {
|
|
78
|
+
id
|
|
79
|
+
} = identifier;
|
|
80
|
+
const fileImageMode = imageResizeModeToFileImageMode(resizeMode);
|
|
81
|
+
cardPreview = getCardPreviewFromCache(id, fileImageMode);
|
|
82
|
+
if (!cardPreview && ssr) {
|
|
83
|
+
cardPreview = getSSRPreview(ssr, identifier, mediaClient);
|
|
84
|
+
}
|
|
85
|
+
return cardPreview;
|
|
86
|
+
};
|
|
87
|
+
const [cardPreview, setCardPreview] = useState(cardPreviewInitializer);
|
|
88
|
+
const {
|
|
89
|
+
fileState
|
|
90
|
+
} = useFileState(identifier.id, {
|
|
91
|
+
skipRemote,
|
|
92
|
+
collectionName: identifier.collectionName,
|
|
93
|
+
occurrenceKey: identifier.occurrenceKey
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
//----------------------------------------------------------------//
|
|
97
|
+
//------------ State, Refs & Initial Values ----------------------//
|
|
98
|
+
//----------------------------------------------------------------//
|
|
99
|
+
|
|
100
|
+
const [status, setStatus] = useState('loading');
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
setStatus('loading');
|
|
103
|
+
}, [identifier]);
|
|
104
|
+
const [isBannedLocalPreview, setIsBannedLocalPreview] = useState(false);
|
|
105
|
+
const wasResolvedUpfrontPreviewRef = useRef(false);
|
|
106
|
+
|
|
107
|
+
//----------------------------------------------------------------//
|
|
108
|
+
//---------------------- Helper Functions -----------------------//
|
|
109
|
+
//----------------------------------------------------------------//
|
|
110
|
+
|
|
111
|
+
const fetchRemotePreviewRef = useCurrentValueRef(identifier => {
|
|
112
|
+
return fetchAndCacheRemotePreview(mediaClient, identifier.id, dimensions !== null && dimensions !== void 0 ? dimensions : {}, imageURLParams, mediaBlobUrlAttrs);
|
|
113
|
+
});
|
|
114
|
+
const resolvePreviewRef = useCurrentValueRef(async (identifier, fileState) => {
|
|
115
|
+
const filePreview = isBannedLocalPreview ? undefined : fileState.status !== 'error' && 'mimeType' in fileState && isMimeTypeSupportedByBrowser(fileState.mimeType) ? fileState.preview : undefined;
|
|
116
|
+
const isRemotePreviewReady = isImageRepresentationReady(fileState);
|
|
117
|
+
try {
|
|
118
|
+
const mode = imageURLParams.mode;
|
|
119
|
+
const cachedPreview = cardPreviewCache.get(identifier.id, mode);
|
|
120
|
+
const dimensionsAreBigger = isBigger(cachedPreview === null || cachedPreview === void 0 ? void 0 : cachedPreview.dimensions, dimensions);
|
|
121
|
+
if (cachedPreview && !dimensionsAreBigger) {
|
|
122
|
+
return cachedPreview;
|
|
123
|
+
}
|
|
124
|
+
let localPreview;
|
|
125
|
+
try {
|
|
126
|
+
if (filePreview) {
|
|
127
|
+
let value;
|
|
128
|
+
try {
|
|
129
|
+
const resolvedFilePreview = await filePreview;
|
|
130
|
+
value = resolvedFilePreview.value;
|
|
131
|
+
} catch (e) {
|
|
132
|
+
throw new LocalPreviewError('local-preview-rejected', e instanceof Error ? e : undefined);
|
|
133
|
+
}
|
|
134
|
+
if (typeof value === 'string') {
|
|
135
|
+
localPreview = {
|
|
136
|
+
dataURI: value,
|
|
137
|
+
orientation: 1,
|
|
138
|
+
source: 'local'
|
|
139
|
+
};
|
|
140
|
+
} else if (value instanceof Blob) {
|
|
141
|
+
const {
|
|
142
|
+
type
|
|
143
|
+
} = value;
|
|
144
|
+
const mediaType = getMediaTypeFromMimeType(type);
|
|
145
|
+
switch (mediaType) {
|
|
146
|
+
case 'image':
|
|
147
|
+
try {
|
|
148
|
+
const orientation = await getOrientation(value);
|
|
149
|
+
const dataURI = URL.createObjectURL(value);
|
|
150
|
+
localPreview = {
|
|
151
|
+
dataURI,
|
|
152
|
+
orientation,
|
|
153
|
+
source: 'local'
|
|
154
|
+
};
|
|
155
|
+
} catch (e) {
|
|
156
|
+
throw new LocalPreviewError('local-preview-image', e instanceof Error ? e : undefined);
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
case 'video':
|
|
160
|
+
try {
|
|
161
|
+
const dataURI = await takeSnapshot(value);
|
|
162
|
+
localPreview = {
|
|
163
|
+
dataURI,
|
|
164
|
+
orientation: 1,
|
|
165
|
+
source: 'local'
|
|
166
|
+
};
|
|
167
|
+
} catch (e) {
|
|
168
|
+
throw new LocalPreviewError('local-preview-video', e instanceof Error ? e : undefined);
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
throw new LocalPreviewError('local-preview-unsupported');
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
throw new LocalPreviewError('local-preview-unsupported');
|
|
176
|
+
}
|
|
177
|
+
const preview = {
|
|
178
|
+
...localPreview,
|
|
179
|
+
dimensions
|
|
180
|
+
};
|
|
181
|
+
let source;
|
|
182
|
+
switch (preview.source) {
|
|
183
|
+
case 'local':
|
|
184
|
+
source = 'cache-local';
|
|
185
|
+
break;
|
|
186
|
+
case 'remote':
|
|
187
|
+
source = 'cache-remote';
|
|
188
|
+
break;
|
|
189
|
+
case 'ssr-server':
|
|
190
|
+
source = 'cache-ssr-server';
|
|
191
|
+
break;
|
|
192
|
+
case 'ssr-client':
|
|
193
|
+
source = 'cache-ssr-client';
|
|
194
|
+
break;
|
|
195
|
+
default:
|
|
196
|
+
source = preview.source;
|
|
197
|
+
}
|
|
198
|
+
// We want to embed some meta context into dataURI for Copy/Paste to work.
|
|
199
|
+
const dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(preview.dataURI, mediaBlobUrlAttrs) : preview.dataURI;
|
|
200
|
+
// We store new cardPreview into cache
|
|
201
|
+
cardPreviewCache.set(identifier.id, mode, {
|
|
202
|
+
...preview,
|
|
203
|
+
source,
|
|
204
|
+
dataURI
|
|
205
|
+
});
|
|
206
|
+
setCardPreview({
|
|
207
|
+
...preview,
|
|
208
|
+
dataURI
|
|
209
|
+
});
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
} catch (e) {
|
|
213
|
+
/**
|
|
214
|
+
* We report the error if:
|
|
215
|
+
* - local preview is supported and fails
|
|
216
|
+
* - local preview is unsupported and remote preview is NOT READY
|
|
217
|
+
* i.e. the function was called for "no reason".
|
|
218
|
+
* We DON'T report the error if:
|
|
219
|
+
* - local preview is unsupported and remote preview IS READY
|
|
220
|
+
* i.e. local preview is available and not supported,
|
|
221
|
+
* but we are after the remote preview instead.
|
|
222
|
+
*/
|
|
223
|
+
if (!isUnsupportedLocalPreviewError(e) || isUnsupportedLocalPreviewError(e) && !isRemotePreviewReady) {
|
|
224
|
+
// CXP-2723 TODO: We might have to wrap this error in MediaCardError
|
|
225
|
+
setNonCriticalError(e);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* No matter the reason why the local preview failed, we break the process
|
|
229
|
+
* if there is no remote preview available
|
|
230
|
+
*/
|
|
231
|
+
if (!isRemotePreviewReady) {
|
|
232
|
+
throw e;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (!isRemotePreviewReady) {
|
|
236
|
+
/**
|
|
237
|
+
* We throw this in case this function has been called
|
|
238
|
+
* without checking isRemotePreviewReady first.
|
|
239
|
+
* If remote preview is not ready, the call to getCardPreviewFromBackend
|
|
240
|
+
* will generate a console error due to a 404 code
|
|
241
|
+
*/
|
|
242
|
+
throw new MediaCardError('remote-preview-not-ready');
|
|
243
|
+
}
|
|
244
|
+
const remotePreview = await fetchAndCacheRemotePreview(mediaClient, identifier.id, dimensions !== null && dimensions !== void 0 ? dimensions : {}, imageURLParams, mediaBlobUrlAttrs, traceContext);
|
|
245
|
+
setCardPreview(remotePreview);
|
|
246
|
+
return;
|
|
247
|
+
} catch (e) {
|
|
248
|
+
const wrappedError = ensureMediaCardError('preview-fetch', e);
|
|
249
|
+
// If remote preview fails, we set status 'error'
|
|
250
|
+
// If local preview fails (i.e, no remote preview available),
|
|
251
|
+
// we can stay in the same status until there is a remote preview available
|
|
252
|
+
// If it's any other error we set status 'error'
|
|
253
|
+
if (isLocalPreviewError(wrappedError)) {
|
|
254
|
+
// This error should already been logged inside the getCardPreview. No need to log it here.
|
|
255
|
+
setIsBannedLocalPreview(true);
|
|
256
|
+
} else {
|
|
257
|
+
if (!['complete', 'error', 'failed-processing'].includes(status)) {
|
|
258
|
+
setStatus('error');
|
|
259
|
+
setError(wrappedError);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
//----------------------------------------------------------------//
|
|
266
|
+
//------------ resolveUpfrontPreview useEffect -------------------//
|
|
267
|
+
//----------------------------------------------------------------//
|
|
268
|
+
const prevCardPreview = usePrevious(cardPreview);
|
|
269
|
+
const dimensionsRef = useCurrentValueRef(dimensions);
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
const resolveUpfrontPreview = async identifier => {
|
|
272
|
+
// We block any possible future call to this method regardless of the outcome (success or fail)
|
|
273
|
+
// If it fails, the normal preview fetch should occur after the file state is fetched anyways
|
|
274
|
+
wasResolvedUpfrontPreviewRef.current = true;
|
|
275
|
+
try {
|
|
276
|
+
const fetchedDimensions = {
|
|
277
|
+
...dimensions
|
|
278
|
+
};
|
|
279
|
+
const newCardPreview = await fetchRemotePreviewRef.current(identifier);
|
|
280
|
+
const areValidFetchedDimensions = !isBigger(fetchedDimensions, dimensionsRef.current);
|
|
281
|
+
|
|
282
|
+
// If there are new and bigger dimensions in the props, and the upfront preview is still resolving,
|
|
283
|
+
// the fetched preview is no longer valid, and thus, we dismiss it
|
|
284
|
+
if (areValidFetchedDimensions) {
|
|
285
|
+
setCardPreview(newCardPreview);
|
|
286
|
+
}
|
|
287
|
+
} catch (e) {
|
|
288
|
+
// NO need to log error. If this call fails, a refetch will happen after
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const hadSSRCardPreview = ssr === 'client' && !!prevCardPreview && isSSRClientPreview(prevCardPreview);
|
|
292
|
+
|
|
293
|
+
// CXP-2723 TODO: `hadSSRCardPreview` is most likely redundant
|
|
294
|
+
if (!wasResolvedUpfrontPreviewRef.current && (!skipRemote || hadSSRCardPreview) && !cardPreview) {
|
|
295
|
+
resolveUpfrontPreview(identifier);
|
|
296
|
+
}
|
|
297
|
+
}, [cardPreview, dimensions, dimensionsRef, fetchRemotePreviewRef, identifier, skipRemote, prevCardPreview, ssr]);
|
|
298
|
+
|
|
299
|
+
//----------------------------------------------------------------//
|
|
300
|
+
//---------------- fetch and resolve card preview ----------------//
|
|
301
|
+
//----------------------------------------------------------------//
|
|
302
|
+
|
|
303
|
+
const prevDimensions = usePrevious(dimensions);
|
|
304
|
+
useEffect(() => {
|
|
305
|
+
var _ssrDataRef$current3;
|
|
306
|
+
if (cardPreview && !skipRemote && isSSRDataPreview(cardPreview) && isBigger((_ssrDataRef$current3 = ssrDataRef.current) === null || _ssrDataRef$current3 === void 0 ? void 0 : _ssrDataRef$current3.dimensions, dimensions)) {
|
|
307
|
+
// refetchSRRPreview: If dimensions from Server have changed and are bigger,
|
|
308
|
+
// we need to refetch
|
|
309
|
+
fetchRemotePreviewRef.current(identifier).then(setCardPreview).catch(e => {
|
|
310
|
+
const wrappedError = ensureMediaCardError('remote-preview-fetch-ssr', e, true);
|
|
311
|
+
setNonCriticalError(wrappedError);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
// CXP-2723 TODO: The above and below preview fetch logic seem very similar and could be revisted
|
|
315
|
+
// Both compare dimensions, but the above is only for SSR in order to refetchSRRPreview and
|
|
316
|
+
// will swallow any errors. Below logic only applies when there is no card preview or the dimensions
|
|
317
|
+
// are bigger.
|
|
318
|
+
if (fileState && shouldResolvePreview({
|
|
319
|
+
status,
|
|
320
|
+
fileState: fileState,
|
|
321
|
+
prevDimensions,
|
|
322
|
+
dimensions,
|
|
323
|
+
hasCardPreview: !!cardPreview,
|
|
324
|
+
isBannedLocalPreview,
|
|
325
|
+
wasResolvedUpfrontPreview: wasResolvedUpfrontPreviewRef.current
|
|
326
|
+
})) {
|
|
327
|
+
resolvePreviewRef.current(identifier, fileState);
|
|
328
|
+
}
|
|
329
|
+
if (!skipRemote && ssr && !!cardPreview && isSSRClientPreview(cardPreview)) {
|
|
330
|
+
// Since the SSR preview brings the token in the query params,
|
|
331
|
+
// We need to fetch the remote preview to be able to cache it,
|
|
332
|
+
fetchRemotePreviewRef.current(identifier).catch(() => {
|
|
333
|
+
// No need to log this error.
|
|
334
|
+
// If preview fails, it will be refetched later
|
|
335
|
+
//TODO: test this catch
|
|
336
|
+
// https://product-fabric.atlassian.net/browse/MEX-1071
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}, [cardPreview, dimensions, fetchRemotePreviewRef, fileState, identifier, isBannedLocalPreview, prevDimensions, resolvePreviewRef, skipRemote, ssr, status]);
|
|
340
|
+
|
|
341
|
+
//----------------------------------------------------------------//
|
|
342
|
+
//----------------- set complete status --------------------------//
|
|
343
|
+
//----------------------------------------------------------------//
|
|
344
|
+
|
|
345
|
+
useEffect(() => {
|
|
346
|
+
if (previewDidRender &&
|
|
347
|
+
// We should't complete if status is uploading
|
|
348
|
+
['loading-preview', 'processing'].includes(status)) {
|
|
349
|
+
setStatus('complete');
|
|
350
|
+
// TODO MEX-788: add test for "do not remove the card preview when unsubscribing".
|
|
351
|
+
setIsBannedLocalPreview(false); // CXP-2723 TODO: we might be able to remove this??
|
|
352
|
+
}
|
|
353
|
+
}, [previewDidRender, status]);
|
|
354
|
+
|
|
355
|
+
// CXP-2723 TODO: Create test cases for banning local preview after status is complete
|
|
356
|
+
|
|
357
|
+
//----------------------------------------------------------------//
|
|
358
|
+
//------------------ Subscribe to file state ---------------------//
|
|
359
|
+
//----------------------------------------------------------------//
|
|
360
|
+
|
|
361
|
+
const updateFileStateRef = useCurrentValueRef(() => {
|
|
362
|
+
if (fileState) {
|
|
363
|
+
// do not update the card status if the status is final
|
|
364
|
+
if (['complete', 'error', 'failed-processing'].includes(status)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (fileState.status !== 'error') {
|
|
368
|
+
const mediaType = 'mediaType' in fileState ? fileState.mediaType : undefined;
|
|
369
|
+
const isPreviewable = !!mediaType && ['audio', 'video', 'image', 'doc'].indexOf(mediaType) > -1;
|
|
370
|
+
const isPreviewableFileState = !!fileState.preview;
|
|
371
|
+
const isSupportedLocalPreview = mediaType === 'image' || mediaType === 'video';
|
|
372
|
+
const hasLocalPreview = !isBannedLocalPreview && isPreviewableFileState && isSupportedLocalPreview && !!fileState.mimeType && isMimeTypeSupportedByBrowser(fileState.mimeType);
|
|
373
|
+
const hasRemotePreview = isImageRepresentationReady(fileState);
|
|
374
|
+
const hasPreview = hasLocalPreview || hasRemotePreview;
|
|
375
|
+
let newStatus;
|
|
376
|
+
switch (fileState.status) {
|
|
377
|
+
case 'uploading':
|
|
378
|
+
case 'failed-processing':
|
|
379
|
+
case 'processing':
|
|
380
|
+
newStatus = fileState.status;
|
|
381
|
+
break;
|
|
382
|
+
case 'processed':
|
|
383
|
+
if (!isPreviewable || !hasPreview) {
|
|
384
|
+
newStatus = 'complete';
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
newStatus = 'loading-preview';
|
|
388
|
+
break;
|
|
389
|
+
default:
|
|
390
|
+
newStatus = 'loading';
|
|
391
|
+
}
|
|
392
|
+
setStatus(newStatus);
|
|
393
|
+
} else {
|
|
394
|
+
const e = new MediaFileStateError(fileState.id, fileState.reason, fileState.message, fileState.details);
|
|
395
|
+
const errorReason = status === 'uploading' ? 'upload' : 'metadata-fetch';
|
|
396
|
+
setError(new MediaCardError(errorReason, e));
|
|
397
|
+
setStatus('error');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
useEffect(() => {
|
|
402
|
+
updateFileStateRef.current();
|
|
403
|
+
}, [fileState, updateFileStateRef]);
|
|
404
|
+
const onImageError = newCardPreview => {
|
|
405
|
+
if (newCardPreview) {
|
|
406
|
+
const failedSSRObject = {
|
|
407
|
+
status: 'fail',
|
|
408
|
+
...extractErrorInfo(new ImageLoadError(newCardPreview.source))
|
|
409
|
+
};
|
|
410
|
+
if (isSSRClientPreview(newCardPreview)) {
|
|
411
|
+
ssrReliabilityRef.current.client = failedSSRObject;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/*
|
|
415
|
+
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.
|
|
416
|
+
*/
|
|
417
|
+
|
|
418
|
+
if (isSSRDataPreview(newCardPreview)) {
|
|
419
|
+
ssrReliabilityRef.current.server = failedSSRObject;
|
|
420
|
+
ssrReliabilityRef.current.client = failedSSRObject;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// If the dataURI has been replaced, we can dismiss this error
|
|
425
|
+
if ((newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.dataURI) !== (cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI)) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const error = new ImageLoadError(newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.source);
|
|
429
|
+
const isLocal = newCardPreview && isLocalPreview(newCardPreview);
|
|
430
|
+
const isSSR = newCardPreview && (isSSRClientPreview(newCardPreview) || isSSRDataPreview(newCardPreview));
|
|
431
|
+
if (isLocal || isSSR) {
|
|
432
|
+
if (isLocal) {
|
|
433
|
+
setIsBannedLocalPreview(true);
|
|
434
|
+
setNonCriticalError(error);
|
|
435
|
+
}
|
|
436
|
+
const fileImageMode = imageResizeModeToFileImageMode(resizeMode);
|
|
437
|
+
removeCardPreviewFromCache(identifier.id, fileImageMode);
|
|
438
|
+
setCardPreview(undefined);
|
|
439
|
+
} else {
|
|
440
|
+
if (!['complete', 'error', 'failed-processing'].includes(status)) {
|
|
441
|
+
setStatus('error');
|
|
442
|
+
setError(error);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
const onImageLoad = newCardPreview => {
|
|
447
|
+
if (newCardPreview) {
|
|
448
|
+
if (isSSRClientPreview(newCardPreview) && ssrReliabilityRef.current.client.status === 'unknown') {
|
|
449
|
+
ssrReliabilityRef.current.client = {
|
|
450
|
+
status: 'success'
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/*
|
|
455
|
+
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.
|
|
456
|
+
*/
|
|
457
|
+
|
|
458
|
+
if (isSSRDataPreview(newCardPreview) && ssrReliabilityRef.current.server.status === 'unknown') {
|
|
459
|
+
ssrReliabilityRef.current.server = {
|
|
460
|
+
status: 'success'
|
|
461
|
+
};
|
|
462
|
+
ssrReliabilityRef.current.client = {
|
|
463
|
+
status: 'success'
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// If the dataURI has been replaced, we can dismiss this callback
|
|
469
|
+
if ((newCardPreview === null || newCardPreview === void 0 ? void 0 : newCardPreview.dataURI) !== (cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI)) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
//----------------------------------------------------------------//
|
|
475
|
+
// RETURN
|
|
476
|
+
//----------------------------------------------------------------//
|
|
477
|
+
|
|
478
|
+
const StoreSSRDataScriptComponent = () => {
|
|
479
|
+
var _ssrReliabilityRef$cu;
|
|
480
|
+
return /*#__PURE__*/React.createElement(StoreSSRDataScript, {
|
|
481
|
+
identifier: identifier,
|
|
482
|
+
dataURI: cardPreview === null || cardPreview === void 0 ? void 0 : cardPreview.dataURI,
|
|
483
|
+
dimensions: requestedDimensions,
|
|
484
|
+
error: ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined
|
|
485
|
+
});
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// CXP-2723 TODO: should consider simplifying our analytics, and how
|
|
489
|
+
// we might get rid of ssrReliabiltyRef from our hook
|
|
490
|
+
return {
|
|
491
|
+
cardPreview,
|
|
492
|
+
error,
|
|
493
|
+
nonCriticalError,
|
|
494
|
+
ssrReliabilityRef,
|
|
495
|
+
onImageError,
|
|
496
|
+
onImageLoad,
|
|
497
|
+
StoreSSRDataScript: StoreSSRDataScriptComponent
|
|
498
|
+
};
|
|
499
|
+
};
|
|
@@ -37,7 +37,7 @@ export default class MediaInlineCardLoader extends React.PureComponent {
|
|
|
37
37
|
} = this.state;
|
|
38
38
|
const analyticsContext = {
|
|
39
39
|
packageVersion: "@atlaskit/media-card",
|
|
40
|
-
packageName: "77.4.
|
|
40
|
+
packageName: "77.4.6",
|
|
41
41
|
componentName: 'mediaInlineCard',
|
|
42
42
|
component: 'mediaInlineCard'
|
|
43
43
|
};
|
|
@@ -4,7 +4,7 @@ import { extractErrorInfo, getRenderErrorRequestMetadata } from './analytics';
|
|
|
4
4
|
import { MediaCardError } from '../errors';
|
|
5
5
|
import { getMediaEnvironment, getMediaRegion } from '@atlaskit/media-client';
|
|
6
6
|
const packageName = "@atlaskit/media-card";
|
|
7
|
-
const packageVersion = "77.4.
|
|
7
|
+
const packageVersion = "77.4.6";
|
|
8
8
|
let concurrentExperience;
|
|
9
9
|
const getExperience = id => {
|
|
10
10
|
if (!concurrentExperience) {
|