@atlaskit/media-card 74.3.2 → 74.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 (58) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/card/card.js +27 -18
  3. package/dist/cjs/card/cardAnalytics.js +16 -5
  4. package/dist/cjs/card/cardLoader.js +12 -3
  5. package/dist/cjs/card/cardState.js +11 -13
  6. package/dist/cjs/card/media-card-analytics-error-boundary.js +129 -0
  7. package/dist/cjs/card/ui/unhandledErrorCard/index.js +114 -0
  8. package/dist/cjs/card/ui/unhandledErrorCard/types.js +5 -0
  9. package/dist/cjs/errors.js +12 -3
  10. package/dist/cjs/inline/loader.js +4 -4
  11. package/dist/cjs/inline/mediaInlineAnalyticsErrorBoundary.js +113 -0
  12. package/dist/cjs/utils/analytics.js +41 -10
  13. package/dist/cjs/utils/ufoExperiences.js +1 -1
  14. package/dist/cjs/version.json +1 -1
  15. package/dist/es2019/card/card.js +29 -17
  16. package/dist/es2019/card/cardAnalytics.js +9 -5
  17. package/dist/es2019/card/cardLoader.js +12 -3
  18. package/dist/es2019/card/cardState.js +12 -7
  19. package/dist/es2019/card/media-card-analytics-error-boundary.js +90 -0
  20. package/dist/es2019/card/ui/unhandledErrorCard/index.js +80 -0
  21. package/dist/es2019/card/ui/unhandledErrorCard/types.js +1 -0
  22. package/dist/es2019/errors.js +13 -2
  23. package/dist/es2019/inline/loader.js +4 -4
  24. package/dist/es2019/inline/mediaInlineAnalyticsErrorBoundary.js +75 -0
  25. package/dist/es2019/utils/analytics.js +32 -9
  26. package/dist/es2019/utils/ufoExperiences.js +1 -1
  27. package/dist/es2019/version.json +1 -1
  28. package/dist/esm/card/card.js +28 -19
  29. package/dist/esm/card/cardAnalytics.js +12 -4
  30. package/dist/esm/card/cardLoader.js +12 -3
  31. package/dist/esm/card/cardState.js +12 -11
  32. package/dist/esm/card/media-card-analytics-error-boundary.js +115 -0
  33. package/dist/esm/card/ui/unhandledErrorCard/index.js +94 -0
  34. package/dist/esm/card/ui/unhandledErrorCard/types.js +1 -0
  35. package/dist/esm/errors.js +12 -3
  36. package/dist/esm/inline/loader.js +5 -5
  37. package/dist/esm/inline/mediaInlineAnalyticsErrorBoundary.js +99 -0
  38. package/dist/esm/utils/analytics.js +34 -9
  39. package/dist/esm/utils/ufoExperiences.js +1 -1
  40. package/dist/esm/version.json +1 -1
  41. package/dist/types/card/card.d.ts +1 -1
  42. package/dist/types/card/cardAnalytics.d.ts +2 -1
  43. package/dist/types/card/cardState.d.ts +6 -1
  44. package/dist/types/card/getCardPreview/index.d.ts +1 -1
  45. package/dist/types/card/media-card-analytics-error-boundary.d.ts +14 -0
  46. package/dist/types/card/ui/unhandledErrorCard/index.d.ts +7 -0
  47. package/dist/types/card/ui/unhandledErrorCard/types.d.ts +6 -0
  48. package/dist/types/errors.d.ts +2 -2
  49. package/dist/types/inline/mediaInlineAnalyticsErrorBoundary.d.ts +11 -0
  50. package/dist/types/types.d.ts +3 -0
  51. package/dist/types/utils/analytics.d.ts +26 -6
  52. package/example-helpers/styles.ts +13 -0
  53. package/package.json +9 -8
  54. package/report.api.md +2 -2
  55. package/dist/cjs/utils/media-card-analytics-error-boundary.js +0 -59
  56. package/dist/es2019/utils/media-card-analytics-error-boundary.js +0 -19
  57. package/dist/esm/utils/media-card-analytics-error-boundary.js +0 -46
  58. package/dist/types/utils/media-card-analytics-error-boundary.d.ts +0 -10
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+
12
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
13
+
14
+ var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
15
+
16
+ var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
17
+
18
+ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
19
+
20
+ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
21
+
22
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
23
+
24
+ var _react = _interopRequireDefault(require("react"));
25
+
26
+ var _mediaCommon = require("@atlaskit/media-common");
27
+
28
+ var _analyticsNext = require("@atlaskit/analytics-next");
29
+
30
+ var _analytics = require("../utils/analytics");
31
+
32
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
33
+
34
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
35
+
36
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
37
+
38
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
39
+
40
+ var WrappedMediaInlineAnalyticsErrorBoundary = /*#__PURE__*/function (_React$Component) {
41
+ (0, _inherits2.default)(WrappedMediaInlineAnalyticsErrorBoundary, _React$Component);
42
+
43
+ var _super = _createSuper(WrappedMediaInlineAnalyticsErrorBoundary);
44
+
45
+ function WrappedMediaInlineAnalyticsErrorBoundary(props) {
46
+ var _this;
47
+
48
+ (0, _classCallCheck2.default)(this, WrappedMediaInlineAnalyticsErrorBoundary);
49
+ _this = _super.call(this, props);
50
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "fireOperationalEvent", function (error, info) {
51
+ var _window, _window$navigator;
52
+
53
+ var _this$props = _this.props,
54
+ _this$props$data = _this$props.data,
55
+ data = _this$props$data === void 0 ? {} : _this$props$data,
56
+ createAnalyticsEvent = _this$props.createAnalyticsEvent;
57
+ var payload = {
58
+ eventType: 'operational',
59
+ action: 'failed',
60
+ actionSubject: 'mediaInlineRender',
61
+ attributes: _objectSpread({
62
+ browserInfo: (_window = window) !== null && _window !== void 0 && (_window$navigator = _window.navigator) !== null && _window$navigator !== void 0 && _window$navigator.userAgent ? window.navigator.userAgent : 'unknown',
63
+ error: error,
64
+ failReason: 'unexpected-error',
65
+ info: info
66
+ }, data)
67
+ };
68
+ (0, _analytics.fireMediaCardEvent)(payload, createAnalyticsEvent);
69
+ });
70
+ _this.state = {
71
+ hasError: false
72
+ };
73
+ return _this;
74
+ }
75
+
76
+ (0, _createClass2.default)(WrappedMediaInlineAnalyticsErrorBoundary, [{
77
+ key: "componentDidCatch",
78
+ value: function componentDidCatch(error, info) {
79
+ try {
80
+ this.fireOperationalEvent(error, info);
81
+ this.setState({
82
+ hasError: true
83
+ });
84
+ } catch (e) {}
85
+ }
86
+ }, {
87
+ key: "render",
88
+ value: function render() {
89
+ var hasError = this.state.hasError;
90
+ var children = this.props.children;
91
+
92
+ if (hasError) {
93
+ // TODO refactor error boundary for inline card https://product-fabric.atlassian.net/browse/MEX-2140
94
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null);
95
+ }
96
+
97
+ return children;
98
+ }
99
+ }]);
100
+ return WrappedMediaInlineAnalyticsErrorBoundary;
101
+ }(_react.default.Component);
102
+
103
+ (0, _defineProperty2.default)(WrappedMediaInlineAnalyticsErrorBoundary, "displayName", 'MediaInlineAnalyticsErrorBoundary');
104
+ var packageName = "@atlaskit/media-card";
105
+ var packageVersion = "74.4.0";
106
+ var MediaInlineAnalyticsErrorBoundary = (0, _mediaCommon.withMediaAnalyticsContext)({
107
+ packageVersion: packageVersion,
108
+ packageName: packageName,
109
+ componentName: 'mediaInlineCard',
110
+ component: 'mediaInlineCard'
111
+ })((0, _analyticsNext.withAnalyticsEvents)()(WrappedMediaInlineAnalyticsErrorBoundary));
112
+ var _default = MediaInlineAnalyticsErrorBoundary;
113
+ exports.default = _default;
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  });
8
8
  exports.extractErrorInfo = exports.createAndFireMediaCardEvent = exports.LOGGED_FEATURE_FLAG_KEYS = exports.LOGGED_FEATURE_FLAGS = void 0;
