@atlaskit/editor-core 189.4.8 → 189.4.10

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/editor-core
2
2
 
3
+ ## 189.4.10
4
+
5
+ ### Patch Changes
6
+
7
+ - [#55514](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/55514) [`9e0ff045562e`](https://bitbucket.org/atlassian/atlassian-frontend/commits/9e0ff045562e) - Re-add safe parameters to config panel analytic event
8
+
9
+ ## 189.4.9
10
+
11
+ ### Patch Changes
12
+
13
+ - [#57079](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/57079) [`d15db1b00c5a`](https://bitbucket.org/atlassian/atlassian-frontend/commits/d15db1b00c5a) - [ED-21267] Improve arrow navigation across MultiBodiedExtensions
14
+
3
15
  ## 189.4.8
4
16
 
5
17
  ### Patch Changes
@@ -6,13 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.default = void 0;
9
- var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
10
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
11
11
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
12
12
  var _react = require("@emotion/react");
13
13
  var _colors = require("@atlaskit/theme/colors");
14
14
  var _react2 = _interopRequireWildcard(require("react"));
15
- var _templateObject;
15
+ var _templateObject, _templateObject2;
16
16
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
17
17
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
18
18
  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; }
@@ -104,6 +104,7 @@ var useMultiBodiedExtensionActions = function useMultiBodiedExtensionActions(_re
104
104
  }, [node, editorView, getPos, updateActiveChild]);
105
105
  return actions;
106
106
  };
107
+ var navigationCSS = (0, _react.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n // make sure the user can't see a range selection inside the navigation\n // This is really important to keep the navigation working properly\n user-select: none;\n -webkit-user-modify: read-only;\n"])));
107
108
  var MultiBodiedExtension = function MultiBodiedExtension(_ref2) {
108
109
  var node = _ref2.node,
109
110
  handleContentDOMRef = _ref2.handleContentDOMRef,
@@ -136,14 +137,15 @@ var MultiBodiedExtension = function MultiBodiedExtension(_ref2) {
136
137
  var articleRef = _react2.default.useCallback(function (node) {
137
138
  return handleContentDOMRef(node);
138
139
  }, [handleContentDOMRef]);
139
- var containerCss = (0, _react.css)(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n border: 1px solid ", ";\n padding: ", ";\n .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true'] {\n display: none;\n }\n\n .multiBodiedExtension-content-dom-wrapper\n > [data-extension-frame='true']:nth-of-type(", ") {\n display: block;\n }\n "])), "var(--ds-border, ".concat(_colors.N30, ")"), "var(--ds-space-050, 4px)", activeChildIndex + 1);
140
+ var containerCSS = (0, _react.css)(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2.default)(["\n border: 1px solid ", ";\n padding: ", ";\n .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true'] {\n display: none;\n }\n\n .multiBodiedExtension-content-dom-wrapper\n > [data-extension-frame='true']:nth-of-type(", ") {\n display: block;\n }\n "])), "var(--ds-border, ".concat(_colors.N30, ")"), "var(--ds-space-050, 4px)", activeChildIndex + 1);
140
141
  return (0, _react.jsx)("section", {
141
142
  className: "multiBodiedExtension--container",
142
- css: containerCss,
143
+ css: containerCSS,
143
144
  "data-testid": "multiBodiedExtension--container",
144
145
  "data-active-child-index": activeChildIndex
145
146
  }, (0, _react.jsx)("nav", {
146
147
  className: "multiBodiedExtension-navigation",
148
+ css: navigationCSS,
147
149
  "data-testid": "multiBodiedExtension-navigation"
148
150
  }, extensionHandlerResult), (0, _react.jsx)("article", {
149
151
  className: "multiBodiedExtension--frames",
@@ -36,8 +36,12 @@ var _WithPluginState = _interopRequireDefault(require("../WithPluginState"));
36
36
  var _FormContent = _interopRequireDefault(require("./FormContent"));
37
37
  var _messages = require("./messages");
38
38
  var _FormErrorBoundary = require("./FormErrorBoundary");
39
+ var _utils = require("./utils");
40
+ var _constants = require("./constants");
39
41
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
40
42
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
43
+ 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; }
44
+ 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; }
41
45
  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); }; }
