@atlaskit/media-viewer 49.2.7 → 49.4.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/cjs/analytics/events/operational/download.js +59 -0
  3. package/dist/cjs/analytics/index.js +1 -1
  4. package/dist/cjs/analytics/ufoExperiences.js +1 -1
  5. package/dist/cjs/components/media-viewer.js +4 -2
  6. package/dist/cjs/download.js +60 -27
  7. package/dist/cjs/header.js +4 -2
  8. package/dist/cjs/item-viewer.js +32 -17
  9. package/dist/cjs/list.js +11 -3
  10. package/dist/cjs/media-viewer.js +4 -2
  11. package/dist/cjs/viewerOptions.js +5 -0
  12. package/dist/cjs/viewers/archiveSidebar/archive.js +52 -8
  13. package/dist/cjs/viewers/base-viewer.js +4 -2
  14. package/dist/cjs/viewers/customViewer/customViewer.js +55 -0
  15. package/dist/es2019/analytics/events/operational/download.js +55 -0
  16. package/dist/es2019/analytics/index.js +1 -1
  17. package/dist/es2019/analytics/ufoExperiences.js +1 -1
  18. package/dist/es2019/components/media-viewer.js +4 -2
  19. package/dist/es2019/download.js +53 -24
  20. package/dist/es2019/header.js +4 -2
  21. package/dist/es2019/item-viewer.js +30 -17
  22. package/dist/es2019/list.js +12 -4
  23. package/dist/es2019/media-viewer.js +4 -2
  24. package/dist/es2019/viewerOptions.js +1 -0
  25. package/dist/es2019/viewers/archiveSidebar/archive.js +27 -5
  26. package/dist/es2019/viewers/base-viewer.js +4 -2
  27. package/dist/es2019/viewers/customViewer/customViewer.js +37 -0
  28. package/dist/esm/analytics/events/operational/download.js +53 -0
  29. package/dist/esm/analytics/index.js +1 -1
  30. package/dist/esm/analytics/ufoExperiences.js +1 -1
  31. package/dist/esm/components/media-viewer.js +4 -2
  32. package/dist/esm/download.js +60 -25
  33. package/dist/esm/header.js +4 -2
  34. package/dist/esm/item-viewer.js +32 -17
  35. package/dist/esm/list.js +12 -4
  36. package/dist/esm/media-viewer.js +4 -2
  37. package/dist/esm/viewerOptions.js +1 -0
  38. package/dist/esm/viewers/archiveSidebar/archive.js +52 -8
  39. package/dist/esm/viewers/base-viewer.js +4 -2
  40. package/dist/esm/viewers/customViewer/customViewer.js +46 -0
  41. package/dist/types/analytics/events/index.d.ts +2 -1
  42. package/dist/types/analytics/events/operational/_mediaFile.d.ts +1 -1
  43. package/dist/types/analytics/events/operational/download.d.ts +9 -0
  44. package/dist/types/components/media-viewer.d.ts +1 -1
  45. package/dist/types/components/types.d.ts +2 -0
  46. package/dist/types/download.d.ts +7 -11
  47. package/dist/types/errors.d.ts +2 -2
  48. package/dist/types/header.d.ts +3 -2
  49. package/dist/types/index.d.ts +1 -0
  50. package/dist/types/item-viewer.d.ts +7 -2
  51. package/dist/types/list.d.ts +3 -1
  52. package/dist/types/media-viewer.d.ts +2 -0
  53. package/dist/types/viewerOptions.d.ts +21 -0
  54. package/dist/types/viewers/archiveSidebar/types.d.ts +4 -0
  55. package/dist/types/viewers/audio.d.ts +2 -0
  56. package/dist/types/viewers/base-viewer.d.ts +2 -0
  57. package/dist/types/viewers/codeViewer/index.d.ts +2 -0
  58. package/dist/types/viewers/customViewer/customViewer.d.ts +12 -0
  59. package/dist/types/viewers/doc/index.d.ts +2 -0
  60. package/dist/types/viewers/image/index.d.ts +1 -1
  61. package/dist/types/viewers/video.d.ts +2 -0
  62. package/dist/types-ts4.5/analytics/events/index.d.ts +2 -1
  63. package/dist/types-ts4.5/analytics/events/operational/_mediaFile.d.ts +1 -1
  64. package/dist/types-ts4.5/analytics/events/operational/download.d.ts +9 -0
  65. package/dist/types-ts4.5/components/media-viewer.d.ts +1 -1
  66. package/dist/types-ts4.5/components/types.d.ts +2 -0
  67. package/dist/types-ts4.5/download.d.ts +7 -11
  68. package/dist/types-ts4.5/errors.d.ts +2 -2
  69. package/dist/types-ts4.5/header.d.ts +3 -2
  70. package/dist/types-ts4.5/index.d.ts +1 -0
  71. package/dist/types-ts4.5/item-viewer.d.ts +7 -2
  72. package/dist/types-ts4.5/list.d.ts +3 -1
  73. package/dist/types-ts4.5/media-viewer.d.ts +2 -0
  74. package/dist/types-ts4.5/viewerOptions.d.ts +21 -0
  75. package/dist/types-ts4.5/viewers/archiveSidebar/types.d.ts +4 -0
  76. package/dist/types-ts4.5/viewers/audio.d.ts +2 -0
  77. package/dist/types-ts4.5/viewers/base-viewer.d.ts +2 -0
  78. package/dist/types-ts4.5/viewers/codeViewer/index.d.ts +2 -0
  79. package/dist/types-ts4.5/viewers/customViewer/customViewer.d.ts +12 -0
  80. package/dist/types-ts4.5/viewers/doc/index.d.ts +2 -0
  81. package/dist/types-ts4.5/viewers/image/index.d.ts +1 -1
  82. package/dist/types-ts4.5/viewers/video.d.ts +2 -0
  83. package/package.json +6 -6
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _typeof = require("@babel/runtime/helpers/typeof");
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.CustomViewer = void 0;
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _errors = require("../../errors");
11
+ var _react = _interopRequireWildcard(require("react"));
12
+ var _loading = require("../../loading");
13
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
14
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
15
+ var CustomViewer = exports.CustomViewer = function CustomViewer(_ref) {
16
+ var mediaClient = _ref.mediaClient,
17
+ item = _ref.item,
18
+ customRendererConfig = _ref.customRendererConfig,
19
+ onSuccess = _ref.onSuccess,
20
+ onError = _ref.onError;
21
+ var _useState = (0, _react.useState)(),
22
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
23
+ getBinaryContent = _useState2[0],
24
+ setGetBinaryContent = _useState2[1];
25
+ (0, _react.useEffect)(function () {
26
+ setGetBinaryContent(undefined);
27
+ var abortController = new AbortController();
28
+ // This sets the 'getBinaryContent' to an async function that fetches the binary content of the file
29
+ // The 'getBinaryContent' function has to be updated when the item changes
30
+ // This approach handles aborting in-progress request outside of the custom-renderer concern
31
+ if (item.status === 'processed' || item.status === 'failed-processing') {
32
+ setGetBinaryContent(function () {
33
+ return function () {
34
+ return mediaClient.mediaStore.getFileBinary(item.id, undefined, abortController);
35
+ };
36
+ });
37
+ }
38
+ return function () {
39
+ return abortController.abort();
40
+ };
41
+ }, [item, mediaClient]);
42
+ var onLoadFailed = (0, _react.useCallback)(function (error) {
43
+ var mediaError = new _errors.MediaViewerError('custom-viewer-error', error);
44
+ onError(mediaError, item);
45
+ }, [item, onError]);
46
+ if (!getBinaryContent) {
47
+ return /*#__PURE__*/_react.default.createElement(_loading.Spinner, null);
48
+ }
49
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, customRendererConfig.renderContent({
50
+ fileItem: item,
51
+ getBinaryContent: getBinaryContent,
52
+ onLoad: onSuccess,
53
+ onError: onLoadFailed
54
+ }));
55
+ };
@@ -0,0 +1,55 @@
1
+ import { getFileAttributes } from '../..';
2
+ import { getPrimaryErrorReason, getSecondaryErrorReason, getErrorDetail, getRequestMetadata } from '../../../errors';
3
+ export const createDownloadSucceededEventPayload = (fileState, traceContext) => {
4
+ const {
5
+ fileId,
6
+ fileMediatype,
7
+ fileMimetype,
8
+ fileSize
9
+ } = getFileAttributes(fileState);
10
+ return {
11
+ eventType: 'operational',
12
+ actionSubject: 'mediaFile',
13
+ action: 'downloadSucceeded',
14
+ attributes: {
15
+ status: 'success',
16
+ fileMediatype,
17
+ fileMimetype,
18
+ fileAttributes: {
19
+ fileId,
20
+ fileMediatype,
21
+ fileMimetype,
22
+ fileSize
23
+ },
24
+ traceContext
25
+ }
26
+ };
27
+ };
28
+ export const createDownloadFailedEventPayload = (fileId, error, fileState, traceContext) => {
29
+ const {
30
+ fileMediatype,
31
+ fileMimetype,
32
+ fileSize
33
+ } = getFileAttributes(fileState);
34
+ return {
35
+ eventType: 'operational',
36
+ actionSubject: 'mediaFile',
37
+ action: 'downloadFailed',
38
+ attributes: {
39
+ status: 'fail',
40
+ failReason: getPrimaryErrorReason(error),
41
+ error: getSecondaryErrorReason(error),
42
+ errorDetail: getErrorDetail(error),
43
+ request: getRequestMetadata(error),
44
+ fileMimetype,
45
+ fileMediatype,
46
+ fileAttributes: {
47
+ fileId,
48
+ fileMediatype,
49
+ fileMimetype,
50
+ fileSize
51
+ },
52
+ traceContext
53
+ }
54
+ };
55
+ };
@@ -1,7 +1,7 @@
1
1
  import { ANALYTICS_MEDIA_CHANNEL, sanitiseAnalyticsPayload } from '@atlaskit/media-common/analytics';