9
9
  exports.fireMediaCardEvent = fireMediaCardEvent;
10
- exports.getRenderSucceededEventPayload = exports.getRenderPreviewableCardPayload = exports.getRenderFailedFileStatusPayload = exports.getRenderFailedExternalUriPayload = exports.getRenderErrorRequestMetadata = exports.getRenderErrorFailReason = exports.getRenderErrorEventPayload = exports.getRenderErrorErrorReason = exports.getRenderErrorErrorDetail = exports.getRenderCommencedEventPayload = exports.getRemoteSuccessEventPayload = exports.getFileAttributes = exports.getCopiedFilePayload = exports.getCacheHitEventPayload = void 0;
10
+ exports.getRenderSucceededEventPayload = exports.getRenderPreviewableCardPayload = exports.getRenderFailedFileStatusPayload = exports.getRenderFailedExternalUriPayload = exports.getRenderErrorRequestMetadata = exports.getRenderErrorFailReason = exports.getRenderErrorEventPayload = exports.getRenderErrorErrorReason = exports.getRenderErrorErrorDetail = exports.getRenderCommencedEventPayload = exports.getRemoteSuccessEventPayload = exports.getFileAttributes = exports.getErrorTraceContext = exports.getErrorEventPayload = exports.getCopiedFilePayload = exports.getCacheHitEventPayload = void 0;
11
11
 