42
46
  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; } }
43
47
  function ConfigForm(_ref) {
@@ -336,16 +340,20 @@ var ConfigPanel = /*#__PURE__*/function (_React$Component) {
336
340
  value: function componentWillUnmount() {
337
341
  var _this$props4 = this.props,
338
342
  createAnalyticsEvent = _this$props4.createAnalyticsEvent,
339
- extensionManifest = _this$props4.extensionManifest;
343
+ extensionManifest = _this$props4.extensionManifest,
344
+ fields = _this$props4.fields;
345
+ var currentParameters = this.state.currentParameters;
340
346
  (0, _analytics.fireAnalyticsEvent)(createAnalyticsEvent)({
341
347
  payload: {
342
348
  action: _analytics.ACTION.CLOSED,
343
349
  actionSubject: _analytics.ACTION_SUBJECT.CONFIG_PANEL,
344
350
  eventType: _analytics.EVENT_TYPE.UI,
345
- attributes: {
351
+ attributes: _objectSpread({
346
352
  extensionKey: extensionManifest === null || extensionManifest === void 0 ? void 0 : extensionManifest.key,
347
353
  extensionType: extensionManifest === null || extensionManifest === void 0 ? void 0 : extensionManifest.type
348
- }
354
+ }, extensionManifest !== null && extensionManifest !== void 0 && extensionManifest.key && _constants.ALLOWED_LOGGED_MACRO_PARAMS[extensionManifest.key] ? {
355
+ parameters: (0, _utils.getLoggedParameters)(extensionManifest.key, currentParameters, fields)
356
+ } : {})
349
357
  }
350
358
  });
351
359
  }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ALLOWED_PARAM_TYPES = exports.ALLOWED_LOGGED_MACRO_PARAMS = void 0;
7
+ // Allowlist of { macroKey: parameterName[] } for analytics logging
8
+ var ALLOWED_LOGGED_MACRO_PARAMS = exports.ALLOWED_LOGGED_MACRO_PARAMS = {
9
+ children: ['all', 'first', 'depth', 'style', 'excerptType', 'sort', 'reverse'],
10
+ 'recently-updated': ['width', 'types', 'max', 'theme', 'showProfilePic', 'hideHeading'],
11
+ excerpt: ['hidden']
12
+ };
13
+ var ALLOWED_PARAM_TYPES = exports.ALLOWED_PARAM_TYPES = ['enum', 'number', 'boolean'];
@@ -1,10 +1,15 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
- exports.validateRequired = exports.validate = exports.isDuplicateField = exports.getSafeParentedName = exports.getOptionFromValue = exports.getNameFromDuplicateField = void 0;
7
+ exports.validateRequired = exports.validate = exports.isDuplicateField = exports.getSafeParentedName = exports.getOptionFromValue = exports.getNameFromDuplicateField = exports.getLoggedParameters = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
7
9
  var _types = require("./types");
10
+ var _constants = require("./constants");
11
+ 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; }
12
+ 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; }
8
13
  var validate = exports.validate = function validate(field, value) {
9
14
  return validateRequired(field, value);
10
15
  };
@@ -53,4 +58,42 @@ var isDuplicateField = exports.isDuplicateField = function isDuplicateField(key)
53
58
  };