2
2
  const componentName = 'mediaViewer';
3
3
  const packageName = "@atlaskit/media-viewer";
4
- const packageVersion = "49.2.7";
4
+ const packageVersion = "49.4.0";
5
5
  export { packageName, packageVersion, componentName, componentName as component };
6
6
  export function getFileAttributes(fileState) {
7
7
  if (!fileState) {
@@ -2,7 +2,7 @@ import { UFOExperience, ExperiencePerformanceTypes, ExperienceTypes } from '@atl
2
2
  import { getMediaEnvironment, getMediaRegion } from '@atlaskit/media-client';
3
3
  import { getFeatureFlagKeysAllProducts } from '@atlaskit/media-common';
4
4
  const packageName = "@atlaskit/media-viewer";
5
- const packageVersion = "49.2.7";
5
+ const packageVersion = "49.4.0";
6
6
  let ufoExperience;
7
7
  const getExperience = () => {
8
8
  if (!ufoExperience) {
@@ -32,7 +32,8 @@ export const MediaViewerBase = ({
32
32
  collectionName,
33
33
  items,
34
34
  extensions,
35
- contextId
35
+ contextId,
36
+ viewerOptions
36
37
  }) => {
37
38
  const {
38
39
  items: normalisedItems,
@@ -65,7 +66,8 @@ export const MediaViewerBase = ({
65
66
  items: normalisedItems,
66
67
  featureFlags: featureFlags,
67
68
  extensions: extensions,
68
- contextId: contextId
69
+ contextId: contextId,
70
+ viewerOptions: viewerOptions
69
71
  });
70
72
  };
71
73
 
@@ -1,60 +1,85 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
+ import { useAnalyticsEvents } from '@atlaskit/analytics-next';
2
3
  import DownloadIcon from '@atlaskit/icon/core/migration/download';
3
4
  import { isErrorFileState, isExternalImageIdentifier } from '@atlaskit/media-client';
4
5
  import { MediaButton, messages } from '@atlaskit/media-ui';
5
6
  import React, { useCallback } from 'react';
6
7
  import { FormattedMessage } from 'react-intl-next';
7
- import { ANALYTICS_MEDIA_CHANNEL } from '@atlaskit/media-common';
8
8
  import { createDownloadButtonClickedEvent } from './analytics/events/ui/downloadButtonClicked';
9
+ import { createDownloadFailedEventPayload, createDownloadSucceededEventPayload } from './analytics/events/operational/download';
10
+ import { fireAnalytics } from './analytics';
9
11
  import { createFailedPreviewDownloadButtonClickedEvent } from './analytics/events/ui/failedPreviewDownloadButtonClicked';
10
12
  import { DownloadButtonWrapper } from './styleWrappers';
13
+ import { MediaViewerError } from './errors';
11
14
  const downloadIcon = /*#__PURE__*/React.createElement(DownloadIcon, {
12
15
  color: "currentColor",
13
16
  spacing: "spacious",
14
17
  label: "Download"
15
18
  });
16
19
  function noop() {}
17
- export function DownloadButton({
20
+ function DownloadButton({
18
21
  analyticspayload,
19
22
  onClick: providedOnClick = noop,
20
23
  ...rest
21
24
  }) {
25
+ const {
26
+ createAnalyticsEvent
27
+ } = useAnalyticsEvents();
22
28
  const onClick = useCallback((event, analyticsEvent) => {
23
- const clone = analyticsEvent.clone();
24
- if (clone) {
25
- clone.update(analyticspayload);
26
- clone.fire(ANALYTICS_MEDIA_CHANNEL);
27
- }
29
+ fireAnalytics(analyticspayload, createAnalyticsEvent);
28
30
  providedOnClick(event, analyticsEvent);
29
- }, [analyticspayload, providedOnClick]);
31
+ }, [analyticspayload, providedOnClick, createAnalyticsEvent]);
30
32
  return /*#__PURE__*/React.createElement(MediaButton, _extends({}, rest, {
31
33
  onClick: onClick
32
34
  }));
33
35
  }
34
- export const createItemDownloader = (file, mediaClient, collectionName) => () => {
36
+ const createItemDownloader = (file, mediaClient, options) => async () => {
37
+ const {
38
+ collectionName,
39
+ traceContext,
40
+ createAnalyticsEvent
41
+ } = options;
35
42
  const id = file.id;
36
43
  const name = !isErrorFileState(file) ? file.name : undefined;
37
- return mediaClient.file.downloadBinary(id, name, collectionName);
44
+ mediaClient.file.downloadBinary(id, name, collectionName, traceContext).then(() => {
45
+ fireAnalytics(createDownloadSucceededEventPayload(file, traceContext), createAnalyticsEvent);
46
+ }).catch(e => {
47
+ fireAnalytics(createDownloadFailedEventPayload(file.id, new MediaViewerError('download', e), file, traceContext), createAnalyticsEvent);
48
+ });
38
49
  };
39
- export const ErrorViewDownloadButton = props => {
40
- const {
41
- fileState,
42
- error
43
- } = props;
50
+ export const ErrorViewDownloadButton = ({
51
+ fileState,
52
+ mediaClient,
53
+ error,
54
+ traceContext,
55
+ collectionName
56
+ }) => {
44
57
  const downloadEvent = createFailedPreviewDownloadButtonClickedEvent(fileState, error);
45
- return /*#__PURE__*/React.createElement(DownloadButtonWrapper, null, /*#__PURE__*/React.createElement(DownloadButton, {
46
- testId: "media-viewer-download-button",
58
+ const {
59
+ createAnalyticsEvent
60
+ } = useAnalyticsEvents();
61
+ return /*#__PURE__*/React.createElement(DownloadButtonWrapper, null, /*#__PURE__*/React.createElement(DownloadButton
62
+ // testId="media-viewer-failed-preview-download-button"
63
+ , {
64
+ testId: "media-viewer-error-download-button",
47
65
  analyticspayload: downloadEvent,
48
66
  appearance: "primary",
49
- onClick: createItemDownloader(props.fileState, props.mediaClient, props.collectionName)
67
+ onClick: createItemDownloader(fileState, mediaClient, {
68
+ collectionName,
69
+ traceContext,
70
+ createAnalyticsEvent
71
+ })
50
72
  }, /*#__PURE__*/React.createElement(FormattedMessage, messages.download)));
51
73
  };
52
- export const ToolbarDownloadButton = props => {
74
+ export const ToolbarDownloadButton = ({
75
+ state,
76
+ mediaClient,
77
+ identifier,
78
+ traceContext
79
+ }) => {
53
80
  const {
54
- state,
55
- mediaClient,
56
- identifier
57
- } = props;
81
+ createAnalyticsEvent
82
+ } = useAnalyticsEvents();
58
83
  const downloadEvent = createDownloadButtonClickedEvent(state);
59
84
 
60
85
  // TODO [MS-1731]: make it work for external files as well
@@ -64,7 +89,11 @@ export const ToolbarDownloadButton = props => {
64
89
  return /*#__PURE__*/React.createElement(DownloadButton, {
65
90
  testId: "media-viewer-download-button",
66
91
  analyticspayload: downloadEvent,
67
- onClick: createItemDownloader(state, mediaClient, identifier.collectionName),
92
+ onClick: createItemDownloader(state, mediaClient, {
93
+ collectionName: identifier.collectionName,
94
+ createAnalyticsEvent,
95
+ traceContext
96
+ }),
68
97
  iconBefore: downloadIcon
69
98
  });
70
99
  };
@@ -16,7 +16,8 @@ export const Header = ({
16
16
  isSidebarVisible,
17
17
  onSidebarButtonClick,
18
18
  identifier,
19
- onSetArchiveSideBarVisible
19
+ onSetArchiveSideBarVisible,
20
+ traceContext
20
21
  }) => {
21
22
  // States
22
23
  const [item, setItem] = useState(Outcome.pending());
@@ -133,7 +134,8 @@ export const Header = ({
133
134
  successful: item => /*#__PURE__*/React.createElement(ToolbarDownloadButton, {
134
135
  state: item,
135
136
  identifier: identifier,
136
- mediaClient: mediaClient
137
+ mediaClient: mediaClient,
138
+ traceContext: traceContext
137
139
  })
138
140
  })));
139
141
  };
@@ -2,6 +2,7 @@ import _extends from "@babel/runtime/helpers/extends";
2
2
  import React, { useCallback, useEffect, useState, useRef } from 'react';
3
3
  import Loadable from 'react-loadable';
4
4
  import { isExternalImageIdentifier, isFileIdentifier } from '@atlaskit/media-client';
5
+ import { Text } from '@atlaskit/primitives';
5
6
  import { FormattedMessage } from 'react-intl-next';
6
7
  import { messages } from '@atlaskit/media-ui';
7
8
  import { isCodeViewerItem } from '@atlaskit/media-ui/codeViewer';
@@ -17,8 +18,8 @@ import { createLoadSucceededEvent } from './analytics/events/operational/loadSuc
17
18
  import { fireAnalytics, getFileAttributes } from './analytics';
18
19
  import { InteractiveImg } from './viewers/image/interactive-img';
19
20
  import ArchiveViewerLoader from './viewers/archiveSidebar/archiveViewerLoader';
20
- import { getRandomHex } from '@atlaskit/media-common';
21
21
  import { startMediaFileUfoExperience, succeedMediaFileUfoExperience } from './analytics/ufoExperiences';
22
+ import { CustomViewer } from './viewers/customViewer/customViewer';
22
23
  const ImageViewer = Loadable({
23
24
  loader: () => import( /* webpackChunkName: "@atlaskit-internal_imageViewer" */'./viewers/image').then(mod => mod.ImageViewer),
24
25
  loading: () => /*#__PURE__*/React.createElement(Spinner, null)
@@ -55,13 +56,12 @@ export const ItemViewerBase = ({
55
56
  onClose,
56
57
  previewCount,
57
58
  contextId,
58
- createAnalyticsEvent
59
+ createAnalyticsEvent,
60
+ viewerOptions,
61
+ traceContext
59
62
  }) => {
60
63
  // States and Refs
61
64
  const [item, setItem] = useState(Outcome.pending());
62
- const traceContext = useRef({
63
- traceId: getRandomHex(8)
64
- });
65
65
  const fileStateFlagsRef = useRef({
66
66
  wasStatusUploading: false,
67
67
  wasStatusProcessing: false
@@ -83,9 +83,10 @@ export const ItemViewerBase = ({
83
83
  fileState: fileState,
84
84
  mediaClient: mediaClient,
85
85
  error: error,
86
- collectionName: collectionName
86
+ collectionName: collectionName,
87
+ traceContext: traceContext
87
88
  });
88
- }, [mediaClient, identifier]);
89
+ }, [mediaClient, identifier, traceContext]);
89
90
 
90
91
  // Did mount
91
92
 
@@ -93,9 +94,9 @@ export const ItemViewerBase = ({
93
94
  if (isExternalImageIdentifier(identifier)) {
94
95
  return;
95
96
  }
96
- fireAnalytics(createCommencedEvent(identifier === null || identifier === void 0 ? void 0 : identifier.id, traceContext.current), createAnalyticsEventRef.current);
97
+ fireAnalytics(createCommencedEvent(identifier === null || identifier === void 0 ? void 0 : identifier.id, traceContext), createAnalyticsEventRef.current);
97
98
  startMediaFileUfoExperience();
98
- }, [identifier]);
99
+ }, [identifier, traceContext]);
99
100
  useEffect(() => {
100
101
  if (isExternalImageIdentifier(identifier)) {
101
102
  // external images do not need to talk to our backend,
@@ -129,26 +130,39 @@ export const ItemViewerBase = ({
129
130
  item.whenSuccessful(fileItem => {
130
131
  if (isFileStateItem(fileItem)) {
131
132
  const fileAttributes = getFileAttributes(fileItem);
132
- fireAnalytics(createLoadSucceededEvent(fileAttributes, traceContext.current), createAnalyticsEventRef.current);
133
+ fireAnalytics(createLoadSucceededEvent(fileAttributes, traceContext), createAnalyticsEventRef.current);
133
134
  succeedMediaFileUfoExperience({
134
135
  fileAttributes,
135
136
  fileStateFlags: fileStateFlagsRef.current
136
137
  });
137
138
  }
138
139
  });
139
- }, [item]);
140
+ }, [item, traceContext]);
140
141
  const onLoadFail = useCallback(mediaViewerError => {
141
142
  setItem(Outcome.failed(mediaViewerError, fileState));
142
143
  }, [fileState]);
143
144
  const renderItem = fileItem => {
145
+ var _viewerOptions$custom;
144
146
  const collectionName = isFileIdentifier(identifier) ? identifier.collectionName : undefined;
145
147
  const viewerProps = {
146
148
  mediaClient,
147
149
  item: fileItem,
148
150
  collectionName,
149
151
  onClose,
150
- previewCount
152
+ previewCount,
153
+ viewerOptions,
154
+ traceContext
151
155
  };
156
+ const customRenderer = viewerOptions === null || viewerOptions === void 0 ? void 0 : (_viewerOptions$custom = viewerOptions.customRenderers) === null || _viewerOptions$custom === void 0 ? void 0 : _viewerOptions$custom.find(renderer => renderer.shouldUseCustomRenderer({
157
+ fileItem
158
+ }));
159
+ if (customRenderer) {
160
+ return /*#__PURE__*/React.createElement(CustomViewer, _extends({
161
+ customRendererConfig: customRenderer,
162
+ onError: onLoadFail,
163
+ onSuccess: onSuccess
164
+ }, viewerProps));
165
+ }
152
166
 
153
167
  // TODO: fix all of the item errors
154
168
 
@@ -169,7 +183,7 @@ export const ItemViewerBase = ({
169
183
  onLoad: onSuccess,
170
184
  onError: onLoadFail,
171
185
  onClose: onClose,
172
- traceContext: traceContext.current
186
+ traceContext: traceContext
173
187
  });
174
188
  }
175
189
  const {
@@ -180,8 +194,7 @@ export const ItemViewerBase = ({
180
194
  return /*#__PURE__*/React.createElement(ImageViewer, _extends({
181
195
  onLoad: onSuccess,
182
196
  onError: onLoadFail,
183
- contextId: contextId,
184
- traceContext: traceContext.current
197
+ contextId: contextId
185
198
  }, viewerProps));
186
199
  case 'audio':
187
200
  return /*#__PURE__*/React.createElement(AudioViewer, _extends({
@@ -226,8 +239,8 @@ export const ItemViewerBase = ({
226
239
  error: error,
227
240
  fileState: fileState,
228
241
  fileStateFlags: fileStateFlagsRef.current,
229
- traceContext: traceContext.current
230
- }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file)), renderDownloadButton(fileState, error));
242
+ traceContext: traceContext
243
+ }, /*#__PURE__*/React.createElement(Text, null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file)), renderDownloadButton(fileState, error));
231
244
  } else {
232
245
  return /*#__PURE__*/React.createElement(ErrorMessage, {
233
246
  fileId: isFileIdentifier(identifier) ? identifier.id : 'undefined',
@@ -1,8 +1,9 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, useRef } from 'react';
2
2
  import { hideControlsClassName } from '@atlaskit/media-ui';
3
3
  import { ItemViewer } from './item-viewer';
4
4
  import { HeaderWrapper, ListWrapper } from './styleWrappers';
5
5
  import { Navigation } from './navigation';
6
+ import { getRandomHex } from '@atlaskit/media-common';
6
7
  import Header from './header';
7
8
  export const List = ({
8
9
  defaultSelectedItem,
@@ -14,11 +15,15 @@ export const List = ({
14
15
  featureFlags,
15
16
  isSidebarVisible,
16
17
  onNavigationChange,
17
- items
18
+ items,
19
+ viewerOptions
18
20
  }) => {
19
21
  const [selectedItem, setSelectedItem] = useState(defaultSelectedItem);
20
22
  const [previewCount, setPreviewCount] = useState(0);
21
23
  const [isArchiveSideBarVisible, setIsArchiveSideBarVisible] = useState(false);
24
+ const traceContext = useRef({
25
+ traceId: getRandomHex(8)
26
+ });
22
27
  return /*#__PURE__*/React.createElement(ListWrapper, null, /*#__PURE__*/React.createElement(HeaderWrapper
23
28
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
24
29
  , {
@@ -32,14 +37,17 @@ export const List = ({
32
37
  isSidebarVisible: isSidebarVisible,
33
38
  isArchiveSideBarVisible: isArchiveSideBarVisible,
34
39
  featureFlags: featureFlags,
35
- onSetArchiveSideBarVisible: setIsArchiveSideBarVisible
40
+ onSetArchiveSideBarVisible: setIsArchiveSideBarVisible,
41
+ traceContext: traceContext.current
36
42
  })), /*#__PURE__*/React.createElement(ItemViewer, {
37
43
  identifier: selectedItem,
38
44
  showControls: showControls,
39
45
  onClose: onClose,
40
46
  previewCount: previewCount,
41
47
  contextId: contextId,
42
- featureFlags: featureFlags
48
+ featureFlags: featureFlags,
49
+ viewerOptions: viewerOptions,
50
+ traceContext: traceContext.current
43
51
  }), /*#__PURE__*/React.createElement(Navigation, {
44
52
  items: items,
45
53
  selectedItem: selectedItem,
@@ -21,7 +21,8 @@ const MediaViewerComponent = ({
21
21
  innerRef,
22
22
  onClose,
23
23
  selectedItem,
24
- intl
24
+ intl,
25
+ viewerOptions
25
26
  }) => {
26
27
  const [isSidebarVisible, setIsSidebarVisible] = useState(false);
27
28
  const [selectedIdentifier, setSelectedIdentifier] = useState();
@@ -76,7 +77,8 @@ const MediaViewerComponent = ({
76
77
  onSidebarButtonClick: () => setIsSidebarVisible(!isSidebarVisible),
77
78
  isSidebarVisible: isSidebarVisible,
78
79
  contextId: contextId,
79
- featureFlags: featureFlags
80
+ featureFlags: featureFlags,
81
+ viewerOptions: viewerOptions
80
82
  })), renderSidebar()));
81
83
  return intl ? content : /*#__PURE__*/React.createElement(IntlProvider, {
82
84
  locale: "en"
@@ -0,0 +1 @@
1
+ export {};
@@ -5,6 +5,7 @@ import { unzip, HTTPRangeReader } from 'unzipit';
5
5
  import { FormattedMessage } from 'react-intl-next';
6
6
  import { CustomMediaPlayer, messages } from '@atlaskit/media-ui';
7
7
  import { getLanguageType, isCodeViewerItem } from '@atlaskit/media-ui/codeViewer';
8
+ import { Text } from '@atlaskit/primitives';
8
9
  import { Outcome } from '../../domain';
9
10
  import { CustomVideoPlayerWrapper, AudioPlayer, CustomAudioPlayerWrapper, DefaultCoverWrapper, ListWrapper } from '../../styleWrappers';
10
11
  import AudioIcon from '@atlaskit/icon/core/migration/audio--media-services-audio';
@@ -48,7 +49,8 @@ export class ArchiveViewerBase extends BaseViewer {
48
49
  this.setState({
49
50
  content: Outcome.successful({
50
51
  ...this.state.content.data,
51
- selectedArchiveEntry: undefined
52
+ selectedArchiveEntry: undefined,
53
+ hasLoadedEntries: false // displays a nice loading spinner for the content viewer
52
54
  })
53
55
  });
54
56
  let src = '';
@@ -56,7 +58,7 @@ export class ArchiveViewerBase extends BaseViewer {
56
58
  const isCodeMimeType = isCodeViewerItem(selectedArchiveEntry.name, getMimeTypeFromFilename(selectedArchiveEntry.name));
57
59
  if (!selectedArchiveEntry.isDirectory) {
58
60
  try {
59
- const blob = await rejectAfter(() => selectedArchiveEntry.blob());
61
+ const blob = await rejectAfter(() => selectedArchiveEntry.blob(), 10000);
60
62
  src = URL.createObjectURL(blob);
61
63
  if (isCodeMimeType) {
62
64
  codeViewerSrc = await rejectAfter(() => blob.text());
@@ -74,7 +76,8 @@ export class ArchiveViewerBase extends BaseViewer {
74
76
  isDirectory: selectedArchiveEntry.isDirectory,
75
77
  error: undefined,
76
78
  codeViewerSrc,
77
- isCodeMimeType
79
+ isCodeMimeType,
80
+ hasLoadedEntries: true
78
81
  })
79
82
  });
80
83
  });
@@ -145,7 +148,8 @@ export class ArchiveViewerBase extends BaseViewer {
145
148
  }
146
149
  renderArchiveItemViewer(content) {
147
150
  const {
148
- item
151
+ item,
152
+ viewerOptions
149
153
  } = this.props;
150
154
  const {
151
155
  src,
@@ -160,9 +164,27 @@ export class ArchiveViewerBase extends BaseViewer {
160
164
  return this.renderPreviewError(error, selectedArchiveEntry);
161
165
  }
162
166
  if (!isDirectory && selectedArchiveEntry) {
167
+ var _viewerOptions$custom;
163
168
  if (!name || !src) {
164
169
  return this.renderPreviewError(new ArchiveViewerError('archiveviewer-missing-name-src'), selectedArchiveEntry);
165
170
  }
171
+ const customRenderer = viewerOptions === null || viewerOptions === void 0 ? void 0 : (_viewerOptions$custom = viewerOptions.customRenderers) === null || _viewerOptions$custom === void 0 ? void 0 : _viewerOptions$custom.find(renderer => renderer.shouldUseCustomRenderer({
172
+ fileItem: item,
173
+ archiveFileItem: {
174
+ name
175
+ }
176
+ }));
177
+ if (customRenderer) {
178
+ return /*#__PURE__*/React.createElement(ArchiveItemViewerWrapper, null, customRenderer.renderContent({
179
+ fileItem: item,
180
+ archiveFileItem: {
181
+ name
182
+ },
183
+ getBinaryContent: async () => (await fetch(src)).blob(),
184
+ onLoad: this.onViewerLoad(selectedArchiveEntry),
185
+ onError: this.onViewerError('archiveviewer-customrenderer-onerror', selectedArchiveEntry)
186
+ }));
187
+ }
166
188
  const mediaType = getMediaTypeFromFilename(name);
167
189
  if (isCodeMimeType) {
168
190
  // Same code viewer logic as in Item-Viewer.tsx
@@ -242,7 +264,7 @@ export class ArchiveViewerBase extends BaseViewer {
242
264
  fileState: item,
243
265
  error: error,
244
266
  supressAnalytics: true
245
- }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file))));
267
+ }, /*#__PURE__*/React.createElement(Text, null, /*#__PURE__*/React.createElement(FormattedMessage, messages.try_downloading_file))));
246
268
  }
247
269
  }
248
270
  export const ArchiveViewer = withAnalyticsEvents()(ArchiveViewerBase);
@@ -81,13 +81,15 @@ export class BaseViewer extends React.Component {
81
81
  const {
82
82
  item,
83
83
  mediaClient,
84
- collectionName
84
+ collectionName,
85
+ traceContext
85
86
  } = this.props;
86
87
  return /*#__PURE__*/React.createElement(ErrorViewDownloadButton, {
87
88
  fileState: item,
88
89
  mediaClient: mediaClient,
89
90
  error: error,
90
- collectionName: collectionName
91
+ collectionName: collectionName,
92
+ traceContext: traceContext
91
93
  });
92
94
  }
93
95
  needsReset(propsA, propsB) {
@@ -0,0 +1,37 @@
1
+ import { MediaViewerError } from '../../errors';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import React from 'react';
4
+ import { Spinner } from '../../loading';
5
+ export const CustomViewer = ({
6
+ mediaClient,
7
+ item,
8
+ customRendererConfig,
9
+ onSuccess,
10
+ onError
11
+ }) => {
12
+ const [getBinaryContent, setGetBinaryContent] = useState();
13
+ useEffect(() => {
14
+ setGetBinaryContent(undefined);
15
+ const abortController = new AbortController();
16
+ // This sets the 'getBinaryContent' to an async function that fetches the binary content of the file
17
+ // The 'getBinaryContent' function has to be updated when the item changes
18
+ // This approach handles aborting in-progress request outside of the custom-renderer concern
19
+ if (item.status === 'processed' || item.status === 'failed-processing') {
20
+ setGetBinaryContent(() => () => mediaClient.mediaStore.getFileBinary(item.id, undefined, abortController));
21
+ }
22
+ return () => abortController.abort();
23
+ }, [item, mediaClient]);
24
+ const onLoadFailed = useCallback(error => {
25
+ const mediaError = new MediaViewerError('custom-viewer-error', error);
26
+ onError(mediaError, item);
27
+ }, [item, onError]);
28
+ if (!getBinaryContent) {
29
+ return /*#__PURE__*/React.createElement(Spinner, null);
30
+ }
31
+ return /*#__PURE__*/React.createElement(React.Fragment, null, customRendererConfig.renderContent({
32
+ fileItem: item,
33
+ getBinaryContent,
34
+ onLoad: onSuccess,
35
+ onError: onLoadFailed
36
+ }));
37
+ };