12
12
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
13
 
@@ -30,7 +30,6 @@ var relevantFlags = {
30
30
  observedWidth: true,
31
31
  mediaInline: false,
32
32
  folderUploads: false,
33
- mediaUploadApiV2: true,
34
33
  memoryCacheLogging: true
35
34
  };
36
35
  var LOGGED_FEATURE_FLAGS = (0, _mediaCommon.filterFeatureFlagNames)(relevantFlags);
@@ -82,7 +81,7 @@ var getRenderCommencedEventPayload = function getRenderCommencedEventPayload(fil
82
81
 
83
82
  exports.getRenderCommencedEventPayload = getRenderCommencedEventPayload;
84
83
 
85
- var getRenderSucceededEventPayload = function getRenderSucceededEventPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext) {
84
+ var getRenderSucceededEventPayload = function getRenderSucceededEventPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext, metadataTraceContext) {
86
85
  return {
87
86
  eventType: 'operational',
88
87
  action: 'succeeded',
@@ -92,7 +91,8 @@ var getRenderSucceededEventPayload = function getRenderSucceededEventPayload(fil
92
91
  performanceAttributes: performanceAttributes,
93
92
  status: 'success',
94
93
  ssrReliability: ssrReliability,
95
- traceContext: traceContext
94
+ traceContext: traceContext,
95
+ metadataTraceContext: metadataTraceContext
96
96
  }
97
97
  };
98
98
  };