54
59
  var getNameFromDuplicateField = exports.getNameFromDuplicateField = function getNameFromDuplicateField(key) {
55
60
  return key.replace(duplicateFieldRegex, '');
61
+ };
62
+
63
+ // An overly cautious parser for sanitizing configuration parameters of UGC
64
+ var parseParamType = function parseParamType(paramValue, paramField) {
65
+ if (paramValue && paramField) {
66
+ if (paramField.type === 'string') {
67
+ if (paramField.name === 'types') {
68
+ // Parse types field as an array of valid content types
69
+ var contentTypes = ['page', 'blogpost', 'comment', 'attachment'];
70
+ return paramValue && paramValue.split(',').map(function (type) {
71
+ return type.trim();
72
+ }).filter(function (type) {
73
+ return contentTypes.includes(type);
74
+ });
75
+ }
76
+ if (paramField.name === 'width') {
77
+ return parseFloat(paramValue);
78
+ }
79
+ // Strings are very risky - return empty string in case anything slips through
80
+ return '';
81
+ }
82
+ if (_constants.ALLOWED_PARAM_TYPES.includes(paramField.type)) {
83
+ // The param types defined here are already parsed and safe to log
84
+ return paramValue;
85
+ }
86
+ }
87
+ // Safety net
88
+ return null;
89
+ };
90
+ var getLoggedParameters = exports.getLoggedParameters = function getLoggedParameters(macroKey, currentParams, macroFields) {
91
+ // Get the parameters only defined in the allowlist of logged macro/parameter keys
92
+ return Object.keys(currentParams).filter(function (paramKey) {
93
+ return _constants.ALLOWED_LOGGED_MACRO_PARAMS[macroKey].includes(paramKey);
94
+ }).reduce(function (obj, param) {
95
+ return _objectSpread(_objectSpread({}, obj), {}, (0, _defineProperty2.default)({}, param, parseParamType(currentParams[param], macroFields === null || macroFields === void 0 ? void 0 : macroFields.find(function (field) {
96
+ return field.name === param;
97
+ }))));
98
+ }, {});
56
99
  };
@@ -5,4 +5,4 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.version = exports.name = void 0;
7
7
  var name = exports.name = "@atlaskit/editor-core";
8
- var version = exports.version = "189.4.8";
8
+ var version = exports.version = "189.4.10";
@@ -100,6 +100,12 @@ const useMultiBodiedExtensionActions = ({
100
100
  }, [node, editorView, getPos, updateActiveChild]);
101
101
  return actions;
102
102
  };
