@atlaskit/media-viewer 54.3.7 → 54.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.
- package/CHANGELOG.md +25 -0
- package/dist/cjs/analytics/index.js +1 -1
- package/dist/cjs/analytics/ufoExperiences.js +1 -1
- package/dist/cjs/download.js +13 -7
- package/dist/cjs/errorMessage.js +17 -5
- package/dist/cjs/errors.js +64 -0
- package/dist/cjs/header.js +2 -1
- package/dist/cjs/viewers/image/index.js +38 -9
- package/dist/es2019/analytics/index.js +1 -1
- package/dist/es2019/analytics/ufoExperiences.js +1 -1
- package/dist/es2019/download.js +13 -6
- package/dist/es2019/errorMessage.js +16 -4
- package/dist/es2019/errors.js +53 -1
- package/dist/es2019/header.js +2 -1
- package/dist/es2019/viewers/image/index.js +26 -5
- package/dist/esm/analytics/index.js +1 -1
- package/dist/esm/analytics/ufoExperiences.js +1 -1
- package/dist/esm/download.js +13 -7
- package/dist/esm/errorMessage.js +17 -5
- package/dist/esm/errors.js +63 -1
- package/dist/esm/header.js +2 -1
- package/dist/esm/viewers/image/index.js +39 -10
- package/dist/types/download.d.ts +2 -1
- package/dist/types/errorMessage.d.ts +2 -0
- package/dist/types/errors.d.ts +24 -2
- package/package.json +12 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @atlaskit/media-viewer
|
|
2
2
|
|
|
3
|
+
## 54.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`ecf905d329e42`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ecf905d329e42) -
|
|
8
|
+
Add diagnostic context to the imageviewer-src-onerror failure (errorDetail now report mimeType,
|
|
9
|
+
decode dimensions and failed source type instead of unknown)
|
|
10
|
+
- [`a654b7573d0a2`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a654b7573d0a2) -
|
|
11
|
+
Route image MIME types that the browser cannot natively decode (e.g. HEIC/HEIF, PSD, TIFF) to the
|
|
12
|
+
unsupported/download preview view instead of a guaranteed-failing `<img>`. These are reported via
|
|
13
|
+
the `previewUnsupported` analytics event rather than `loadFailed`. Behind the
|
|
14
|
+
`platform_media_unsupported_mime_routing` feature gate.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
|
|
20
|
+
## 54.3.8
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- [`bea4da79c297d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bea4da79c297d) -
|
|
25
|
+
[ux] EDITOR-7679 use fallback media name for filename in download
|
|
26
|
+
- Updated dependencies
|
|
27
|
+
|
|
3
28
|
## 54.3.7
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -10,7 +10,7 @@ exports.packageVersion = exports.packageName = void 0;
|
|
|
10
10
|
var _analytics = require("@atlaskit/media-common/analytics");
|
|
11
11
|
var componentName = exports.component = exports.componentName = 'mediaViewer';
|
|
12
12
|
var packageName = exports.packageName = "@atlaskit/media-viewer";
|
|
13
|
-
var packageVersion = exports.packageVersion = "54.
|
|
13
|
+
var packageVersion = exports.packageVersion = "54.4.0";
|
|
14
14
|
function getFileAttributes(fileState) {
|
|
15
15
|
if (!fileState) {
|
|
16
16
|
return {
|
|
@@ -13,7 +13,7 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
|
13
13
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
14
14
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
15
15
|
var packageName = "@atlaskit/media-viewer";
|
|
16
|
-
var packageVersion = "54.
|
|
16
|
+
var packageVersion = "54.4.0";
|
|
17
17
|
var ufoExperience;
|
|
18
18
|
var getExperience = function getExperience() {
|
|
19
19
|
if (!ufoExperience) {
|
package/dist/cjs/download.js
CHANGED
|
@@ -22,6 +22,7 @@ var _download2 = require("./analytics/events/operational/download");
|
|
|
22
22
|
var _analytics = require("./analytics");
|
|
23
23
|
var _failedPreviewDownloadButtonClicked = require("./analytics/events/ui/failedPreviewDownloadButtonClicked");
|
|
24
24
|
var _styleWrappers = require("./styleWrappers");
|
|
25
|
+
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
25
26
|
var _errors = require("./errors");
|
|
26
27
|
var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
|
|
27
28
|
var _abuseModal = require("@atlaskit/media-ui/abuseModal");
|
|
@@ -56,13 +57,14 @@ function DownloadButton(_ref) {
|
|
|
56
57
|
}
|
|
57
58
|
var createItemDownloader = function createItemDownloader(file, mediaClient, options) {
|
|
58
59
|
return /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
59
|
-
var collectionName, traceContext, createAnalyticsEvent, id, name;
|
|
60
|
+
var collectionName, traceContext, createAnalyticsEvent, fallbackMediaName, id, fileStateName, name;
|
|
60
61
|
return _regenerator.default.wrap(function (_context) {
|
|
61
62
|
while (1) switch (_context.prev = _context.next) {
|
|
62
63
|
case 0:
|
|
63
|
-
collectionName = options.collectionName, traceContext = options.traceContext, createAnalyticsEvent = options.createAnalyticsEvent;
|
|
64
|
+
collectionName = options.collectionName, traceContext = options.traceContext, createAnalyticsEvent = options.createAnalyticsEvent, fallbackMediaName = options.fallbackMediaName;
|
|
64
65
|
id = file.id;
|
|
65
|
-
|
|
66
|
+
fileStateName = !(0, _mediaClient.isErrorFileState)(file) ? file.name : undefined;
|
|
67
|
+
name = fileStateName || ((0, _expValEquals.expValEquals)('platform_editor_media_download_fallback_name', 'isEnabled', true) ? fallbackMediaName : undefined);
|
|
66
68
|
mediaClient.file.downloadBinary(id, name, collectionName, traceContext).then(function () {
|
|
67
69
|
(0, _analytics.fireAnalytics)((0, _download2.createDownloadSucceededEventPayload)(file, traceContext), createAnalyticsEvent);
|
|
68
70
|
}).catch(function (e) {
|
|
@@ -94,7 +96,8 @@ var DownloadItem = function DownloadItem(_ref3) {
|
|
|
94
96
|
analyticspayload = _ref3.analyticspayload,
|
|
95
97
|
traceContext = _ref3.traceContext,
|
|
96
98
|
iconBefore = _ref3.iconBefore,
|
|
97
|
-
children = _ref3.children
|
|
99
|
+
children = _ref3.children,
|
|
100
|
+
fallbackMediaName = _ref3.fallbackMediaName;
|
|
98
101
|
var _useState = (0, _react.useState)(false),
|
|
99
102
|
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
100
103
|
isAbuseModalOpen = _useState2[0],
|
|
@@ -108,7 +111,8 @@ var DownloadItem = function DownloadItem(_ref3) {
|
|
|
108
111
|
var itemDownloader = createItemDownloader(fileState, mediaClient, {
|
|
109
112
|
collectionName: collectionName,
|
|
110
113
|
createAnalyticsEvent: createAnalyticsEvent,
|
|
111
|
-
traceContext: traceContext
|
|
114
|
+
traceContext: traceContext,
|
|
115
|
+
fallbackMediaName: fallbackMediaName
|
|
112
116
|
});
|
|
113
117
|
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, shouldRenderAbuseModal && /*#__PURE__*/_react.default.createElement(_abuseModal.AbuseModal, {
|
|
114
118
|
isOpen: isAbuseModalOpen,
|
|
@@ -154,7 +158,8 @@ var ToolbarDownloadButton = exports.ToolbarDownloadButton = function ToolbarDown
|
|
|
154
158
|
var state = _ref5.state,
|
|
155
159
|
mediaClient = _ref5.mediaClient,
|
|
156
160
|
identifier = _ref5.identifier,
|
|
157
|
-
traceContext = _ref5.traceContext
|
|
161
|
+
traceContext = _ref5.traceContext,
|
|
162
|
+
fallbackMediaName = _ref5.fallbackMediaName;
|
|
158
163
|
// TODO [MS-1731]: make it work for external files as well
|
|
159
164
|
if ((0, _mediaClient.isExternalImageIdentifier)(identifier)) {
|
|
160
165
|
return null;
|
|
@@ -168,7 +173,8 @@ var ToolbarDownloadButton = exports.ToolbarDownloadButton = function ToolbarDown
|
|
|
168
173
|
mediaClient: mediaClient,
|
|
169
174
|
collectionName: identifier.collectionName,
|
|
170
175
|
traceContext: traceContext,
|
|
171
|
-
iconBefore: downloadIcon
|
|
176
|
+
iconBefore: downloadIcon,
|
|
177
|
+
fallbackMediaName: fallbackMediaName
|
|
172
178
|
});
|
|
173
179
|
};
|
|
174
180
|
var DisabledToolbarDownloadButton = exports.DisabledToolbarDownloadButton = /*#__PURE__*/_react.default.createElement(_mediaUi.MediaButton, {
|
package/dist/cjs/errorMessage.js
CHANGED
|
@@ -5,12 +5,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.getErrorMessageFromError = exports.errorReasonToMessages = exports.default = exports.ErrorMessage = void 0;
|
|
8
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
8
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
10
9
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
11
10
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
12
11
|
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
13
12
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
13
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
14
14
|
var _react = _interopRequireDefault(require("react"));
|
|
15
15
|
var _reactIntl = require("react-intl");
|
|
16
16
|
var _mediaUi = require("@atlaskit/media-ui");
|
|
@@ -51,11 +51,12 @@ var ErrorMessage = exports.ErrorMessage = /*#__PURE__*/function (_React$Componen
|
|
|
51
51
|
var _this$props = this.props,
|
|
52
52
|
formatMessage = _this$props.intl.formatMessage,
|
|
53
53
|
error = _this$props.error;
|
|
54
|
-
// Non-ZIP archives (e.g. RAR, TAR, 7z)
|
|
54
|
+
// Non-ZIP archives (e.g. RAR, TAR, 7z) and image MIME types that no browser
|
|
55
|
+
// can natively decode (e.g. HEIC/HEIF, PSD, TIFF) aren't load failures - the
|
|
55
56
|
// browser-based viewer simply can't preview them. Show a dedicated
|
|
56
57
|
// "Unsupported file format" heading instead of the generic
|
|
57
58
|
// "Something went wrong" copy.
|
|
58
|
-
if ((0, _errors.getPrimaryErrorReason)(error) === 'archiveviewer-not-zip') {
|
|
59
|
+
if ((0, _errors.getPrimaryErrorReason)(error) === 'archiveviewer-not-zip' || (0, _errors.getPrimaryErrorReason)(error) === 'imageviewer-unsupported-mime') {
|
|
59
60
|
return {
|
|
60
61
|
icon: errorLoadingFileImage(formatMessage),
|
|
61
62
|
messages: [_mediaUi.messages.unsupported_file_format, _mediaUi.messages.archive_format_not_supported]
|
|
@@ -95,6 +96,10 @@ var ErrorMessage = exports.ErrorMessage = /*#__PURE__*/function (_React$Componen
|
|
|
95
96
|
(0, _ufoExperiences.failMediaFileUfoExperience)(failMediaFileUfoExperiencePayload);
|
|
96
97
|
}
|
|
97
98
|
}
|
|
99
|
+
|
|
100
|
+
// Error reasons that represent a format the browser-based viewer simply can't
|
|
101
|
+
// preview (not a load failure). These are reported as the informational,
|
|
102
|
+
// non-SLI `previewUnsupported` metric instead of `loadFailed`.
|
|
98
103
|
}, {
|
|
99
104
|
key: "render",
|
|
100
105
|
value: function render() {
|
|
@@ -112,10 +117,16 @@ var ErrorMessage = exports.ErrorMessage = /*#__PURE__*/function (_React$Componen
|
|
|
112
117
|
})), this.props.children);
|
|
113
118
|
}
|
|
114
119
|
}], [{
|
|
120
|
+
key: "isPreviewUnsupported",
|
|
121
|
+
value: function isPreviewUnsupported(error) {
|
|
122
|
+
return ErrorMessage.previewUnsupportedReasons.includes((0, _errors.getPrimaryErrorReason)(error));
|
|
123
|
+
}
|
|
124
|
+
}, {
|
|
115
125
|
key: "getEventPayload",
|
|
116
126
|
value: function getEventPayload(error, fileId, fileState, traceContext) {
|
|
117
|
-
if (fileState &&
|
|
118
|
-
// this is not an SLI, its just a useful metric for
|
|
127
|
+
if (fileState && ErrorMessage.isPreviewUnsupported(error)) {
|
|
128
|
+
// this is not an SLI (load failure), its just a useful metric for files
|
|
129
|
+
// whose format the browser-based viewer can't preview.
|
|
119
130
|
return (0, _previewUnsupported.createPreviewUnsupportedEvent)(fileState);
|
|
120
131
|
} else {
|
|
121
132
|
return (0, _loadFailed.createLoadFailedEvent)(fileId, error, fileState, traceContext);
|
|
@@ -123,5 +134,6 @@ var ErrorMessage = exports.ErrorMessage = /*#__PURE__*/function (_React$Componen
|
|
|
123
134
|
}
|
|
124
135
|
}]);
|
|
125
136
|
}(_react.default.Component); // @ts-ignore: [PIT-1685] Fails in post-office due to backwards incompatibility issue with React 18
|
|
137
|
+
(0, _defineProperty2.default)(ErrorMessage, "previewUnsupportedReasons", ['unsupported', 'imageviewer-unsupported-mime']);
|
|
126
138
|
var ErroMsg = (0, _analyticsNext.withAnalyticsEvents)()((0, _reactIntl.injectIntl)(ErrorMessage));
|
|
127
139
|
var _default = exports.default = ErroMsg;
|
package/dist/cjs/errors.js
CHANGED
|
@@ -5,12 +5,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.MediaViewerError = exports.ArchiveViewerError = void 0;
|
|
8
|
+
exports.buildImgErrorDiagnostics = buildImgErrorDiagnostics;
|
|
9
|
+
exports.classifyFailedSrc = classifyFailedSrc;
|
|
8
10
|
exports.getErrorDetail = getErrorDetail;
|
|
9
11
|
exports.getPrimaryErrorReason = getPrimaryErrorReason;
|
|
10
12
|
exports.getRequestMetadata = getRequestMetadata;
|
|
11
13
|
exports.getSecondaryErrorReason = getSecondaryErrorReason;
|
|
12
14
|
exports.isArchiveViewerError = isArchiveViewerError;
|
|
13
15
|
exports.isMediaViewerError = isMediaViewerError;
|
|
16
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
14
17
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
15
18
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
16
19
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
@@ -18,6 +21,7 @@ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/ge
|
|
|
18
21
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
19
22
|
var _wrapNativeSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/wrapNativeSuper"));
|
|
20
23
|
var _mediaClient = require("@atlaskit/media-client");
|
|
24
|
+
var _isMimeTypeSupportedByBrowser = require("@atlaskit/media-common/isMimeTypeSupportedByBrowser");
|
|
21
25
|
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
|
|
22
26
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
23
27
|
var MediaViewerError = exports.MediaViewerError = /*#__PURE__*/function (_Error) {
|
|
@@ -91,4 +95,64 @@ function getRequestMetadata(error) {
|
|
|
91
95
|
if ((0, _mediaClient.isCommonMediaClientError)(secondaryError)) {
|
|
92
96
|
return secondaryError.metadata;
|
|
93
97
|
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Classifies the failed `<img>` source into a coarse, non-sensitive enum so we can
|
|
102
|
+
* tell which kind of source failed without leaking the (potentially signed) url.
|
|
103
|
+
*/
|
|
104
|
+
function classifyFailedSrc(currentSrc) {
|
|
105
|
+
if (!currentSrc) {
|
|
106
|
+
return 'unknown';
|
|
107
|
+
}
|
|
108
|
+
if (currentSrc.startsWith('blob:')) {
|
|
109
|
+
return 'blob';
|
|
110
|
+
}
|
|
111
|
+
if (currentSrc.startsWith('data:')) {
|
|
112
|
+
return 'data';
|
|
113
|
+
}
|
|
114
|
+
if (currentSrc.startsWith('http:') || currentSrc.startsWith('https:')) {
|
|
115
|
+
return 'remote';
|
|
116
|
+
}
|
|
117
|
+
return 'unknown';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Builds a descriptive `secondaryError` for an `<img>` onerror so the downstream
|
|
122
|
+
* `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
|
|
123
|
+
* the opaque `unknown`/`unknown`. The returned Error's `message` captures decode
|
|
124
|
+
* diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
|
|
125
|
+
* - whether the browser decoded any pixels (`naturalWidth`/`naturalHeight === 0`)
|
|
126
|
+
* - the file MIME type and whether it is natively browser-decodable
|
|
127
|
+
* - which source failed (preview blob vs. original-binary/HD url)
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* // message:
|
|
131
|
+
* "mimeType=image/png, isBrowserDecodable=true, naturalWidth=0, naturalHeight=0, failedSrcType=blob"
|
|
132
|
+
*/
|
|
133
|
+
function buildImgErrorDiagnostics(item, event) {
|
|
134
|
+
var img = event === null || event === void 0 ? void 0 : event.currentTarget;
|
|
135
|
+
var mimeType = item && !(0, _mediaClient.isErrorFileState)(item) ? item.mimeType : undefined;
|
|
136
|
+
var isBrowserDecodable = !!mimeType && (0, _isMimeTypeSupportedByBrowser.isImageMimeTypeSupportedByBrowser)(mimeType);
|
|
137
|
+
var naturalWidth = img === null || img === void 0 ? void 0 : img.naturalWidth;
|
|
138
|
+
var naturalHeight = img === null || img === void 0 ? void 0 : img.naturalHeight;
|
|
139
|
+
var failedSrcType = classifyFailedSrc(img === null || img === void 0 ? void 0 : img.currentSrc);
|
|
140
|
+
var diagnostics = {
|
|
141
|
+
mimeType: mimeType,
|
|
142
|
+
isBrowserDecodable: isBrowserDecodable,
|
|
143
|
+
naturalWidth: naturalWidth,
|
|
144
|
+
naturalHeight: naturalHeight,
|
|
145
|
+
failedSrcType: failedSrcType
|
|
146
|
+
};
|
|
147
|
+
var detail = Object.entries(diagnostics).filter(function (_ref3) {
|
|
148
|
+
var _ref4 = (0, _slicedToArray2.default)(_ref3, 2),
|
|
149
|
+
value = _ref4[1];
|
|
150
|
+
return value !== undefined;
|
|
151
|
+
}).map(function (_ref5) {
|
|
152
|
+
var _ref6 = (0, _slicedToArray2.default)(_ref5, 2),
|
|
153
|
+
key = _ref6[0],
|
|
154
|
+
value = _ref6[1];
|
|
155
|
+
return "".concat(key, "=").concat(value);
|
|
156
|
+
}).join(', ');
|
|
157
|
+
return new Error(detail);
|
|
94
158
|
}
|
package/dist/cjs/header.js
CHANGED
|
@@ -205,7 +205,8 @@ var Header = exports.Header = function Header(_ref) {
|
|
|
205
205
|
state: item,
|
|
206
206
|
identifier: identifier,
|
|
207
207
|
mediaClient: mediaClient,
|
|
208
|
-
traceContext: traceContext
|
|
208
|
+
traceContext: traceContext,
|
|
209
|
+
fallbackMediaName: fallbackMediaName
|
|
209
210
|
});
|
|
210
211
|
}
|
|
211
212
|
})));
|
|
@@ -17,6 +17,7 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
17
17
|
var _mediaClient = require("@atlaskit/media-client");
|
|
18
18
|
var _mediaCommon = require("@atlaskit/media-common");
|
|
19
19
|
var _mediaUi = require("@atlaskit/media-ui");
|
|
20
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
20
21
|
var _domain = require("../../domain");
|
|
21
22
|
var _errors = require("../../errors");
|
|
22
23
|
var _interactiveImg = require("./interactive-img");
|
|
@@ -43,8 +44,14 @@ var ImageViewer = exports.ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
43
44
|
_this.props.onLoad();
|
|
44
45
|
_this.onMediaDisplayed();
|
|
45
46
|
});
|
|
46
|
-
(0, _defineProperty2.default)(_this, "onImgError", function () {
|
|
47
|
-
|
|
47
|
+
(0, _defineProperty2.default)(_this, "onImgError", function (event) {
|
|
48
|
+
var secondaryError;
|
|
49
|
+
try {
|
|
50
|
+
secondaryError = (0, _errors.buildImgErrorDiagnostics)(_this.props.item, event);
|
|
51
|
+
} catch (_unused) {
|
|
52
|
+
secondaryError = undefined;
|
|
53
|
+
}
|
|
54
|
+
_this.props.onError(new _errors.MediaViewerError('imageviewer-src-onerror', secondaryError));
|
|
48
55
|
});
|
|
49
56
|
return _this;
|
|
50
57
|
}
|
|
@@ -60,7 +67,7 @@ var ImageViewer = exports.ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
60
67
|
key: "init",
|
|
61
68
|
value: function () {
|
|
62
69
|
var _init = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
63
|
-
var _this$props, fileState, mediaClient, collectionName, traceContext, controller, orientation, objectUrl, originalBinaryImageUrl, isLocalFileReference, clientId, preview, _yield$preview, value, origin, item, response, imgError, _t, _t2, _t3;
|
|
70
|
+
var _this$props, fileState, mediaClient, collectionName, traceContext, controller, orientation, objectUrl, originalBinaryImageUrl, isLocalFileReference, clientId, preview, _yield$preview, value, origin, item, response, unsupportedError, imgError, _t, _t2, _t3;
|
|
64
71
|
return _regenerator.default.wrap(function (_context) {
|
|
65
72
|
while (1) switch (_context.prev = _context.next) {
|
|
66
73
|
case 0:
|
|
@@ -142,7 +149,11 @@ var ImageViewer = exports.ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
142
149
|
case 14:
|
|
143
150
|
if (!(!isLocalFileReference &&
|
|
144
151
|
// objectUrl at this point is binary file already
|
|
145
|
-
!(0, _mediaClient.isErrorFileState)(fileState) && fileState.status !== 'uploading' && fileState.mediaType === 'image'
|
|
152
|
+
!(0, _mediaClient.isErrorFileState)(fileState) && fileState.status !== 'uploading' && fileState.mediaType === 'image')) {
|
|
153
|
+
_context.next = 17;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
if (!(0, _mediaCommon.isImageMimeTypeSupportedByBrowser)(fileState.mimeType)) {
|
|
146
157
|
_context.next = 16;
|
|
147
158
|
break;
|
|
148
159
|
}
|
|
@@ -150,7 +161,25 @@ var ImageViewer = exports.ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
150
161
|
return mediaClient.file.getFileBinaryURL(fileState.id, collectionName);
|
|
151
162
|
case 15:
|
|
152
163
|
originalBinaryImageUrl = _context.sent;
|
|
164
|
+
_context.next = 17;
|
|
165
|
+
break;
|
|
153
166
|
case 16:
|
|
167
|
+
if (!(0, _platformFeatureFlags.fg)('platform_media_unsupported_mime_routing')) {
|
|
168
|
+
_context.next = 17;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
// Route unsupported MIME types browser can't natively decode straight to the
|
|
172
|
+
// unsupported/download view instead of handing a guaranteed-undecodable blob
|
|
173
|
+
// to <img>, which would only ever fire onerror and
|
|
174
|
+
// surface as an opaque `imageviewer-src-onerror` failure.
|
|
175
|
+
this.revokeObjectUrl(objectUrl);
|
|
176
|
+
unsupportedError = new _errors.MediaViewerError('imageviewer-unsupported-mime');
|
|
177
|
+
this.setState({
|
|
178
|
+
content: _domain.Outcome.failed(unsupportedError)
|
|
179
|
+
});
|
|
180
|
+
this.props.onError(unsupportedError);
|
|
181
|
+
return _context.abrupt("return");
|
|
182
|
+
case 17:
|
|
154
183
|
this.setState({
|
|
155
184
|
content: _domain.Outcome.successful({
|
|
156
185
|
objectUrl: objectUrl,
|
|
@@ -159,10 +188,10 @@ var ImageViewer = exports.ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
159
188
|
clientId: clientId
|
|
160
189
|
})
|
|
161
190
|
});
|
|
162
|
-
_context.next =
|
|
191
|
+
_context.next = 19;
|
|
163
192
|
break;
|
|
164
|
-
case
|
|
165
|
-
_context.prev =
|
|
193
|
+
case 18:
|
|
194
|
+
_context.prev = 18;
|
|
166
195
|
_t3 = _context["catch"](2);
|
|
167
196
|
// TODO : properly handle aborted requests (MS-2843)
|
|
168
197
|
if (!(controller !== null && controller !== void 0 && controller.signal.aborted)) {
|
|
@@ -172,11 +201,11 @@ var ImageViewer = exports.ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
172
201
|
});
|
|
173
202
|
this.props.onError(imgError);
|
|
174
203
|
}
|
|
175
|
-
case
|
|
204
|
+
case 19:
|
|
176
205
|
case "end":
|
|
177
206
|
return _context.stop();
|
|
178
207
|
}
|
|
179
|
-
}, _callee, this, [[2,
|
|
208
|
+
}, _callee, this, [[2, 18], [3, 5]]);
|
|
180
209
|
}));
|
|
181
210
|
function init() {
|
|
182
211
|
return _init.apply(this, arguments);
|
|
@@ -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 = "54.
|
|
4
|
+
const packageVersion = "54.4.0";
|
|
5
5
|
export { packageName, packageVersion, componentName, componentName as component };
|
|
6
6
|
export function getFileAttributes(fileState) {
|
|
7
7
|
if (!fileState) {
|
|
@@ -3,7 +3,7 @@ import { getMediaEnvironment, getMediaRegion } from '@atlaskit/media-client';
|
|
|
3
3
|
import { getFeatureFlagKeysAllProducts } from '@atlaskit/media-common';
|
|
4
4
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
5
|
const packageName = "@atlaskit/media-viewer";
|
|
6
|
-
const packageVersion = "54.
|
|
6
|
+
const packageVersion = "54.4.0";
|
|
7
7
|
let ufoExperience;
|
|
8
8
|
const getExperience = () => {
|
|
9
9
|
if (!ufoExperience) {
|
package/dist/es2019/download.js
CHANGED
|
@@ -10,6 +10,7 @@ import { createDownloadFailedEventPayload, createDownloadSucceededEventPayload }
|
|
|
10
10
|
import { fireAnalytics } from './analytics';
|
|
11
11
|
import { createFailedPreviewDownloadButtonClickedEvent } from './analytics/events/ui/failedPreviewDownloadButtonClicked';
|
|
12
12
|
import { DownloadButtonWrapper } from './styleWrappers';
|
|
13
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
13
14
|
import { MediaViewerError } from './errors';
|
|
14
15
|
import Tooltip from '@atlaskit/tooltip';
|
|
15
16
|
import { AbuseModal } from '@atlaskit/media-ui/abuseModal';
|
|
@@ -45,10 +46,12 @@ const createItemDownloader = (file, mediaClient, options) => async () => {
|
|
|
45
46
|
const {
|
|
46
47
|
collectionName,
|
|
47
48
|
traceContext,
|
|
48
|
-
createAnalyticsEvent
|
|
49
|
+
createAnalyticsEvent,
|
|
50
|
+
fallbackMediaName
|
|
49
51
|
} = options;
|
|
50
52
|
const id = file.id;
|
|
51
|
-
const
|
|
53
|
+
const fileStateName = !isErrorFileState(file) ? file.name : undefined;
|
|
54
|
+
const name = fileStateName || (expValEquals('platform_editor_media_download_fallback_name', 'isEnabled', true) ? fallbackMediaName : undefined);
|
|
52
55
|
mediaClient.file.downloadBinary(id, name, collectionName, traceContext).then(() => {
|
|
53
56
|
fireAnalytics(createDownloadSucceededEventPayload(file, traceContext), createAnalyticsEvent);
|
|
54
57
|
}).catch(e => {
|
|
@@ -75,7 +78,8 @@ const DownloadItem = ({
|
|
|
75
78
|
analyticspayload,
|
|
76
79
|
traceContext,
|
|
77
80
|
iconBefore,
|
|
78
|
-
children
|
|
81
|
+
children,
|
|
82
|
+
fallbackMediaName
|
|
79
83
|
}) => {
|
|
80
84
|
const [isAbuseModalOpen, setIsAbuseModalOpen] = useState(false);
|
|
81
85
|
const {
|
|
@@ -89,7 +93,8 @@ const DownloadItem = ({
|
|
|
89
93
|
const itemDownloader = createItemDownloader(fileState, mediaClient, {
|
|
90
94
|
collectionName: collectionName,
|
|
91
95
|
createAnalyticsEvent,
|
|
92
|
-
traceContext
|
|
96
|
+
traceContext,
|
|
97
|
+
fallbackMediaName
|
|
93
98
|
});
|
|
94
99
|
return /*#__PURE__*/React.createElement(React.Fragment, null, shouldRenderAbuseModal && /*#__PURE__*/React.createElement(AbuseModal, {
|
|
95
100
|
isOpen: isAbuseModalOpen,
|
|
@@ -134,7 +139,8 @@ export const ToolbarDownloadButton = ({
|
|
|
134
139
|
state,
|
|
135
140
|
mediaClient,
|
|
136
141
|
identifier,
|
|
137
|
-
traceContext
|
|
142
|
+
traceContext,
|
|
143
|
+
fallbackMediaName
|
|
138
144
|
}) => {
|
|
139
145
|
// TODO [MS-1731]: make it work for external files as well
|
|
140
146
|
if (isExternalImageIdentifier(identifier)) {
|
|
@@ -149,7 +155,8 @@ export const ToolbarDownloadButton = ({
|
|
|
149
155
|
mediaClient: mediaClient,
|
|
150
156
|
collectionName: identifier.collectionName,
|
|
151
157
|
traceContext: traceContext,
|
|
152
|
-
iconBefore: downloadIcon
|
|
158
|
+
iconBefore: downloadIcon,
|
|
159
|
+
fallbackMediaName: fallbackMediaName
|
|
153
160
|
});
|
|
154
161
|
};
|
|
155
162
|
export const DisabledToolbarDownloadButton = /*#__PURE__*/React.createElement(MediaButton, {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
|
3
4
|
import { messages as i18nMessages } from '@atlaskit/media-ui';
|
|
@@ -26,11 +27,12 @@ export class ErrorMessage extends React.Component {
|
|
|
26
27
|
},
|
|
27
28
|
error
|
|
28
29
|
} = this.props;
|
|
29
|
-
// Non-ZIP archives (e.g. RAR, TAR, 7z)
|
|
30
|
+
// Non-ZIP archives (e.g. RAR, TAR, 7z) and image MIME types that no browser
|
|
31
|
+
// can natively decode (e.g. HEIC/HEIF, PSD, TIFF) aren't load failures - the
|
|
30
32
|
// browser-based viewer simply can't preview them. Show a dedicated
|
|
31
33
|
// "Unsupported file format" heading instead of the generic
|
|
32
34
|
// "Something went wrong" copy.
|
|
33
|
-
if (getPrimaryErrorReason(error) === 'archiveviewer-not-zip') {
|
|
35
|
+
if (getPrimaryErrorReason(error) === 'archiveviewer-not-zip' || getPrimaryErrorReason(error) === 'imageviewer-unsupported-mime') {
|
|
34
36
|
return {
|
|
35
37
|
icon: errorLoadingFileImage(formatMessage),
|
|
36
38
|
messages: [i18nMessages.unsupported_file_format, i18nMessages.archive_format_not_supported]
|
|
@@ -73,9 +75,18 @@ export class ErrorMessage extends React.Component {
|
|
|
73
75
|
failMediaFileUfoExperience(failMediaFileUfoExperiencePayload);
|
|
74
76
|
}
|
|
75
77
|
}
|
|
78
|
+
|
|
79
|
+
// Error reasons that represent a format the browser-based viewer simply can't
|
|
80
|
+
// preview (not a load failure). These are reported as the informational,
|
|
81
|
+
// non-SLI `previewUnsupported` metric instead of `loadFailed`.
|
|
82
|
+
|
|
83
|
+
static isPreviewUnsupported(error) {
|
|
84
|
+
return ErrorMessage.previewUnsupportedReasons.includes(getPrimaryErrorReason(error));
|
|
85
|
+
}
|
|
76
86
|
static getEventPayload(error, fileId, fileState, traceContext) {
|
|
77
|
-
if (fileState &&
|
|
78
|
-
// this is not an SLI, its just a useful metric for
|
|
87
|
+
if (fileState && ErrorMessage.isPreviewUnsupported(error)) {
|
|
88
|
+
// this is not an SLI (load failure), its just a useful metric for files
|
|
89
|
+
// whose format the browser-based viewer can't preview.
|
|
79
90
|
return createPreviewUnsupportedEvent(fileState);
|
|
80
91
|
} else {
|
|
81
92
|
return createLoadFailedEvent(fileId, error, fileState, traceContext);
|
|
@@ -95,5 +106,6 @@ export class ErrorMessage extends React.Component {
|
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
// @ts-ignore: [PIT-1685] Fails in post-office due to backwards incompatibility issue with React 18
|
|
109
|
+
_defineProperty(ErrorMessage, "previewUnsupportedReasons", ['unsupported', 'imageviewer-unsupported-mime']);
|
|
98
110
|
const ErroMsg = withAnalyticsEvents()(injectIntl(ErrorMessage));
|
|
99
111
|
export default ErroMsg;
|
package/dist/es2019/errors.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { isCommonMediaClientError } from '@atlaskit/media-client';
|
|
1
|
+
import { isCommonMediaClientError, isErrorFileState } from '@atlaskit/media-client';
|
|
2
|
+
import { isImageMimeTypeSupportedByBrowser } from '@atlaskit/media-common/isMimeTypeSupportedByBrowser';
|
|
2
3
|
export class MediaViewerError extends Error {
|
|
3
4
|
constructor(primaryReason, secondaryError) {
|
|
4
5
|
super(primaryReason);
|
|
@@ -64,4 +65,55 @@ export function getRequestMetadata(error) {
|
|
|
64
65
|
if (isCommonMediaClientError(secondaryError)) {
|
|
65
66
|
return secondaryError.metadata;
|
|
66
67
|
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Classifies the failed `<img>` source into a coarse, non-sensitive enum so we can
|
|
72
|
+
* tell which kind of source failed without leaking the (potentially signed) url.
|
|
73
|
+
*/
|
|
74
|
+
export function classifyFailedSrc(currentSrc) {
|
|
75
|
+
if (!currentSrc) {
|
|
76
|
+
return 'unknown';
|
|
77
|
+
}
|
|
78
|
+
if (currentSrc.startsWith('blob:')) {
|
|
79
|
+
return 'blob';
|
|
80
|
+
}
|
|
81
|
+
if (currentSrc.startsWith('data:')) {
|
|
82
|
+
return 'data';
|
|
83
|
+
}
|
|
84
|
+
if (currentSrc.startsWith('http:') || currentSrc.startsWith('https:')) {
|
|
85
|
+
return 'remote';
|
|
86
|
+
}
|
|
87
|
+
return 'unknown';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Builds a descriptive `secondaryError` for an `<img>` onerror so the downstream
|
|
92
|
+
* `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
|
|
93
|
+
* the opaque `unknown`/`unknown`. The returned Error's `message` captures decode
|
|
94
|
+
* diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
|
|
95
|
+
* - whether the browser decoded any pixels (`naturalWidth`/`naturalHeight === 0`)
|
|
96
|
+
* - the file MIME type and whether it is natively browser-decodable
|
|
97
|
+
* - which source failed (preview blob vs. original-binary/HD url)
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* // message:
|
|
101
|
+
* "mimeType=image/png, isBrowserDecodable=true, naturalWidth=0, naturalHeight=0, failedSrcType=blob"
|
|
102
|
+
*/
|
|
103
|
+
export function buildImgErrorDiagnostics(item, event) {
|
|
104
|
+
const img = event === null || event === void 0 ? void 0 : event.currentTarget;
|
|
105
|
+
const mimeType = item && !isErrorFileState(item) ? item.mimeType : undefined;
|
|
106
|
+
const isBrowserDecodable = !!mimeType && isImageMimeTypeSupportedByBrowser(mimeType);
|
|
107
|
+
const naturalWidth = img === null || img === void 0 ? void 0 : img.naturalWidth;
|
|
108
|
+
const naturalHeight = img === null || img === void 0 ? void 0 : img.naturalHeight;
|
|
109
|
+
const failedSrcType = classifyFailedSrc(img === null || img === void 0 ? void 0 : img.currentSrc);
|
|
110
|
+
const diagnostics = {
|
|
111
|
+
mimeType,
|
|
112
|
+
isBrowserDecodable,
|
|
113
|
+
naturalWidth,
|
|
114
|
+
naturalHeight,
|
|
115
|
+
failedSrcType
|
|
116
|
+
};
|
|
117
|
+
const detail = Object.entries(diagnostics).filter(([, value]) => value !== undefined).map(([key, value]) => `${key}=${value}`).join(', ');
|
|
118
|
+
return new Error(detail);
|
|
67
119
|
}
|
package/dist/es2019/header.js
CHANGED
|
@@ -3,8 +3,9 @@ import React from 'react';
|
|
|
3
3
|
import { isImageRepresentationReady, isErrorFileState, addFileAttrsToUrl } from '@atlaskit/media-client';
|
|
4
4
|
import { isImageMimeTypeSupportedByBrowser } from '@atlaskit/media-common';
|
|
5
5
|
import { getOrientation } from '@atlaskit/media-ui';
|
|
6
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
7
|
import { Outcome } from '../../domain';
|
|
7
|
-
import { MediaViewerError } from '../../errors';
|
|
8
|
+
import { buildImgErrorDiagnostics, MediaViewerError } from '../../errors';
|
|
8
9
|
import { InteractiveImg } from './interactive-img';
|
|
9
10
|
import { BaseViewer } from '../base-viewer';
|
|
10
11
|
function processedFileStateToMediaItem(file) {
|
|
@@ -22,8 +23,14 @@ export class ImageViewer extends BaseViewer {
|
|
|
22
23
|
this.props.onLoad();
|
|
23
24
|
this.onMediaDisplayed();
|
|
24
25
|
});
|
|
25
|
-
_defineProperty(this, "onImgError",
|
|
26
|
-
|
|
26
|
+
_defineProperty(this, "onImgError", event => {
|
|
27
|
+
let secondaryError;
|
|
28
|
+
try {
|
|
29
|
+
secondaryError = buildImgErrorDiagnostics(this.props.item, event);
|
|
30
|
+
} catch {
|
|
31
|
+
secondaryError = undefined;
|
|
32
|
+
}
|
|
33
|
+
this.props.onError(new MediaViewerError('imageviewer-src-onerror', secondaryError));
|
|
27
34
|
});
|
|
28
35
|
}
|
|
29
36
|
get initialState() {
|
|
@@ -86,8 +93,22 @@ export class ImageViewer extends BaseViewer {
|
|
|
86
93
|
}
|
|
87
94
|
if (!isLocalFileReference &&
|
|
88
95
|
// objectUrl at this point is binary file already
|
|
89
|
-
!isErrorFileState(fileState) && fileState.status !== 'uploading' && fileState.mediaType === 'image'
|
|
90
|
-
|
|
96
|
+
!isErrorFileState(fileState) && fileState.status !== 'uploading' && fileState.mediaType === 'image') {
|
|
97
|
+
if (isImageMimeTypeSupportedByBrowser(fileState.mimeType)) {
|
|
98
|
+
originalBinaryImageUrl = await mediaClient.file.getFileBinaryURL(fileState.id, collectionName);
|
|
99
|
+
} else if (fg('platform_media_unsupported_mime_routing')) {
|
|
100
|
+
// Route unsupported MIME types browser can't natively decode straight to the
|
|
101
|
+
// unsupported/download view instead of handing a guaranteed-undecodable blob
|
|
102
|
+
// to <img>, which would only ever fire onerror and
|
|
103
|
+
// surface as an opaque `imageviewer-src-onerror` failure.
|
|
104
|
+
this.revokeObjectUrl(objectUrl);
|
|
105
|
+
const unsupportedError = new MediaViewerError('imageviewer-unsupported-mime');
|
|
106
|
+
this.setState({
|
|
107
|
+
content: Outcome.failed(unsupportedError)
|
|
108
|
+
});
|
|
109
|
+
this.props.onError(unsupportedError);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
91
112
|
}
|
|
92
113
|
this.setState({
|
|
93
114
|
content: Outcome.successful({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ANALYTICS_MEDIA_CHANNEL, sanitiseAnalyticsPayload } from '@atlaskit/media-common/analytics';
|
|
2
2
|
var componentName = 'mediaViewer';
|
|
3
3
|
var packageName = "@atlaskit/media-viewer";
|
|
4
|
-
var packageVersion = "54.
|
|
4
|
+
var packageVersion = "54.4.0";
|
|
5
5
|
export { packageName, packageVersion, componentName, componentName as component };
|
|
6
6
|
export function getFileAttributes(fileState) {
|
|
7
7
|
if (!fileState) {
|
|
@@ -6,7 +6,7 @@ import { getMediaEnvironment, getMediaRegion } from '@atlaskit/media-client';
|
|
|
6
6
|
import { getFeatureFlagKeysAllProducts } from '@atlaskit/media-common';
|
|
7
7
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
8
8
|
var packageName = "@atlaskit/media-viewer";
|
|
9
|
-
var packageVersion = "54.
|
|
9
|
+
var packageVersion = "54.4.0";
|
|
10
10
|
var ufoExperience;
|
|
11
11
|
var getExperience = function getExperience() {
|
|
12
12
|
if (!ufoExperience) {
|
package/dist/esm/download.js
CHANGED
|
@@ -15,6 +15,7 @@ import { createDownloadFailedEventPayload, createDownloadSucceededEventPayload }
|
|
|
15
15
|
import { fireAnalytics } from './analytics';
|
|
16
16
|
import { createFailedPreviewDownloadButtonClickedEvent } from './analytics/events/ui/failedPreviewDownloadButtonClicked';
|
|
17
17
|
import { DownloadButtonWrapper } from './styleWrappers';
|
|
18
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
18
19
|
import { MediaViewerError } from './errors';
|
|
19
20
|
import Tooltip from '@atlaskit/tooltip';
|
|
20
21
|
import { AbuseModal } from '@atlaskit/media-ui/abuseModal';
|
|
@@ -47,13 +48,14 @@ function DownloadButton(_ref) {
|
|
|
47
48
|
}
|
|
48
49
|
var createItemDownloader = function createItemDownloader(file, mediaClient, options) {
|
|
49
50
|
return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
50
|
-
var collectionName, traceContext, createAnalyticsEvent, id, name;
|
|
51
|
+
var collectionName, traceContext, createAnalyticsEvent, fallbackMediaName, id, fileStateName, name;
|
|
51
52
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
52
53
|
while (1) switch (_context.prev = _context.next) {
|
|
53
54
|
case 0:
|
|
54
|
-
collectionName = options.collectionName, traceContext = options.traceContext, createAnalyticsEvent = options.createAnalyticsEvent;
|
|
55
|
+
collectionName = options.collectionName, traceContext = options.traceContext, createAnalyticsEvent = options.createAnalyticsEvent, fallbackMediaName = options.fallbackMediaName;
|
|
55
56
|
id = file.id;
|
|
56
|
-
|
|
57
|
+
fileStateName = !isErrorFileState(file) ? file.name : undefined;
|
|
58
|
+
name = fileStateName || (expValEquals('platform_editor_media_download_fallback_name', 'isEnabled', true) ? fallbackMediaName : undefined);
|
|
57
59
|
mediaClient.file.downloadBinary(id, name, collectionName, traceContext).then(function () {
|
|
58
60
|
fireAnalytics(createDownloadSucceededEventPayload(file, traceContext), createAnalyticsEvent);
|
|
59
61
|
}).catch(function (e) {
|
|
@@ -85,7 +87,8 @@ var DownloadItem = function DownloadItem(_ref3) {
|
|
|
85
87
|
analyticspayload = _ref3.analyticspayload,
|
|
86
88
|
traceContext = _ref3.traceContext,
|
|
87
89
|
iconBefore = _ref3.iconBefore,
|
|
88
|
-
children = _ref3.children
|
|
90
|
+
children = _ref3.children,
|
|
91
|
+
fallbackMediaName = _ref3.fallbackMediaName;
|
|
89
92
|
var _useState = useState(false),
|
|
90
93
|
_useState2 = _slicedToArray(_useState, 2),
|
|
91
94
|
isAbuseModalOpen = _useState2[0],
|
|
@@ -99,7 +102,8 @@ var DownloadItem = function DownloadItem(_ref3) {
|
|
|
99
102
|
var itemDownloader = createItemDownloader(fileState, mediaClient, {
|
|
100
103
|
collectionName: collectionName,
|
|
101
104
|
createAnalyticsEvent: createAnalyticsEvent,
|
|
102
|
-
traceContext: traceContext
|
|
105
|
+
traceContext: traceContext,
|
|
106
|
+
fallbackMediaName: fallbackMediaName
|
|
103
107
|
});
|
|
104
108
|
return /*#__PURE__*/React.createElement(React.Fragment, null, shouldRenderAbuseModal && /*#__PURE__*/React.createElement(AbuseModal, {
|
|
105
109
|
isOpen: isAbuseModalOpen,
|
|
@@ -145,7 +149,8 @@ export var ToolbarDownloadButton = function ToolbarDownloadButton(_ref5) {
|
|
|
145
149
|
var state = _ref5.state,
|
|
146
150
|
mediaClient = _ref5.mediaClient,
|
|
147
151
|
identifier = _ref5.identifier,
|
|
148
|
-
traceContext = _ref5.traceContext
|
|
152
|
+
traceContext = _ref5.traceContext,
|
|
153
|
+
fallbackMediaName = _ref5.fallbackMediaName;
|
|
149
154
|
// TODO [MS-1731]: make it work for external files as well
|
|
150
155
|
if (isExternalImageIdentifier(identifier)) {
|
|
151
156
|
return null;
|
|
@@ -159,7 +164,8 @@ export var ToolbarDownloadButton = function ToolbarDownloadButton(_ref5) {
|
|
|
159
164
|
mediaClient: mediaClient,
|
|
160
165
|
collectionName: identifier.collectionName,
|
|
161
166
|
traceContext: traceContext,
|
|
162
|
-
iconBefore: downloadIcon
|
|
167
|
+
iconBefore: downloadIcon,
|
|
168
|
+
fallbackMediaName: fallbackMediaName
|
|
163
169
|
});
|
|
164
170
|
};
|
|
165
171
|
export var DisabledToolbarDownloadButton = /*#__PURE__*/React.createElement(MediaButton, {
|
package/dist/esm/errorMessage.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
1
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
3
2
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
4
3
|
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
|
|
5
4
|
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
|
|
6
5
|
import _inherits from "@babel/runtime/helpers/inherits";
|
|
6
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
7
7
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
8
8
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9
9
|
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
|
|
@@ -44,11 +44,12 @@ export var ErrorMessage = /*#__PURE__*/function (_React$Component) {
|
|
|
44
44
|
var _this$props = this.props,
|
|
45
45
|
formatMessage = _this$props.intl.formatMessage,
|
|
46
46
|
error = _this$props.error;
|
|
47
|
-
// Non-ZIP archives (e.g. RAR, TAR, 7z)
|
|
47
|
+
// Non-ZIP archives (e.g. RAR, TAR, 7z) and image MIME types that no browser
|
|
48
|
+
// can natively decode (e.g. HEIC/HEIF, PSD, TIFF) aren't load failures - the
|
|
48
49
|
// browser-based viewer simply can't preview them. Show a dedicated
|
|
49
50
|
// "Unsupported file format" heading instead of the generic
|
|
50
51
|
// "Something went wrong" copy.
|
|
51
|
-
if (getPrimaryErrorReason(error) === 'archiveviewer-not-zip') {
|
|
52
|
+
if (getPrimaryErrorReason(error) === 'archiveviewer-not-zip' || getPrimaryErrorReason(error) === 'imageviewer-unsupported-mime') {
|
|
52
53
|
return {
|
|
53
54
|
icon: errorLoadingFileImage(formatMessage),
|
|
54
55
|
messages: [i18nMessages.unsupported_file_format, i18nMessages.archive_format_not_supported]
|
|
@@ -88,6 +89,10 @@ export var ErrorMessage = /*#__PURE__*/function (_React$Component) {
|
|
|
88
89
|
failMediaFileUfoExperience(failMediaFileUfoExperiencePayload);
|
|
89
90
|
}
|
|
90
91
|
}
|
|
92
|
+
|
|
93
|
+
// Error reasons that represent a format the browser-based viewer simply can't
|
|
94
|
+
// preview (not a load failure). These are reported as the informational,
|
|
95
|
+
// non-SLI `previewUnsupported` metric instead of `loadFailed`.
|
|
91
96
|
}, {
|
|
92
97
|
key: "render",
|
|
93
98
|
value: function render() {
|
|
@@ -105,10 +110,16 @@ export var ErrorMessage = /*#__PURE__*/function (_React$Component) {
|
|
|
105
110
|
})), this.props.children);
|
|
106
111
|
}
|
|
107
112
|
}], [{
|
|
113
|
+
key: "isPreviewUnsupported",
|
|
114
|
+
value: function isPreviewUnsupported(error) {
|
|
115
|
+
return ErrorMessage.previewUnsupportedReasons.includes(getPrimaryErrorReason(error));
|
|
116
|
+
}
|
|
117
|
+
}, {
|
|
108
118
|
key: "getEventPayload",
|
|
109
119
|
value: function getEventPayload(error, fileId, fileState, traceContext) {
|
|
110
|
-
if (fileState &&
|
|
111
|
-
// this is not an SLI, its just a useful metric for
|
|
120
|
+
if (fileState && ErrorMessage.isPreviewUnsupported(error)) {
|
|
121
|
+
// this is not an SLI (load failure), its just a useful metric for files
|
|
122
|
+
// whose format the browser-based viewer can't preview.
|
|
112
123
|
return createPreviewUnsupportedEvent(fileState);
|
|
113
124
|
} else {
|
|
114
125
|
return createLoadFailedEvent(fileId, error, fileState, traceContext);
|
|
@@ -118,5 +129,6 @@ export var ErrorMessage = /*#__PURE__*/function (_React$Component) {
|
|
|
118
129
|
}(React.Component);
|
|
119
130
|
|
|
120
131
|
// @ts-ignore: [PIT-1685] Fails in post-office due to backwards incompatibility issue with React 18
|
|
132
|
+
_defineProperty(ErrorMessage, "previewUnsupportedReasons", ['unsupported', 'imageviewer-unsupported-mime']);
|
|
121
133
|
var ErroMsg = withAnalyticsEvents()(injectIntl(ErrorMessage));
|
|
122
134
|
export default ErroMsg;
|
package/dist/esm/errors.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
1
2
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
2
3
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
3
4
|
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
|
|
@@ -6,7 +7,8 @@ import _inherits from "@babel/runtime/helpers/inherits";
|
|
|
6
7
|
import _wrapNativeSuper from "@babel/runtime/helpers/wrapNativeSuper";
|
|
7
8
|
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
|
|
8
9
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
9
|
-
import { isCommonMediaClientError } from '@atlaskit/media-client';
|
|
10
|
+
import { isCommonMediaClientError, isErrorFileState } from '@atlaskit/media-client';
|
|
11
|
+
import { isImageMimeTypeSupportedByBrowser } from '@atlaskit/media-common/isMimeTypeSupportedByBrowser';
|
|
10
12
|
export var MediaViewerError = /*#__PURE__*/function (_Error) {
|
|
11
13
|
function MediaViewerError(primaryReason, secondaryError) {
|
|
12
14
|
var _this;
|
|
@@ -78,4 +80,64 @@ export function getRequestMetadata(error) {
|
|
|
78
80
|
if (isCommonMediaClientError(secondaryError)) {
|
|
79
81
|
return secondaryError.metadata;
|
|
80
82
|
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Classifies the failed `<img>` source into a coarse, non-sensitive enum so we can
|
|
87
|
+
* tell which kind of source failed without leaking the (potentially signed) url.
|
|
88
|
+
*/
|
|
89
|
+
export function classifyFailedSrc(currentSrc) {
|
|
90
|
+
if (!currentSrc) {
|
|
91
|
+
return 'unknown';
|
|
92
|
+
}
|
|
93
|
+
if (currentSrc.startsWith('blob:')) {
|
|
94
|
+
return 'blob';
|
|
95
|
+
}
|
|
96
|
+
if (currentSrc.startsWith('data:')) {
|
|
97
|
+
return 'data';
|
|
98
|
+
}
|
|
99
|
+
if (currentSrc.startsWith('http:') || currentSrc.startsWith('https:')) {
|
|
100
|
+
return 'remote';
|
|
101
|
+
}
|
|
102
|
+
return 'unknown';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Builds a descriptive `secondaryError` for an `<img>` onerror so the downstream
|
|
107
|
+
* `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
|
|
108
|
+
* the opaque `unknown`/`unknown`. The returned Error's `message` captures decode
|
|
109
|
+
* diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
|
|
110
|
+
* - whether the browser decoded any pixels (`naturalWidth`/`naturalHeight === 0`)
|
|
111
|
+
* - the file MIME type and whether it is natively browser-decodable
|
|
112
|
+
* - which source failed (preview blob vs. original-binary/HD url)
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // message:
|
|
116
|
+
* "mimeType=image/png, isBrowserDecodable=true, naturalWidth=0, naturalHeight=0, failedSrcType=blob"
|
|
117
|
+
*/
|
|
118
|
+
export function buildImgErrorDiagnostics(item, event) {
|
|
119
|
+
var img = event === null || event === void 0 ? void 0 : event.currentTarget;
|
|
120
|
+
var mimeType = item && !isErrorFileState(item) ? item.mimeType : undefined;
|
|
121
|
+
var isBrowserDecodable = !!mimeType && isImageMimeTypeSupportedByBrowser(mimeType);
|
|
122
|
+
var naturalWidth = img === null || img === void 0 ? void 0 : img.naturalWidth;
|
|
123
|
+
var naturalHeight = img === null || img === void 0 ? void 0 : img.naturalHeight;
|
|
124
|
+
var failedSrcType = classifyFailedSrc(img === null || img === void 0 ? void 0 : img.currentSrc);
|
|
125
|
+
var diagnostics = {
|
|
126
|
+
mimeType: mimeType,
|
|
127
|
+
isBrowserDecodable: isBrowserDecodable,
|
|
128
|
+
naturalWidth: naturalWidth,
|
|
129
|
+
naturalHeight: naturalHeight,
|
|
130
|
+
failedSrcType: failedSrcType
|
|
131
|
+
};
|
|
132
|
+
var detail = Object.entries(diagnostics).filter(function (_ref3) {
|
|
133
|
+
var _ref4 = _slicedToArray(_ref3, 2),
|
|
134
|
+
value = _ref4[1];
|
|
135
|
+
return value !== undefined;
|
|
136
|
+
}).map(function (_ref5) {
|
|
137
|
+
var _ref6 = _slicedToArray(_ref5, 2),
|
|
138
|
+
key = _ref6[0],
|
|
139
|
+
value = _ref6[1];
|
|
140
|
+
return "".concat(key, "=").concat(value);
|
|
141
|
+
}).join(', ');
|
|
142
|
+
return new Error(detail);
|
|
81
143
|
}
|
package/dist/esm/header.js
CHANGED
|
@@ -12,8 +12,9 @@ import React from 'react';
|
|
|
12
12
|
import { isImageRepresentationReady, isErrorFileState, addFileAttrsToUrl } from '@atlaskit/media-client';
|
|
13
13
|
import { isImageMimeTypeSupportedByBrowser } from '@atlaskit/media-common';
|
|
14
14
|
import { getOrientation } from '@atlaskit/media-ui';
|
|
15
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
15
16
|
import { Outcome } from '../../domain';
|
|
16
|
-
import { MediaViewerError } from '../../errors';
|
|
17
|
+
import { buildImgErrorDiagnostics, MediaViewerError } from '../../errors';
|
|
17
18
|
import { InteractiveImg } from './interactive-img';
|
|
18
19
|
import { BaseViewer } from '../base-viewer';
|
|
19
20
|
function processedFileStateToMediaItem(file) {
|
|
@@ -36,8 +37,14 @@ export var ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
36
37
|
_this.props.onLoad();
|
|
37
38
|
_this.onMediaDisplayed();
|
|
38
39
|
});
|
|
39
|
-
_defineProperty(_this, "onImgError", function () {
|
|
40
|
-
|
|
40
|
+
_defineProperty(_this, "onImgError", function (event) {
|
|
41
|
+
var secondaryError;
|
|
42
|
+
try {
|
|
43
|
+
secondaryError = buildImgErrorDiagnostics(_this.props.item, event);
|
|
44
|
+
} catch (_unused) {
|
|
45
|
+
secondaryError = undefined;
|
|
46
|
+
}
|
|
47
|
+
_this.props.onError(new MediaViewerError('imageviewer-src-onerror', secondaryError));
|
|
41
48
|
});
|
|
42
49
|
return _this;
|
|
43
50
|
}
|
|
@@ -53,7 +60,7 @@ export var ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
53
60
|
key: "init",
|
|
54
61
|
value: function () {
|
|
55
62
|
var _init = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
56
|
-
var _this$props, fileState, mediaClient, collectionName, traceContext, controller, orientation, objectUrl, originalBinaryImageUrl, isLocalFileReference, clientId, preview, _yield$preview, value, origin, item, response, imgError, _t, _t2, _t3;
|
|
63
|
+
var _this$props, fileState, mediaClient, collectionName, traceContext, controller, orientation, objectUrl, originalBinaryImageUrl, isLocalFileReference, clientId, preview, _yield$preview, value, origin, item, response, unsupportedError, imgError, _t, _t2, _t3;
|
|
57
64
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
58
65
|
while (1) switch (_context.prev = _context.next) {
|
|
59
66
|
case 0:
|
|
@@ -135,7 +142,11 @@ export var ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
135
142
|
case 14:
|
|
136
143
|
if (!(!isLocalFileReference &&
|
|
137
144
|
// objectUrl at this point is binary file already
|
|
138
|
-
!isErrorFileState(fileState) && fileState.status !== 'uploading' && fileState.mediaType === 'image'
|
|
145
|
+
!isErrorFileState(fileState) && fileState.status !== 'uploading' && fileState.mediaType === 'image')) {
|
|
146
|
+
_context.next = 17;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
if (!isImageMimeTypeSupportedByBrowser(fileState.mimeType)) {
|
|
139
150
|
_context.next = 16;
|
|
140
151
|
break;
|
|
141
152
|
}
|
|
@@ -143,7 +154,25 @@ export var ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
143
154
|
return mediaClient.file.getFileBinaryURL(fileState.id, collectionName);
|
|
144
155
|
case 15:
|
|
145
156
|
originalBinaryImageUrl = _context.sent;
|
|
157
|
+
_context.next = 17;
|
|
158
|
+
break;
|
|
146
159
|
case 16:
|
|
160
|
+
if (!fg('platform_media_unsupported_mime_routing')) {
|
|
161
|
+
_context.next = 17;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
// Route unsupported MIME types browser can't natively decode straight to the
|
|
165
|
+
// unsupported/download view instead of handing a guaranteed-undecodable blob
|
|
166
|
+
// to <img>, which would only ever fire onerror and
|
|
167
|
+
// surface as an opaque `imageviewer-src-onerror` failure.
|
|
168
|
+
this.revokeObjectUrl(objectUrl);
|
|
169
|
+
unsupportedError = new MediaViewerError('imageviewer-unsupported-mime');
|
|
170
|
+
this.setState({
|
|
171
|
+
content: Outcome.failed(unsupportedError)
|
|
172
|
+
});
|
|
173
|
+
this.props.onError(unsupportedError);
|
|
174
|
+
return _context.abrupt("return");
|
|
175
|
+
case 17:
|
|
147
176
|
this.setState({
|
|
148
177
|
content: Outcome.successful({
|
|
149
178
|
objectUrl: objectUrl,
|
|
@@ -152,10 +181,10 @@ export var ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
152
181
|
clientId: clientId
|
|
153
182
|
})
|
|
154
183
|
});
|
|
155
|
-
_context.next =
|
|
184
|
+
_context.next = 19;
|
|
156
185
|
break;
|
|
157
|
-
case
|
|
158
|
-
_context.prev =
|
|
186
|
+
case 18:
|
|
187
|
+
_context.prev = 18;
|
|
159
188
|
_t3 = _context["catch"](2);
|
|
160
189
|
// TODO : properly handle aborted requests (MS-2843)
|
|
161
190
|
if (!(controller !== null && controller !== void 0 && controller.signal.aborted)) {
|
|
@@ -165,11 +194,11 @@ export var ImageViewer = /*#__PURE__*/function (_BaseViewer) {
|
|
|
165
194
|
});
|
|
166
195
|
this.props.onError(imgError);
|
|
167
196
|
}
|
|
168
|
-
case
|
|
197
|
+
case 19:
|
|
169
198
|
case "end":
|
|
170
199
|
return _context.stop();
|
|
171
200
|
}
|
|
172
|
-
}, _callee, this, [[2,
|
|
201
|
+
}, _callee, this, [[2, 18], [3, 5]]);
|
|
173
202
|
}));
|
|
174
203
|
function init() {
|
|
175
204
|
return _init.apply(this, arguments);
|
package/dist/types/download.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type ToolbarDownloadButtonProps = {
|
|
|
15
15
|
identifier: Identifier;
|
|
16
16
|
mediaClient: MediaClient;
|
|
17
17
|
traceContext: MediaTraceContext;
|
|
18
|
+
fallbackMediaName?: string;
|
|
18
19
|
};
|
|
19
|
-
export declare const ToolbarDownloadButton: ({ state, mediaClient, identifier, traceContext, }: ToolbarDownloadButtonProps) => React.JSX.Element | null;
|
|
20
|
+
export declare const ToolbarDownloadButton: ({ state, mediaClient, identifier, traceContext, fallbackMediaName, }: ToolbarDownloadButtonProps) => React.JSX.Element | null;
|
|
20
21
|
export declare const DisabledToolbarDownloadButton: React.JSX.Element;
|
|
@@ -26,6 +26,8 @@ export declare const getErrorMessageFromError: (error: MediaViewerError) => Mess
|
|
|
26
26
|
export declare class ErrorMessage extends React.Component<Props & WrappedComponentProps & WithAnalyticsEventsProps, {}> {
|
|
27
27
|
private getErrorInfo;
|
|
28
28
|
componentDidMount(): void;
|
|
29
|
+
private static readonly previewUnsupportedReasons;
|
|
30
|
+
static isPreviewUnsupported(error: MediaViewerError): boolean;
|
|
29
31
|
static getEventPayload(error: MediaViewerError, fileId: string, fileState?: FileState, traceContext?: MediaTraceContext): PreviewUnsupportedEventPayload | LoadFailedEventPayload;
|
|
30
32
|
render(): React.JSX.Element;
|
|
31
33
|
}
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type SyntheticEvent } from 'react';
|
|
2
|
+
import { type FileState, type MediaClientErrorReason, type RequestErrorMetadata } from '@atlaskit/media-client';
|
|
2
3
|
import { type ZipEntry } from 'unzipit';
|
|
3
4
|
export declare class MediaViewerError extends Error {
|
|
4
5
|
readonly primaryReason: MediaViewerErrorReason | ArchiveViewerErrorReason;
|
|
@@ -13,7 +14,8 @@ export declare class ArchiveViewerError extends MediaViewerError {
|
|
|
13
14
|
constructor(primaryReason: ArchiveViewerErrorReason, secondaryError?: Error | undefined, zipEntry?: ZipEntry | undefined);
|
|
14
15
|
}
|
|
15
16
|
export declare function isArchiveViewerError(err: Error): err is ArchiveViewerError;
|
|
16
|
-
|
|
17
|
+
type srcType = 'blob' | 'remote' | 'data' | 'unknown';
|
|
18
|
+
export type MediaViewerErrorReason = 'collection-fetch-metadata' | 'header-fetch-metadata' | 'itemviewer-onerror' | 'itemviewer-fetch-metadata' | 'itemviewer-file-error-status' | 'itemviewer-file-failed-processing-status' | 'imageviewer-external-onerror' | 'imageviewer-fetch-url' | 'imageviewer-src-onerror' | 'imageviewer-unsupported-mime' | 'audioviewer-fetch-url' | 'audioviewer-missing-artefact' | 'audioviewer-playback' | 'videoviewer-fetch-url' | 'videoviewer-missing-artefact' | 'videoviewer-playback' | 'docviewer-fetch-url' | 'docviewer-content-fetch-failed' | 'docviewer-fetch-pdf' | 'codeviewer-fetch-src' | 'codeviewer-load-src' | 'codeviewer-file-size-exceeds' | 'codeviewer-parse-email' | 'svg-img-error' | 'svg-binary-fetch' | 'svg-unknown-error' | 'svg-blob-to-datauri' | 'unsupported' | 'custom-viewer-error' | 'download';
|
|
17
19
|
export type ArchiveViewerErrorReason = 'archiveviewer-bundle-loader' | 'archiveviewer-read-binary' | 'archiveviewer-not-zip' | 'archiveviewer-create-url' | 'archiveviewer-imageviewer-onerror' | 'archiveviewer-videoviewer-onerror' | 'archiveviewer-audioviewer-onerror' | 'archiveviewer-docviewer-onerror' | 'archiveviewer-codeviewer-onerror' | 'archiveviewer-codeviewer-file-size-exceeds' | 'archiveviewer-missing-name-src' | 'archiveviewer-unsupported' | 'archiveviewer-encrypted-entry' | 'archiveviewer-customrenderer-onerror';
|
|
18
20
|
export type PrimaryErrorReason = MediaViewerErrorReason | ArchiveViewerErrorReason;
|
|
19
21
|
export type SecondaryErrorReason = MediaClientErrorReason | 'unknown' | 'nativeError' | undefined;
|
|
@@ -21,3 +23,23 @@ export declare function getPrimaryErrorReason(error: MediaViewerError): PrimaryE
|
|
|
21
23
|
export declare function getSecondaryErrorReason(error: MediaViewerError): SecondaryErrorReason;
|
|
22
24
|
export declare function getErrorDetail(error?: MediaViewerError): string;
|
|
23
25
|
export declare function getRequestMetadata(error?: MediaViewerError): RequestErrorMetadata | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Classifies the failed `<img>` source into a coarse, non-sensitive enum so we can
|
|
28
|
+
* tell which kind of source failed without leaking the (potentially signed) url.
|
|
29
|
+
*/
|
|
30
|
+
export declare function classifyFailedSrc(currentSrc?: string): srcType;
|
|
31
|
+
/**
|
|
32
|
+
* Builds a descriptive `secondaryError` for an `<img>` onerror so the downstream
|
|
33
|
+
* `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
|
|
34
|
+
* the opaque `unknown`/`unknown`. The returned Error's `message` captures decode
|
|
35
|
+
* diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
|
|
36
|
+
* - whether the browser decoded any pixels (`naturalWidth`/`naturalHeight === 0`)
|
|
37
|
+
* - the file MIME type and whether it is natively browser-decodable
|
|
38
|
+
* - which source failed (preview blob vs. original-binary/HD url)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // message:
|
|
42
|
+
* "mimeType=image/png, isBrowserDecodable=true, naturalWidth=0, naturalHeight=0, failedSrcType=blob"
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildImgErrorDiagnostics(item: FileState | undefined, event?: SyntheticEvent<HTMLImageElement, Event>): Error;
|
|
45
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/media-viewer",
|
|
3
|
-
"version": "54.
|
|
3
|
+
"version": "54.4.0",
|
|
4
4
|
"description": "MediaViewer is Atlassian's powerful solution for viewing files on the web. It's both powerful and extendable yet easy-to-integrate",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
"module": "dist/esm/index.js",
|
|
13
13
|
"module:es2019": "dist/es2019/index.js",
|
|
14
14
|
"types": "dist/types/index.d.ts",
|
|
15
|
-
"sideEffects": [
|
|
16
|
-
"*.compiled.css"
|
|
17
|
-
],
|
|
15
|
+
"sideEffects": ["*.compiled.css"],
|
|
18
16
|
"atlaskit:src": "src/index.ts",
|
|
19
17
|
"atlassian": {
|
|
20
18
|
"react-compiler": {
|
|
@@ -41,20 +39,20 @@
|
|
|
41
39
|
"@atlaskit/icon-lab": "^7.3.0",
|
|
42
40
|
"@atlaskit/media-client": "^37.2.0",
|
|
43
41
|
"@atlaskit/media-client-react": "^6.1.0",
|
|
44
|
-
"@atlaskit/media-common": "^14.
|
|
42
|
+
"@atlaskit/media-common": "^14.3.0",
|
|
45
43
|
"@atlaskit/media-document-viewer": "^1.1.0",
|
|
46
44
|
"@atlaskit/media-state": "^3.0.0",
|
|
47
45
|
"@atlaskit/media-svg": "^3.1.0",
|
|
48
|
-
"@atlaskit/media-ui": "^30.
|
|
46
|
+
"@atlaskit/media-ui": "^30.6.0",
|
|
49
47
|
"@atlaskit/platform-feature-flags": "^2.0.0",
|
|
50
48
|
"@atlaskit/portal": "^6.1.0",
|
|
51
|
-
"@atlaskit/primitives": "^20.
|
|
49
|
+
"@atlaskit/primitives": "^20.4.0",
|
|
52
50
|
"@atlaskit/react-compiler-gating": "^0.2.0",
|
|
53
51
|
"@atlaskit/side-navigation": "^12.2.0",
|
|
54
52
|
"@atlaskit/spinner": "^20.1.0",
|
|
55
53
|
"@atlaskit/textfield": "^9.1.0",
|
|
56
54
|
"@atlaskit/theme": "^26.1.0",
|
|
57
|
-
"@atlaskit/tmp-editor-statsig": "^121.
|
|
55
|
+
"@atlaskit/tmp-editor-statsig": "^121.3.0",
|
|
58
56
|
"@atlaskit/tokens": "^15.4.0",
|
|
59
57
|
"@atlaskit/tooltip": "^23.1.0",
|
|
60
58
|
"@atlaskit/ufo": "^1.0.0",
|
|
@@ -89,12 +87,12 @@
|
|
|
89
87
|
"@atlaskit/media-core": "^38.0.0",
|
|
90
88
|
"@atlaskit/media-integration-test-helpers": "workspace:^",
|
|
91
89
|
"@atlaskit/media-test-data": "^4.0.0",
|
|
92
|
-
"@atlaskit/media-test-helpers": "^42.
|
|
90
|
+
"@atlaskit/media-test-helpers": "^42.2.0",
|
|
93
91
|
"@atlaskit/ssr": "workspace:^",
|
|
94
92
|
"@atlaskit/toggle": "^17.1.0",
|
|
95
93
|
"@atlassian/a11y-jest-testing": "^0.13.0",
|
|
96
94
|
"@atlassian/feature-flags-test-utils": "^1.1.0",
|
|
97
|
-
"@atlassian/testing-library": "^0.
|
|
95
|
+
"@atlassian/testing-library": "^0.10.0",
|
|
98
96
|
"@atlassian/ufo": "^0.8.0",
|
|
99
97
|
"@testing-library/dom": "^10.1.0",
|
|
100
98
|
"@testing-library/react": "^16.3.0",
|
|
@@ -143,14 +141,14 @@
|
|
|
143
141
|
},
|
|
144
142
|
"platform_media_archive_zip_guard": {
|
|
145
143
|
"type": "boolean"
|
|
144
|
+
},
|
|
145
|
+
"platform_media_unsupported_mime_routing": {
|
|
146
|
+
"type": "boolean"
|
|
146
147
|
}
|
|
147
148
|
},
|
|
148
149
|
"techstack": {
|
|
149
150
|
"@repo/internal": {
|
|
150
|
-
"design-tokens": [
|
|
151
|
-
"color",
|
|
152
|
-
"spacing"
|
|
153
|
-
]
|
|
151
|
+
"design-tokens": ["color", "spacing"]
|
|
154
152
|
}
|
|
155
153
|
}
|
|
156
154
|
}
|