@@ -175,6 +175,16 @@ var getRenderErrorErrorDetail = function getRenderErrorErrorDetail(error) {
175
175
 
176
176
  exports.getRenderErrorErrorDetail = getRenderErrorErrorDetail;
177
177
 
178
+ var getErrorTraceContext = function getErrorTraceContext(error) {
179
+ if ((0, _errors.isMediaCardError)(error) && !!error.secondaryError && (0, _mediaClient.isRequestError)(error.secondaryError)) {
180
+ var _error$secondaryError;
181
+
182
+ return (_error$secondaryError = error.secondaryError.metadata) === null || _error$secondaryError === void 0 ? void 0 : _error$secondaryError.traceContext;
183
+ }
184
+ };
185
+
186
+ exports.getErrorTraceContext = getErrorTraceContext;
187
+
178
188
  var getRenderErrorRequestMetadata = function getRenderErrorRequestMetadata(error) {
179
189
  if ((0, _errors.isMediaCardError)(error) && !!error.secondaryError && (0, _mediaClient.isRequestError)(error.secondaryError)) {
180
190
  return error.secondaryError.metadata;
@@ -183,17 +193,18 @@ var getRenderErrorRequestMetadata = function getRenderErrorRequestMetadata(error
183
193
 
184
194
  exports.getRenderErrorRequestMetadata = getRenderErrorRequestMetadata;
185
195
 
186
- var extractErrorInfo = function extractErrorInfo(error) {
196
+ var extractErrorInfo = function extractErrorInfo(error, metadataTraceContext) {
187
197
  return {
188
198
  failReason: getRenderErrorFailReason(error),
189
199
  error: getRenderErrorErrorReason(error),
190
- errorDetail: getRenderErrorErrorDetail(error)
200
+ errorDetail: getRenderErrorErrorDetail(error),
201
+ metadataTraceContext: metadataTraceContext !== null && metadataTraceContext !== void 0 ? metadataTraceContext : getErrorTraceContext(error)
191
202
  };
192
203
  };
193
204
 
194
205
  exports.extractErrorInfo = extractErrorInfo;
195
206
 
196
- var getRenderErrorEventPayload = function getRenderErrorEventPayload(fileAttributes, performanceAttributes, error, ssrReliability, traceContext) {
207
+ var getRenderErrorEventPayload = function getRenderErrorEventPayload(fileAttributes, performanceAttributes, error, ssrReliability, traceContext, metadataTraceContext) {
197
208
  return {
198
209
  eventType: 'operational',
199
210
  action: 'failed',
@@ -202,7 +213,7 @@ var getRenderErrorEventPayload = function getRenderErrorEventPayload(fileAttribu
202
213
  fileAttributes: fileAttributes,
203
214
  performanceAttributes: performanceAttributes,
204
215
  status: 'fail'
205
- }, extractErrorInfo(error)), {}, {
216
+ }, extractErrorInfo(error, metadataTraceContext)), {}, {
206
217
  request: getRenderErrorRequestMetadata(error),
207
218
  ssrReliability: ssrReliability,
208
219
  traceContext: traceContext
@@ -212,7 +223,26 @@ var getRenderErrorEventPayload = function getRenderErrorEventPayload(fileAttribu
212
223
 
213
224
  exports.getRenderErrorEventPayload = getRenderErrorEventPayload;
214
225
 
215
- var getRenderFailedFileStatusPayload = function getRenderFailedFileStatusPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext) {
226
+ var getErrorEventPayload = function getErrorEventPayload(cardStatus, fileAttributes, error, ssrReliability, traceContext, metadataTraceContext) {
227
+ return {
228
+ eventType: 'operational',
229
+ action: 'nonCriticalFail',
230
+ actionSubject: 'mediaCardRender',
231
+ attributes: _objectSpread(_objectSpread({
232
+ fileAttributes: fileAttributes,
233
+ status: 'fail'
234
+ }, extractErrorInfo(error, metadataTraceContext)), {}, {
235
+ request: getRenderErrorRequestMetadata(error),
236
+ ssrReliability: ssrReliability,
237
+ traceContext: traceContext,
238
+ cardStatus: cardStatus
239
+ })
240
+ };
241
+ };
242
+
243
+ exports.getErrorEventPayload = getErrorEventPayload;
244
+
245
+ var getRenderFailedFileStatusPayload = function getRenderFailedFileStatusPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext, metadataTraceContext) {
216
246
  return {
217
247
  eventType: 'operational',
218
248
  action: 'failed',
@@ -223,7 +253,8 @@ var getRenderFailedFileStatusPayload = function getRenderFailedFileStatusPayload
223
253
  status: 'fail',
224
254
  failReason: 'failed-processing',
225
255
  ssrReliability: ssrReliability,
226
- traceContext: traceContext
256
+ traceContext: traceContext,
257
+ metadataTraceContext: metadataTraceContext
227
258
  }
228
259
  };
229
260
  };
@@ -22,7 +22,7 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
22
22
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
23
23
 
24
24
  var packageName = "@atlaskit/media-card";
25
- var packageVersion = "74.3.2";
25
+ var packageVersion = "74.4.0";
26
26
  var concurrentExperience;
27
27
 
28
28
  var getExperience = function getExperience(id) {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/media-card",
3
- "version": "74.3.2",
3
+ "version": "74.4.0",
4
4
  "sideEffects": false
5
5
  }
@@ -16,7 +16,7 @@ import { getFileDetails } from '../utils/metadata';
16
16
  import { InlinePlayerLazy } from './inlinePlayerLazy';
17
17
  import { getFileAttributes, extractErrorInfo, LOGGED_FEATURE_FLAGS } from '../utils/analytics';
18
18
  import { isLocalPreviewError, MediaCardError, ensureMediaCardError, ImageLoadError } from '../errors';
19
- import { fireOperationalEvent, fireCommencedEvent, fireCopiedEvent, fireScreenEvent } from './cardAnalytics';
19
+ import { fireOperationalEvent, fireCommencedEvent, fireCopiedEvent, fireScreenEvent, fireNonCriticalErrorEvent } from './cardAnalytics';
20
20
  import getDocument from '../utils/document';
21
21
  import { StoreSSRDataScript, getSSRData } from '../utils/globalScope';
22
22
  import { getCardStateFromFileState, createStateUpdater } from './cardState';
@@ -26,7 +26,7 @@ import { getMediaCardCursor } from '../utils/getMediaCardCursor';
26
26
  import { completeUfoExperience, startUfoExperience } from '../utils/ufoExperiences';
27
27
  import { generateUniqueId } from '../utils/generateUniqueId';
28
28
  const packageName = "@atlaskit/media-card";
29
- const packageVersion = "74.3.2";
29
+ const packageVersion = "74.4.0";
30
30
  export class CardBase extends Component {
31
31
  // An internalOccurrenceKey is a randomly generated value to differentiate various instances
32
32
  // of Cards regardless of whether it shares the same file (either internal or external)
@@ -57,7 +57,7 @@ export class CardBase extends Component {
57
57
  _defineProperty(this, "timeElapsedTillCommenced", performance.now());
58
58
 
59
59
  _defineProperty(this, "traceContext", {
60
- traceId: getRandomHex(16)
60
+ traceId: getRandomHex(8)
61
61
  });
62
62
 
63
63
  _defineProperty(this, "getImageURLParams", ({
@@ -112,7 +112,7 @@ export class CardBase extends Component {
112
112
  mediaClient,
113
113
  id,
114
114
  dimensions,
115
- onLocalPreviewError: this.fireLocalPreviewErrorEvent,
115
+ onLocalPreviewError: this.fireNonCriticalErrorEvent,
116
116
  filePreview: isBannedLocalPreview ? undefined : getFilePreviewFromFileState(fileState),
117
117
  isRemotePreviewReady: isImageRepresentationReady(fileState),
118
118
  imageUrlParams: this.getImageURLParams(identifier),
@@ -146,8 +146,9 @@ export class CardBase extends Component {
146
146
  this.safeSetState({
147
147
  cardPreview
148
148
  });
149
- } catch (e) {// No need to log this error.
150
- // If preview fails, it will be refetched later
149
+ } catch (e) {
150
+ const wrappedError = ensureMediaCardError('remote-preview-fetch-ssr', e, true);
151
+ this.fireNonCriticalErrorEvent(wrappedError);
151
152
  }
152
153
  });
153
154
 
@@ -165,6 +166,7 @@ export class CardBase extends Component {
165
166
  // If it's any other error we set status 'error'
166
167
 
167
168
  if (isLocalPreviewError(wrappedError)) {
169
+ // This error should already been logged inside the getCardPreview. No need to log it here.
168
170
  this.safeSetState({
169
171
  isBannedLocalPreview: true
170
172
  });
@@ -234,7 +236,7 @@ export class CardBase extends Component {
234
236
 
235
237
  if (isLocal) {
236
238
  updateState.isBannedLocalPreview = true;
237
- this.fireLocalPreviewErrorEvent(error);
239
+ this.fireNonCriticalErrorEvent(error);
238
240
  }
239
241
 
240
242
  const {
@@ -304,17 +306,26 @@ export class CardBase extends Component {
304
306
  createAnalyticsEvent && fireScreenEvent(createAnalyticsEvent, this.fileAttributes);
305
307
  });
306
308
 
307
- _defineProperty(this, "fireLocalPreviewErrorEvent", error => {// TODO: track local preview success rate
308
- // https://product-fabric.atlassian.net/browse/MEX-774
309
+ _defineProperty(this, "fireNonCriticalErrorEvent", error => {
310
+ const {
311
+ createAnalyticsEvent
312
+ } = this.props;
313
+ const {
314
+ fileState
315
+ } = this.state;
316
+ createAnalyticsEvent && fireNonCriticalErrorEvent(createAnalyticsEvent, this.state.status, this.fileAttributes, this.ssrReliability, error, this.traceContext, fileState === null || fileState === void 0 ? void 0 : fileState.metadataTraceContext);
309
317
  });
310
318
 
311
- _defineProperty(this, "safeSetState", state => {
319
+ _defineProperty(this, "safeSetState", newState => {
312
320
  if (this.hasBeenMounted) {
313
- // If it's setting the status, we need to use a state updater function,
314
- // which ensures that no non-final status overrides a final status.
315
- // If no status is set, we don't need a sate updater
316
- const updater = !!state.status ? createStateUpdater(state) : state;
317
- this.setState(updater);
321
+ /**
322
+ * createStateUpdater helper returns a callback to be passed to setState.
323
+ * It decides wether to update the 'status' depending on the current state vs the input state.
324
+ * From docs: "Both state and props received by the updater function are guaranteed to be up-to-date."
325
+ * If the input state brings an error and it won't be updating the state, the error will be logged as non-critical inside the helper.
326
+ * If the error persists int the state, it means it is a critical error and should be logged as a failed event for Card
327
+ */
328
+ this.setState(createStateUpdater(newState, this.fireNonCriticalErrorEvent));
318
329
  }
319
330
  });
320
331
 
@@ -939,12 +950,13 @@ export class CardBase extends Component {
939
950
  fireOperationalEvent() {
940
951
  const {
941
952
  status,
942
- error
953
+ error,
954
+ fileState
943
955
  } = this.state;
944
956
  const {
945
957
  createAnalyticsEvent
946
958
  } = this.props;
947
- createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent, status, this.fileAttributes, this.getPerformanceAttributes(), this.ssrReliability, error, this.traceContext);
959
+ createAnalyticsEvent && fireOperationalEvent(createAnalyticsEvent, status, this.fileAttributes, this.getPerformanceAttributes(), this.ssrReliability, error, this.traceContext, fileState === null || fileState === void 0 ? void 0 : fileState.metadataTraceContext);
948
960
  completeUfoExperience(this.internalOccurrenceKey, status, this.fileAttributes, this.fileStateFlags, this.ssrReliability, error);
949
961
  }
950
962
 
@@ -1,19 +1,19 @@
1
- import { fireMediaCardEvent, getRenderSucceededEventPayload, getRenderErrorEventPayload, getRenderFailedFileStatusPayload, getCopiedFilePayload, getRenderCommencedEventPayload, getRenderPreviewableCardPayload } from '../utils/analytics';
1
+ import { fireMediaCardEvent, getRenderSucceededEventPayload, getRenderErrorEventPayload, getRenderFailedFileStatusPayload, getCopiedFilePayload, getRenderCommencedEventPayload, getRenderPreviewableCardPayload, getErrorEventPayload } from '../utils/analytics';
2
2
  import { MediaCardError } from '../errors';
3
- export const fireOperationalEvent = (createAnalyticsEvent, status, fileAttributes, performanceAttributes, ssrReliability, error = new MediaCardError('missing-error-data'), traceContext) => {
3
+ export const fireOperationalEvent = (createAnalyticsEvent, status, fileAttributes, performanceAttributes, ssrReliability, error = new MediaCardError('missing-error-data'), traceContext, metadataTraceContext) => {
4
4
  const fireEvent = payload => fireMediaCardEvent(payload, createAnalyticsEvent);
5
5
 
6
6
  switch (status) {
7
7
  case 'complete':
8
- fireEvent(getRenderSucceededEventPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext));
8
+ fireEvent(getRenderSucceededEventPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext, metadataTraceContext));
9
9
  break;
10
10
 
11
11
  case 'failed-processing':
12
- fireEvent(getRenderFailedFileStatusPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext));
12
+ fireEvent(getRenderFailedFileStatusPayload(fileAttributes, performanceAttributes, ssrReliability, traceContext, metadataTraceContext));
13
13
  break;
14
14
 
15
15
  case 'error':
16
- fireEvent(getRenderErrorEventPayload(fileAttributes, performanceAttributes, error, ssrReliability, traceContext));
16
+ fireEvent(getRenderErrorEventPayload(fileAttributes, performanceAttributes, error, ssrReliability, traceContext, metadataTraceContext));
17
17
  break;
18
18
  }
19
19
  };
@@ -33,4 +33,8 @@ export const fireCopiedEvent = (createAnalyticsEvent, fileId, cardRef) => {
33
33
  };
34
34
  export const fireScreenEvent = (createAnalyticsEvent, fileAttributes) => {
35
35
  fireMediaCardEvent(getRenderPreviewableCardPayload(fileAttributes), createAnalyticsEvent);
36
+ };
37
+ export const fireNonCriticalErrorEvent = (createAnalyticsEvent, cardStatus, fileAttributes, ssrReliability, error = new MediaCardError('missing-error-data'), traceContext, metadataTraceContext) => {
38
+ const errorPayload = getErrorEventPayload(cardStatus, fileAttributes, error, ssrReliability, traceContext, metadataTraceContext);
39
+ fireMediaCardEvent(errorPayload, createAnalyticsEvent);
36
40
  };
@@ -19,7 +19,7 @@ const MediaCard = Loadable({
19
19
  const MediaCardErrorBoundary = Loadable({
20
20
  loader: () => import(
21
21
  /* webpackChunkName: "@atlaskit-internal_media-card-error-boundary" */
22
- '../utils/media-card-analytics-error-boundary').then(mod => mod.default),
22
+ './media-card-analytics-error-boundary').then(mod => mod.default),
23
23
  loading: () => /*#__PURE__*/React.createElement(CardLoadingWithContext, null)
24
24
  });
25
25
  const MediaCardWithMediaClient = Loadable({
@@ -35,13 +35,22 @@ const MediaCardWithMediaClient = Loadable({
35
35
  const CardWithMediaClient = props => {
36
36
  const {
37
37
  withMediaClient,
38
- featureFlags
38
+ dimensions,
39
+ featureFlags,
40
+ onClick
39
41
  } = props;
40
42
  const memoizedFeatureFlags = useMemoizeFeatureFlags(featureFlags);
41
43
  const Card = React.useMemo(() => {
42
44
  return withMediaClient(MediaCard, memoizedFeatureFlags);
43
45
  }, [withMediaClient, memoizedFeatureFlags]);
44
- return /*#__PURE__*/React.createElement(MediaCardErrorBoundary, null, /*#__PURE__*/React.createElement(Card, props));
46
+ return (
47
+ /*#__PURE__*/
48
+ // onClick is passed into MediaCardErrorBoundary so MediaGroup items can get the toolbar menu in Editor
49
+ React.createElement(MediaCardErrorBoundary, {
50
+ dimensions: dimensions,
51
+ onClick: onClick
52
+ }, /*#__PURE__*/React.createElement(Card, props))
53
+ );
45
54
  };
46
55
 
47
56
  const CardLoader = props => {
@@ -2,16 +2,21 @@ import { isErrorFileState } from '@atlaskit/media-client';
2
2
  import { MediaCardError } from '../errors';
3
3
  import { getCardStatus, isFinalCardStatus } from './getCardStatus';
4
4
  import { extractFilePreviewStatus } from './getCardPreview';
5
- export const createStateUpdater = newState => prevState => {
6
- // Only override if previous status is non-final
7
- // or new status is 'complete'
8
- if (isFinalCardStatus(prevState.status) && newState.status !== 'complete') {
5
+ /**
6
+ * From docs: "Both state and props received by the updater function are guaranteed to be up-to-date.
7
+ * The output of the updater is shallowly merged with state."
8
+ */
9
+
10
+ export const createStateUpdater = (newState, fireErrorEvent) => prevState => {
11
+ // Only override if previous status is non-final or new status is 'complete'
12
+ if (!!newState.status && isFinalCardStatus(prevState.status) && newState.status !== 'complete') {
13
+ // Log the error if the new state is not going to store it.
14
+ // i.e. this is a non critical error
15
+ !!newState.error && fireErrorEvent(newState.error);
9
16
  return prevState;
10
17
  }
11
18
 
12
- return { ...prevState,
13
- ...newState
14
- };
19
+ return newState;
15
20
  };
16
21
  export const getCardStateFromFileState = (fileState, isBannedLocalPreview, featureFlags) => {
17
22
  const status = getCardStatus(fileState.status, extractFilePreviewStatus(fileState, isBannedLocalPreview, featureFlags));
@@ -0,0 +1,90 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import React from 'react';
3
+ import { withMediaAnalyticsContext } from '@atlaskit/media-common';
4
+ import { UnhandledErrorCard } from './ui/unhandledErrorCard';
5
+ import { withAnalyticsEvents } from '@atlaskit/analytics-next';
6
+ import { fireMediaCardEvent } from '../utils/analytics';
7
+
8
+ class WrappedMediaCardAnalyticsErrorBoundary extends React.Component {
9
+ constructor(props) {
10
+ super(props);
11
+
12
+ _defineProperty(this, "fireOperationalEvent", (error, info) => {
13
+ var _window, _window$navigator;
14
+
15
+ const {
16
+ data = {},
17
+ createAnalyticsEvent
18
+ } = this.props;
19
+ const payload = {
20
+ eventType: 'operational',
21
+ action: 'failed',
22
+ actionSubject: 'mediaCardRender',
23
+ attributes: {
24
+ browserInfo: (_window = window) !== null && _window !== void 0 && (_window$navigator = _window.navigator) !== null && _window$navigator !== void 0 && _window$navigator.userAgent ? window.navigator.userAgent : 'unknown',
25
+ error,
26
+ info,
27
+ failReason: 'unexpected-error',
28
+ ...data
29
+ }
30
+ };
31
+ fireMediaCardEvent(payload, createAnalyticsEvent);
32
+ });
33
+
34
+ _defineProperty(this, "handleOnClick", event => {
35
+ try {
36
+ var _this$props$onClick, _this$props;
37
+
38
+ (_this$props$onClick = (_this$props = this.props).onClick) === null || _this$props$onClick === void 0 ? void 0 : _this$props$onClick.call(_this$props, {
39
+ event
40
+ });
41
+ } catch (e) {}
42
+ });
43
+
44
+ this.state = {
45
+ hasError: false
46
+ };
47
+ }
48
+
49
+ componentDidCatch(error, info) {
50
+ try {
51
+ this.fireOperationalEvent(error, info);
52
+ } catch (e) {}
53
+
54
+ this.setState({
55
+ hasError: true
56
+ });
57
+ }
58
+
59
+ render() {
60
+ const {
61
+ hasError
62
+ } = this.state;
63
+ const {
64
+ dimensions,
65
+ children
66
+ } = this.props;
67
+
68
+ if (hasError) {
69
+ return /*#__PURE__*/React.createElement(UnhandledErrorCard, {
70
+ dimensions: dimensions,
71
+ onClick: this.handleOnClick
72
+ });
73
+ }
74
+
75
+ return children;
76
+ }
77
+
78
+ }
79
+
80
+ _defineProperty(WrappedMediaCardAnalyticsErrorBoundary, "displayName", 'MediaCardAnalyticsErrorBoundary');
81
+
82
+ const packageName = "@atlaskit/media-card";
83
+ const packageVersion = "74.4.0";
84
+ const MediaCardAnalyticsErrorBoundary = withMediaAnalyticsContext({
85
+ packageVersion,
86
+ packageName,
87
+ componentName: 'mediaCard',
88
+ component: 'mediaCard'
89
+ })(withAnalyticsEvents()(WrappedMediaCardAnalyticsErrorBoundary));
90
+ export default MediaCardAnalyticsErrorBoundary;
@@ -0,0 +1,80 @@
1
+ /** @jsx jsx */
2
+ import { Component } from 'react';
3
+ import { css, jsx } from '@emotion/react';
4
+ import { token } from '@atlaskit/tokens';
5
+ import WarningIcon from '@atlaskit/icon/glyph/editor/warning';
6
+ import { N20, N800, Y500 } from '@atlaskit/theme/colors';
7
+ import { fontSize } from '@atlaskit/theme/constants';
8
+ import { center, borderRadius } from '@atlaskit/media-ui';
9
+ import { defaultImageCardDimensions } from '../../../utils';
10
+
11
+ const isPercentage = value => /^\d+(\.\d+)?%$/.test(value);
12
+
13
+ const shouldShowText = ({
14
+ width,
15
+ height
16
+ }) => {
17
+ if (isPercentage(width) || isPercentage(height)) {
18
+ return false;
19
+ }
20
+
21
+ return parseInt(width, 10) >= 240 && parseInt(height, 10) >= 90;
22
+ };
23
+
24
+ const normalizeDimension = (value, defaultValue) => {
25
+ const sValue = value.toString();
26
+ return isPercentage(sValue) ? sValue : isNaN(parseInt(sValue, 10)) ? defaultValue + 'px' : parseInt(sValue, 10) + 'px';
27
+ };
28
+
29
+ const getConvertedDimension = dimensions => {
30
+ const {
31
+ width = defaultImageCardDimensions.width,
32
+ height = defaultImageCardDimensions.height
33
+ } = dimensions;
34
+ return {
35
+ width: normalizeDimension(width, defaultImageCardDimensions.width),
36
+ height: normalizeDimension(height, defaultImageCardDimensions.height)
37
+ };
38
+ };
39
+
40
+ const wrapperStyles = (dimensions = defaultImageCardDimensions) => {
41
+ try {
42
+ return css`
43
+ ${center};
44
+ ${borderRadius};
45
+ background: ${token('color.background.neutral', N20)};
46
+ color: ${token('color.text.subtle', N800)};
47
+ max-height: 100%;
48
+ max-width: 100%;
49
+ ${getConvertedDimension(dimensions)};
50
+ display: flex;
51
+ flex-direction: column;
52
+
53
+ p {
54
+ font-size: ${fontSize()}px;
55
+ text-align: center;
56
+ display: ${shouldShowText(getConvertedDimension(dimensions)) ? 'block' : 'none'};
57
+ }
58
+ `;
59
+ } catch (e) {
60
+ return null;
61
+ }
62
+ };
63
+
64
+ export class UnhandledErrorCard extends Component {
65
+ render() {
66
+ const {
67
+ dimensions,
68
+ onClick
69
+ } = this.props;
70
+ return jsx("div", {
71
+ css: wrapperStyles(dimensions),
72
+ onClick: onClick
73
+ }, jsx(WarningIcon, {
74
+ label: "Error",
75
+ primaryColor: token('color.icon.warning', Y500),
76
+ size: "medium"
77
+ }), jsx("p", null, "We couldn't load this content"));
78
+ }
79
+
80
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -76,8 +76,19 @@ export const isRemotePreviewError = err => err instanceof RemotePreviewError;
76
76
  export const isUnsupportedLocalPreviewError = err => isMediaCardError(err) && err.primaryReason === 'local-preview-unsupported';
77
77
  export function isImageLoadError(err) {
78
78
  return err instanceof ImageLoadError;
79
- } // In a try/catch statement, the error caught is the type of any.
79
+ } // In a try/catch statement, the error caught is the type of unknown.
80
80
  // We can use this helper to ensure that the error handled is the type of MediaCardError if unsure
81
+ // If updatePrimaryReason is true, if it's a MediaCardError already, it will update it's primary reason
81
82
 
82
- export const ensureMediaCardError = (primaryReason, error) => isMediaCardError(error) ? error : new MediaCardError(primaryReason, error);
83
+ export const ensureMediaCardError = (primaryReason, error, updatePrimaryReason) => {
84
+ if (isMediaCardError(error)) {
85
+ if (updatePrimaryReason && error.primaryReason !== primaryReason) {
86
+ return new MediaCardError(primaryReason, error.secondaryError);
87
+ }
88
+
89
+ return error;
90
+ }
91
+
92
+ return new MediaCardError(primaryReason, error);
93
+ };
83
94
  export const isUploadError = error => error && error.primaryReason === 'upload';