103
+ const navigationCSS = css`
104
+ // make sure the user can't see a range selection inside the navigation
105
+ // This is really important to keep the navigation working properly
106
+ user-select: none;
107
+ -webkit-user-modify: read-only;
108
+ `;
103
109
  const MultiBodiedExtension = ({
104
110
  node,
105
111
  handleContentDOMRef,
@@ -130,7 +136,7 @@ const MultiBodiedExtension = ({
130
136
  const articleRef = React.useCallback(node => {
131
137
  return handleContentDOMRef(node);
132
138
  }, [handleContentDOMRef]);
133
- const containerCss = css`
139
+ const containerCSS = css`
134
140
  border: 1px solid ${`var(--ds-border, ${N30})`};
135
141
  padding: ${"var(--ds-space-050, 4px)"};
136
142
  .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true'] {
@@ -144,11 +150,12 @@ const MultiBodiedExtension = ({
144
150
  `;
145
151
  return jsx("section", {
146
152
  className: "multiBodiedExtension--container",
147
- css: containerCss,
153
+ css: containerCSS,
148
154
  "data-testid": "multiBodiedExtension--container",
149
155
  "data-active-child-index": activeChildIndex
150
156
  }, jsx("nav", {
151
157
  className: "multiBodiedExtension-navigation",
158
+ css: navigationCSS,
152
159
  "data-testid": "multiBodiedExtension-navigation"
153
160
  }, extensionHandlerResult), jsx("article", {
154
161
  className: "multiBodiedExtension--frames",
@@ -21,6 +21,8 @@ import WithPluginState from '../WithPluginState';
21
21
  import FormContent from './FormContent';
22
22
  import { messages } from './messages';
23
23
  import { FormErrorBoundary } from './FormErrorBoundary';
24
+ import { getLoggedParameters } from './utils';
25
+ import { ALLOWED_LOGGED_MACRO_PARAMS } from './constants';
24
26
  function ConfigForm({
25
27
  canSave,
26
28
  errorMessage,
@@ -276,8 +278,12 @@ class ConfigPanel extends React.Component {
276
278
  componentWillUnmount() {
277
279
  const {
278
280
  createAnalyticsEvent,
279
- extensionManifest
281
+ extensionManifest,
282
+ fields
280
283
  } = this.props;
284
+ const {
285
+ currentParameters
286
+ } = this.state;
281
287
  fireAnalyticsEvent(createAnalyticsEvent)({
282
288
  payload: {
283
289
  action: ACTION.CLOSED,
@@ -285,7 +291,10 @@ class ConfigPanel extends React.Component {
285
291
  eventType: EVENT_TYPE.UI,
286
292
  attributes: {
287
293
  extensionKey: extensionManifest === null || extensionManifest === void 0 ? void 0 : extensionManifest.key,
288
- extensionType: extensionManifest === null || extensionManifest === void 0 ? void 0 : extensionManifest.type
294
+ extensionType: extensionManifest === null || extensionManifest === void 0 ? void 0 : extensionManifest.type,
295
+ ...(extensionManifest !== null && extensionManifest !== void 0 && extensionManifest.key && ALLOWED_LOGGED_MACRO_PARAMS[extensionManifest.key] ? {
296
+ parameters: getLoggedParameters(extensionManifest.key, currentParameters, fields)
297
+ } : {})
289
298
  }
290
299
  }
291
300
  });
@@ -0,0 +1,7 @@
1
+ // Allowlist of { macroKey: parameterName[] } for analytics logging
2
+ export const ALLOWED_LOGGED_MACRO_PARAMS = {
3
+ children: ['all', 'first', 'depth', 'style', 'excerptType', 'sort', 'reverse'],
4
+ 'recently-updated': ['width', 'types', 'max', 'theme', 'showProfilePic', 'hideHeading'],
5
+ excerpt: ['hidden']
6
+ };
7
+ export const ALLOWED_PARAM_TYPES = ['enum', 'number', 'boolean'];
@@ -1,4 +1,5 @@
1
1
  import { ValidationError } from './types';
2
+ import { ALLOWED_LOGGED_MACRO_PARAMS, ALLOWED_PARAM_TYPES } from './constants';
2
3
  export const validate = (field, value) => {
3
4
  return validateRequired(field, value);
4
5
  };
@@ -36,4 +37,37 @@ export const getSafeParentedName = (name, parentName) => {
36
37
  };
37
38
  const duplicateFieldRegex = /:[0-9]+$/;
38
39
  export const isDuplicateField = key => duplicateFieldRegex.test(key);
39
- export const getNameFromDuplicateField = key => key.replace(duplicateFieldRegex, '');
40
+ export const getNameFromDuplicateField = key => key.replace(duplicateFieldRegex, '');
41
+
42
+ // An overly cautious parser for sanitizing configuration parameters of UGC
43
+ const parseParamType = (paramValue, paramField) => {
44
+ if (paramValue && paramField) {
45
+ if (paramField.type === 'string') {
46
+ if (paramField.name === 'types') {
47
+ // Parse types field as an array of valid content types
48
+ const contentTypes = ['page', 'blogpost', 'comment', 'attachment'];
49
+ return paramValue && paramValue.split(',').map(type => type.trim()).filter(type => contentTypes.includes(type));
50
+ }
51
+ if (paramField.name === 'width') {
52
+ return parseFloat(paramValue);
53
+ }
54
+ // Strings are very risky - return empty string in case anything slips through
55
+ return '';
56
+ }
57
+ if (ALLOWED_PARAM_TYPES.includes(paramField.type)) {
58
+ // The param types defined here are already parsed and safe to log
59
+ return paramValue;
60
+ }
61
+ }
62
+ // Safety net
63
+ return null;
64
+ };
65
+ export const getLoggedParameters = (macroKey, currentParams, macroFields) => {
66
+ // Get the parameters only defined in the allowlist of logged macro/parameter keys
67
+ return Object.keys(currentParams).filter(paramKey => ALLOWED_LOGGED_MACRO_PARAMS[macroKey].includes(paramKey)).reduce((obj, param) => {
68
+ return {
69
+ ...obj,
70
+ [param]: parseParamType(currentParams[param], macroFields === null || macroFields === void 0 ? void 0 : macroFields.find(field => field.name === param))
71
+ };
72
+ }, {});
73
+ };
@@ -1,2 +1,2 @@
1
1
  export const name = "@atlaskit/editor-core";
2
- export const version = "189.4.8";
2
+ export const version = "189.4.10";
@@ -1,7 +1,7 @@
1
- import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
2
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import _taggedTemplateLiteral from "@babel/runtime/helpers/taggedTemplateLiteral";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
- var _templateObject;
4
+ var _templateObject, _templateObject2;
5
5
  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; }
6
6
  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; }
7
7
  /** @jsx jsx */
@@ -96,6 +96,7 @@ var useMultiBodiedExtensionActions = function useMultiBodiedExtensionActions(_re
96
96
  }, [node, editorView, getPos, updateActiveChild]);
97
97
  return actions;
98
98
  };
99
+ var navigationCSS = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n // make sure the user can't see a range selection inside the navigation\n // This is really important to keep the navigation working properly\n user-select: none;\n -webkit-user-modify: read-only;\n"])));
99
100
  var MultiBodiedExtension = function MultiBodiedExtension(_ref2) {
100
101
  var node = _ref2.node,
101
102
  handleContentDOMRef = _ref2.handleContentDOMRef,
@@ -128,14 +129,15 @@ var MultiBodiedExtension = function MultiBodiedExtension(_ref2) {
128
129
  var articleRef = React.useCallback(function (node) {
129
130
  return handleContentDOMRef(node);
130
131
  }, [handleContentDOMRef]);
131
- var containerCss = css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n border: 1px solid ", ";\n padding: ", ";\n .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true'] {\n display: none;\n }\n\n .multiBodiedExtension-content-dom-wrapper\n > [data-extension-frame='true']:nth-of-type(", ") {\n display: block;\n }\n "])), "var(--ds-border, ".concat(N30, ")"), "var(--ds-space-050, 4px)", activeChildIndex + 1);
132
+ var containerCSS = css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n border: 1px solid ", ";\n padding: ", ";\n .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true'] {\n display: none;\n }\n\n .multiBodiedExtension-content-dom-wrapper\n > [data-extension-frame='true']:nth-of-type(", ") {\n display: block;\n }\n "])), "var(--ds-border, ".concat(N30, ")"), "var(--ds-space-050, 4px)", activeChildIndex + 1);
132
133
  return jsx("section", {
133
134
  className: "multiBodiedExtension--container",
134
- css: containerCss,
135
+ css: containerCSS,
135
136
  "data-testid": "multiBodiedExtension--container",
136
137
  "data-active-child-index": activeChildIndex
137
138
  }, jsx("nav", {
138
139
  className: "multiBodiedExtension-navigation",
140
+ css: navigationCSS,
139
141
  "data-testid": "multiBodiedExtension-navigation"
140
142
  }, extensionHandlerResult), jsx("article", {
141
143
  className: "multiBodiedExtension--frames",
@@ -7,6 +7,8 @@ import _inherits from "@babel/runtime/helpers/inherits";
7
7
  import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
8
8
  import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
9
9
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
10
+ 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; }
11
+ 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; }
10
12
  import _regeneratorRuntime from "@babel/runtime/regenerator";
11
13
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
12
14
  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; } }
@@ -31,6 +33,8 @@ import WithPluginState from '../WithPluginState';
31
33
  import FormContent from './FormContent';
32
34
  import { messages } from './messages';
33
35
  import { FormErrorBoundary } from './FormErrorBoundary';
36
+ import { getLoggedParameters } from './utils';
37
+ import { ALLOWED_LOGGED_MACRO_PARAMS } from './constants';
34
38
  function ConfigForm(_ref) {
35
39
  var canSave = _ref.canSave,
36
40
  errorMessage = _ref.errorMessage,
@@ -327,16 +331,20 @@ var ConfigPanel = /*#__PURE__*/function (_React$Component) {
327
331
  value: function componentWillUnmount() {
328
332
  var _this$props4 = this.props,
329
333
  createAnalyticsEvent = _this$props4.createAnalyticsEvent,
330
- extensionManifest = _this$props4.extensionManifest;
334
+ extensionManifest = _this$props4.extensionManifest,
335
+ fields = _this$props4.fields;
336
+ var currentParameters = this.state.currentParameters;
331
337
  fireAnalyticsEvent(createAnalyticsEvent)({
332
338
  payload: {
333
339
  action: ACTION.CLOSED,
334
340
  actionSubject: ACTION_SUBJECT.CONFIG_PANEL,
335
341
  eventType: EVENT_TYPE.UI,
336
- attributes: {
342
+ attributes: _objectSpread({
337
343
  extensionKey: extensionManifest === null || extensionManifest === void 0 ? void 0 : extensionManifest.key,
338
344
  extensionType: extensionManifest === null || extensionManifest === void 0 ? void 0 : extensionManifest.type
339
- }
345
+ }, extensionManifest !== null && extensionManifest !== void 0 && extensionManifest.key && ALLOWED_LOGGED_MACRO_PARAMS[extensionManifest.key] ? {
346
+ parameters: getLoggedParameters(extensionManifest.key, currentParameters, fields)
347
+ } : {})
340
348
  }
341
349
  });
342
350
  }
@@ -0,0 +1,7 @@
1
+ // Allowlist of { macroKey: parameterName[] } for analytics logging
2
+ export var ALLOWED_LOGGED_MACRO_PARAMS = {
3
+ children: ['all', 'first', 'depth', 'style', 'excerptType', 'sort', 'reverse'],
4
+ 'recently-updated': ['width', 'types', 'max', 'theme', 'showProfilePic', 'hideHeading'],
5
+ excerpt: ['hidden']
6
+ };
7
+ export var ALLOWED_PARAM_TYPES = ['enum', 'number', 'boolean'];
@@ -1,4 +1,8 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ 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; }
3
+ 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; }
1
4
  import { ValidationError } from './types';
5
+ import { ALLOWED_LOGGED_MACRO_PARAMS, ALLOWED_PARAM_TYPES } from './constants';
2
6
  export var validate = function validate(field, value) {
3
7
  return validateRequired(field, value);
4
8
  };
@@ -47,4 +51,42 @@ export var isDuplicateField = function isDuplicateField(key) {
47
51
  };
48
52
  export var getNameFromDuplicateField = function getNameFromDuplicateField(key) {
49
53
  return key.replace(duplicateFieldRegex, '');
54
+ };
55
+
56
+ // An overly cautious parser for sanitizing configuration parameters of UGC
57
+ var parseParamType = function parseParamType(paramValue, paramField) {
58
+ if (paramValue && paramField) {
59
+ if (paramField.type === 'string') {
60
+ if (paramField.name === 'types') {
61
+ // Parse types field as an array of valid content types
62
+ var contentTypes = ['page', 'blogpost', 'comment', 'attachment'];
63
+ return paramValue && paramValue.split(',').map(function (type) {
64
+ return type.trim();
65
+ }).filter(function (type) {
66
+ return contentTypes.includes(type);
67
+ });
68
+ }
69
+ if (paramField.name === 'width') {
70
+ return parseFloat(paramValue);
71
+ }
72
+ // Strings are very risky - return empty string in case anything slips through
73
+ return '';
74
+ }
75
+ if (ALLOWED_PARAM_TYPES.includes(paramField.type)) {
76
+ // The param types defined here are already parsed and safe to log
77
+ return paramValue;
78
+ }
79
+ }
80
+ // Safety net
81
+ return null;
82
+ };
83
+ export var getLoggedParameters = function getLoggedParameters(macroKey, currentParams, macroFields) {
84
+ // Get the parameters only defined in the allowlist of logged macro/parameter keys
85
+ return Object.keys(currentParams).filter(function (paramKey) {
86
+ return ALLOWED_LOGGED_MACRO_PARAMS[macroKey].includes(paramKey);
87
+ }).reduce(function (obj, param) {
88
+ return _objectSpread(_objectSpread({}, obj), {}, _defineProperty({}, param, parseParamType(currentParams[param], macroFields === null || macroFields === void 0 ? void 0 : macroFields.find(function (field) {
89
+ return field.name === param;
90
+ }))));
91
+ }, {});
50
92
  };
@@ -1,2 +1,2 @@
1
1
  export var name = "@atlaskit/editor-core";
2
- export var version = "189.4.8";
2
+ export var version = "189.4.10";
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import { WithAnalyticsEventsProps } from '@atlaskit/analytics-next';
3
- import type { ExtensionManifest } from '@atlaskit/editor-common/extensions';
4
- import { FieldDefinition, Parameters, OnSaveCallback } from '@atlaskit/editor-common/extensions';
5
- import { FeatureFlags } from '@atlaskit/editor-common/types';
2
+ import type { WithAnalyticsEventsProps } from '@atlaskit/analytics-next';
3
+ import type { ExtensionManifest, FieldDefinition, Parameters, OnSaveCallback } from '@atlaskit/editor-common/extensions';
4
+ import type { FeatureFlags } from '@atlaskit/editor-common/types';
6
5
  type Props = {
7
6
  extensionManifest?: ExtensionManifest;
8
7
  fields?: FieldDefinition[];
@@ -0,0 +1,2 @@
1
+ export declare const ALLOWED_LOGGED_MACRO_PARAMS: Record<string, Array<string>>;
2
+ export declare const ALLOWED_PARAM_TYPES: string[];
@@ -1,4 +1,4 @@
1
- import { Option, FieldDefinition } from '@atlaskit/editor-common/extensions';
1
+ import type { Option, FieldDefinition, Parameters } from '@atlaskit/editor-common/extensions';
2
2
  import { ValidationError } from './types';
3
3
  export declare const validate: <T>(field: Partial<FieldDefinition>, value: T) => ValidationError | undefined;
4
4
  type ValidationProps = {
@@ -10,4 +10,5 @@ export declare const getOptionFromValue: (options: Option[], value: string | str
10
10
  export declare const getSafeParentedName: (name: string, parentName?: string) => string;
11
11
  export declare const isDuplicateField: (key: string) => boolean;
12
12
  export declare const getNameFromDuplicateField: (key: string) => string;
13
+ export declare const getLoggedParameters: (macroKey: string, currentParams: Parameters, macroFields?: FieldDefinition[]) => {};
13
14
  export {};
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import { WithAnalyticsEventsProps } from '@atlaskit/analytics-next';
3
- import type { ExtensionManifest } from '@atlaskit/editor-common/extensions';
4
- import { FieldDefinition, Parameters, OnSaveCallback } from '@atlaskit/editor-common/extensions';
5
- import { FeatureFlags } from '@atlaskit/editor-common/types';
2
+ import type { WithAnalyticsEventsProps } from '@atlaskit/analytics-next';
3
+ import type { ExtensionManifest, FieldDefinition, Parameters, OnSaveCallback } from '@atlaskit/editor-common/extensions';
4
+ import type { FeatureFlags } from '@atlaskit/editor-common/types';
6
5
  type Props = {
7
6
  extensionManifest?: ExtensionManifest;
8
7
  fields?: FieldDefinition[];
@@ -0,0 +1,2 @@
1
+ export declare const ALLOWED_LOGGED_MACRO_PARAMS: Record<string, Array<string>>;
2
+ export declare const ALLOWED_PARAM_TYPES: string[];
@@ -1,4 +1,4 @@
1
- import { Option, FieldDefinition } from '@atlaskit/editor-common/extensions';
1
+ import type { Option, FieldDefinition, Parameters } from '@atlaskit/editor-common/extensions';
2
2
  import { ValidationError } from './types';
3
3
  export declare const validate: <T>(field: Partial<FieldDefinition>, value: T) => ValidationError | undefined;
4
4
  type ValidationProps = {
@@ -10,4 +10,5 @@ export declare const getOptionFromValue: (options: Option[], value: string | str
10
10
  export declare const getSafeParentedName: (name: string, parentName?: string) => string;
11
11
  export declare const isDuplicateField: (key: string) => boolean;
12
12
  export declare const getNameFromDuplicateField: (key: string) => string;
13
+ export declare const getLoggedParameters: (macroKey: string, currentParams: Parameters, macroFields?: FieldDefinition[]) => {};
13
14
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-core",
3
- "version": "189.4.8",
3
+ "version": "189.4.10",
4
4
  "description": "A package contains Atlassian editor core functionality",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -168,7 +168,7 @@
168
168
  "@af/integration-testing": "*",
169
169
  "@af/visual-regression": "*",
170
170
  "@atlaskit/analytics-listeners": "^8.7.0",
171
- "@atlaskit/collab-provider": "9.17.2",
171
+ "@atlaskit/collab-provider": "9.17.3",
172
172
  "@atlaskit/dropdown-menu": "^12.1.0",
173
173
  "@atlaskit/editor-extension-dropbox": "^0.4.0",
174
174
  "@atlaskit/editor-palette": "1.5.2",