@gravity-ui/dashkit 5.1.0 → 5.3.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 CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.3.0](https://github.com/gravity-ui/dashkit/compare/v5.2.0...v5.3.0) (2023-04-06)
4
+
5
+
6
+ ### Features
7
+
8
+ * add actionParams support ([#47](https://github.com/gravity-ui/dashkit/issues/47)) ([0c78ae2](https://github.com/gravity-ui/dashkit/commit/0c78ae2b96d9882ea27a7e7742d40728fadcfa84))
9
+
10
+ ## [5.2.0](https://github.com/gravity-ui/dashkit/compare/v5.1.0...v5.2.0) (2023-03-27)
11
+
12
+
13
+ ### Features
14
+
15
+ * add custom qa attribute for overlay controls ([#45](https://github.com/gravity-ui/dashkit/issues/45)) ([738ce14](https://github.com/gravity-ui/dashkit/commit/738ce14a7883a88d3096ed4c9bd21bcc16f3fd20))
16
+ * export OverlayControlItem type ([#50](https://github.com/gravity-ui/dashkit/issues/50)) ([a68cc5c](https://github.com/gravity-ui/dashkit/commit/a68cc5cb4e4470278220e18f79f9b82dc6a7cfba))
17
+
3
18
  ## [5.1.0](https://github.com/gravity-ui/dashkit/compare/v5.0.0...v5.1.0) (2023-02-09)
4
19
 
5
20
 
@@ -16,6 +16,7 @@ export interface OverlayControlItem {
16
16
  allWidgetsControls?: boolean;
17
17
  excludeWidgetsTypes?: Array<PluginBase['type']>;
18
18
  id?: string;
19
+ qa?: string;
19
20
  }
20
21
  export interface OverlayCustomControlItem {
21
22
  id: string;
@@ -25,6 +26,7 @@ export interface OverlayCustomControlItem {
25
26
  handler?: (item: ConfigItem, params: StringParams) => void;
26
27
  visible?: (item: ConfigItem) => boolean;
27
28
  className?: string;
29
+ qa?: string;
28
30
  }
29
31
  interface OverlayControlsDefaultProps {
30
32
  position: OverlayControlsPosition;
@@ -26,9 +26,9 @@ class OverlayControls extends react_1.default.Component {
26
26
  super(...arguments);
27
27
  this.renderControlsItem = (item, index, length) => {
28
28
  const { view, size } = this.props;
29
- const { title, handler, icon, iconSize } = item;
29
+ const { title, handler, icon, iconSize, qa } = item;
30
30
  const onItemClickHandler = typeof handler === 'function' ? handler : noop_1.default;
31
- return (react_1.default.createElement(uikit_1.Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => onItemClickHandler(this.props.configItem) },
31
+ return (react_1.default.createElement(uikit_1.Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => onItemClickHandler(this.props.configItem), qa: qa },
32
32
  react_1.default.createElement(uikit_1.Icon, { data: icon || CogIcon_1.CogIcon, size: icon ? iconSize : 24 })));
33
33
  };
34
34
  this.getCustomLeftOverlayControls = () => {
@@ -171,10 +171,11 @@ class OverlayControls extends react_1.default.Component {
171
171
  icon: item.icon,
172
172
  action: itemAction,
173
173
  className: item.className,
174
+ qa: item.qa,
174
175
  };
175
176
  });
176
177
  items = items.filter(Boolean);
177
- return (react_1.default.createElement(uikit_1.DropdownMenu, { items: items, switcher: react_1.default.createElement(uikit_1.Button, { view: view, size: size, pin: "brick-round" },
178
+ return (react_1.default.createElement(uikit_1.DropdownMenu, { items: items, switcher: react_1.default.createElement(uikit_1.Button, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" },
178
179
  react_1.default.createElement(uikit_1.Icon, { data: DotsIcon_1.DotsIcon, size: "16" })) }));
179
180
  }
180
181
  getControlItemPinStyle(index, itemsLength) {
@@ -1 +1,2 @@
1
1
  export * from './DashKit';
2
+ export { OverlayControlItem } from './OverlayControls/OverlayControls';
@@ -1,2 +1,3 @@
1
1
  export declare const CURRENT_VERSION = 2;
2
2
  export declare const META_KEY = "__meta__";
3
+ export declare const ACTION_PARAM_PREFIX = "_ap_";
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.META_KEY = exports.CURRENT_VERSION = void 0;
3
+ exports.ACTION_PARAM_PREFIX = exports.META_KEY = exports.CURRENT_VERSION = void 0;
4
4
  exports.CURRENT_VERSION = 2;
5
5
  exports.META_KEY = '__meta__';
6
+ exports.ACTION_PARAM_PREFIX = '_ap_';
@@ -13,6 +13,59 @@ const getMockedControlItem = ({ id = DEFAULT_CONTROL_ID, defaults, }) => ({
13
13
  type: 'control',
14
14
  namespace: NAMESPACE,
15
15
  });
16
+ const stateAndParamsWithParamsOnly = {
17
+ params: {
18
+ paramName: 'param1',
19
+ },
20
+ };
21
+ const stateAndParamsWithStateOnly = {
22
+ state: {
23
+ tabId: 'tabId1',
24
+ },
25
+ };
26
+ const stateAndParamsWithActionParamsInParamsOnly = {
27
+ params: {
28
+ _ap_paramName: 'param1',
29
+ },
30
+ };
31
+ const stateAndParamsWithStateAndActionParamsInParams = {
32
+ state: {
33
+ tabId: 'tabId1',
34
+ },
35
+ params: {
36
+ _ap_paramName: 'param1',
37
+ },
38
+ };
39
+ const stateAndParamsWithParamsAndActionParamsInParams = {
40
+ params: {
41
+ paramName2: 'param2',
42
+ _ap_paramName: 'param1',
43
+ },
44
+ };
45
+ const paramsToTransform = {
46
+ in: {
47
+ param1: 'val 1',
48
+ param2: 'val 2',
49
+ },
50
+ out: {
51
+ [`${constants_1.ACTION_PARAM_PREFIX}param1`]: 'val 1',
52
+ [`${constants_1.ACTION_PARAM_PREFIX}param2`]: 'val 2',
53
+ },
54
+ };
55
+ const exeptActionParam1 = {
56
+ in: stateAndParamsWithParamsOnly.params,
57
+ out: stateAndParamsWithParamsOnly.params,
58
+ };
59
+ const exeptActionParam2 = {
60
+ in: stateAndParamsWithActionParamsInParamsOnly.params,
61
+ out: {},
62
+ };
63
+ const exeptActionParam3 = {
64
+ in: stateAndParamsWithParamsAndActionParamsInParams.params,
65
+ out: {
66
+ paramName2: 'param2',
67
+ },
68
+ };
16
69
  const getMockedWidgetItem = ({ id = DEFAULT_WIDGET_ID, tabs }) => ({
17
70
  id,
18
71
  data: { tabs },
@@ -214,4 +267,28 @@ describe('modules.helpers', () => {
214
267
  }));
215
268
  });
216
269
  });
270
+ describe('actionParams helpers', () => {
271
+ it('check hasActionParams', () => {
272
+ const empty = (0, helpers_1.hasActionParams)({});
273
+ expect(empty).toBeFalsy();
274
+ const withParamsOnly = (0, helpers_1.hasActionParams)(stateAndParamsWithParamsOnly);
275
+ expect(withParamsOnly).toBeFalsy();
276
+ const withStateOnly = (0, helpers_1.hasActionParams)(stateAndParamsWithStateOnly);
277
+ expect(withStateOnly).toBeFalsy();
278
+ const withAPinParams = (0, helpers_1.hasActionParams)(stateAndParamsWithActionParamsInParamsOnly);
279
+ expect(withAPinParams).toBeTruthy();
280
+ const withAPinParamsNState = (0, helpers_1.hasActionParams)(stateAndParamsWithStateAndActionParamsInParams);
281
+ expect(withAPinParamsNState).toBeTruthy();
282
+ const withParamsAndAPinParams = (0, helpers_1.hasActionParams)(stateAndParamsWithParamsAndActionParamsInParams);
283
+ expect(withParamsAndAPinParams).toBeTruthy();
284
+ });
285
+ it('check transformParamsToActionParams', () => {
286
+ expect(paramsToTransform.out).toEqual((0, helpers_1.transformParamsToActionParams)(paramsToTransform.in));
287
+ });
288
+ it('check pickExceptActionParamsFromParams', () => {
289
+ expect(exeptActionParam1.out).toEqual((0, helpers_1.pickExceptActionParamsFromParams)(exeptActionParam1.in));
290
+ expect(exeptActionParam2.out).toEqual((0, helpers_1.pickExceptActionParamsFromParams)(exeptActionParam2.in));
291
+ expect(exeptActionParam3.out).toEqual((0, helpers_1.pickExceptActionParamsFromParams)(exeptActionParam3.in));
292
+ });
293
+ });
217
294
  });
@@ -1,4 +1,4 @@
1
- import { PluginBase, ConfigItem, ItemsStateAndParams, StateAndParamsMetaData, StringParams, ConfigConnection, ConfigAliases, ConfigItemWithTabs, Config } from '../types';
1
+ import { PluginBase, ConfigItem, ItemsStateAndParams, StateAndParamsMetaData, StringParams, ConfigConnection, ConfigAliases, ConfigItemWithTabs, Config, ItemStateAndParams } from '../types';
2
2
  export declare function prerenderItems({ items, plugins, }: {
3
3
  items: ConfigItem[];
4
4
  plugins: PluginBase[];
@@ -25,10 +25,11 @@ export declare function getMapItemsIgnores({ items, ignores, itemsStateAndParams
25
25
  itemsStateAndParams: ItemsStateAndParams;
26
26
  isFirstVersion: boolean;
27
27
  }): Record<string, string[]>;
28
- export declare function mergeParamsWithAliases({ aliases, namespace, params, }: {
28
+ export declare function mergeParamsWithAliases({ aliases, namespace, params, actionParams, }: {
29
29
  aliases: ConfigAliases;
30
30
  namespace: string;
31
31
  params: StringParams;
32
+ actionParams?: StringParams;
32
33
  }): StringParams;
33
34
  export declare function getInitialItemsStateAndParamsMeta(): StateAndParamsMetaData;
34
35
  interface ChangeQueueArg {
@@ -39,4 +40,33 @@ interface ChangeQueueArg {
39
40
  }
40
41
  export declare function addToQueue({ id, tabId, config, itemsStateAndParams, }: ChangeQueueArg): StateAndParamsMetaData;
41
42
  export declare function deleteFromQueue(data: ChangeQueueArg): StateAndParamsMetaData;
43
+ /**
44
+ * public function for getting only actionParams from object (all fields with keys that contains prefix)
45
+ * @param params - object for pick fields
46
+ * @param returnWithPrefix - format of returning actionParams fields (with actionParams prefix or without them)
47
+ *
48
+ * ex1: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}, true) returns {_ap_Year: '2023'}
49
+ * ex2: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}) returns {Year: '2023'}
50
+ */
51
+ export declare function pickActionParamsFromParams(params: ItemStateAndParams['params'], returnWithPrefix?: boolean): StringParams;
52
+ /**
53
+ * public function for getting params from object without actionParams
54
+ * @param params
55
+ */
56
+ export declare function pickExceptActionParamsFromParams(params: ItemStateAndParams['params']): StringParams;
57
+ /**
58
+ * public function for transforming object to actionParams format
59
+ * @param params
60
+ */
61
+ export declare function transformParamsToActionParams(params: ItemStateAndParams['params']): StringParams;
62
+ /**
63
+ * check if object contains actionParams
64
+ * @param conf
65
+ */
66
+ export declare function hasActionParam(conf?: StringParams): boolean;
67
+ /**
68
+ * check if ItemStateAndParams object has actionParams in params or state field
69
+ * @param stateAndParams
70
+ */
71
+ export declare function hasActionParams(stateAndParams: ItemStateAndParams): boolean;
42
72
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteFromQueue = exports.addToQueue = exports.getInitialItemsStateAndParamsMeta = exports.mergeParamsWithAliases = exports.getMapItemsIgnores = exports.resolveItemInnerId = exports.formQueueData = exports.isItemWithTabs = exports.getCurrentVersion = exports.getItemsStateAndParamsMeta = exports.prerenderItems = void 0;
3
+ exports.hasActionParams = exports.hasActionParam = exports.transformParamsToActionParams = exports.pickExceptActionParamsFromParams = exports.pickActionParamsFromParams = exports.deleteFromQueue = exports.addToQueue = exports.getInitialItemsStateAndParamsMeta = exports.mergeParamsWithAliases = exports.getMapItemsIgnores = exports.resolveItemInnerId = exports.formQueueData = exports.isItemWithTabs = exports.getCurrentVersion = exports.getItemsStateAndParamsMeta = exports.prerenderItems = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const keyBy_1 = tslib_1.__importDefault(require("lodash/keyBy"));
6
6
  const get_1 = tslib_1.__importDefault(require("lodash/get"));
@@ -52,7 +52,7 @@ function isItemWithTabs(item) {
52
52
  return Array.isArray((_a = item === null || item === void 0 ? void 0 : item.data) === null || _a === void 0 ? void 0 : _a.tabs);
53
53
  }
54
54
  exports.isItemWithTabs = isItemWithTabs;
55
- // Массив параметров, которые исходят от виджетов, согласно очереди
55
+ // Array of parameters from widgets according to queue
56
56
  function formQueueData({ items, itemsStateAndParams, }) {
57
57
  var _a;
58
58
  const queue = ((_a = getItemsStateAndParamsMeta(itemsStateAndParams)) === null || _a === void 0 ? void 0 : _a.queue) || [];
@@ -77,10 +77,24 @@ function formQueueData({ items, itemsStateAndParams, }) {
77
77
  itemDefaultParams = item.defaults || {};
78
78
  }
79
79
  const itemQueueParams = (0, get_1.default)(itemsStateAndParams, [item.id, 'params'], {});
80
+ const filteredParamsByDefaults = (0, pick_1.default)(itemQueueParams, Object.keys(itemDefaultParams));
81
+ /**
82
+ * filtering actionParams without prefixes by defaults params
83
+ * ex.:
84
+ * itemDefaultParams contains 'Country' in defaults
85
+ * and we receive '_ap_Country' and '_ap_City' in itemQueueParams
86
+ * we need to ignore '_ap_City' param because we don't have actionParam without prefix ('City') in defaults
87
+ */
88
+ const actionParams = pickActionParamsFromParams(itemQueueParams, false) || {};
89
+ const filteredActionParamsByDefaults = (0, pick_1.default)(actionParams, Object.keys(itemDefaultParams));
90
+ /**
91
+ * merging filtered params and filtered actionParams with prefixes
92
+ */
93
+ const params = Object.assign(Object.assign({}, filteredParamsByDefaults), transformParamsToActionParams(filteredActionParamsByDefaults));
80
94
  return {
81
95
  id: item.id,
82
96
  namespace: item.namespace,
83
- params: (0, pick_1.default)(itemQueueParams, Object.keys(itemDefaultParams)),
97
+ params,
84
98
  };
85
99
  })
86
100
  .filter(nonNullable);
@@ -125,10 +139,11 @@ function getMapItemsIgnores({ items, ignores, itemsStateAndParams, isFirstVersio
125
139
  }, {});
126
140
  }
127
141
  exports.getMapItemsIgnores = getMapItemsIgnores;
128
- function mergeParamsWithAliases({ aliases, namespace, params, }) {
142
+ function mergeParamsWithAliases({ aliases, namespace, params, actionParams, }) {
129
143
  const aliasesByNamespace = (0, get_1.default)(aliases, [namespace], []);
130
- return Object.keys(params).reduce((matchedParams, paramKey) => {
131
- const paramValue = params[paramKey];
144
+ const items = Object.assign(Object.assign({}, (params || {})), (actionParams || {}));
145
+ return Object.keys(items).reduce((matchedParams, paramKey) => {
146
+ const paramValue = items[paramKey];
132
147
  const collectAliasesParamsKeys = aliasesByNamespace.reduce((collect, group) => {
133
148
  return group.includes(paramKey) ? collect.concat(group) : collect;
134
149
  }, [paramKey]);
@@ -170,3 +185,77 @@ function deleteFromQueue(data) {
170
185
  return Object.assign(Object.assign({}, meta), { queue: meta.queue.slice(0, -1) });
171
186
  }
172
187
  exports.deleteFromQueue = deleteFromQueue;
188
+ /**
189
+ * public function for getting only actionParams from object (all fields with keys that contains prefix)
190
+ * @param params - object for pick fields
191
+ * @param returnWithPrefix - format of returning actionParams fields (with actionParams prefix or without them)
192
+ *
193
+ * ex1: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}, true) returns {_ap_Year: '2023'}
194
+ * ex2: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}) returns {Year: '2023'}
195
+ */
196
+ function pickActionParamsFromParams(params, returnWithPrefix) {
197
+ if (!params || (0, isEmpty_1.default)(params)) {
198
+ return {};
199
+ }
200
+ const actionParams = {};
201
+ for (const [key, val] of Object.entries(params)) {
202
+ // starts with actionParams prefix (from'_ap_')
203
+ if (key.startsWith(constants_1.ACTION_PARAM_PREFIX)) {
204
+ const paramName = returnWithPrefix ? key : key.slice(constants_1.ACTION_PARAM_PREFIX.length);
205
+ actionParams[paramName] = val;
206
+ }
207
+ }
208
+ return actionParams;
209
+ }
210
+ exports.pickActionParamsFromParams = pickActionParamsFromParams;
211
+ /**
212
+ * public function for getting params from object without actionParams
213
+ * @param params
214
+ */
215
+ function pickExceptActionParamsFromParams(params) {
216
+ if (!params || (0, isEmpty_1.default)(params)) {
217
+ return {};
218
+ }
219
+ const onlyParams = {};
220
+ for (const [key, val] of Object.entries(params)) {
221
+ if (!key.startsWith(constants_1.ACTION_PARAM_PREFIX)) {
222
+ onlyParams[key] = val;
223
+ }
224
+ }
225
+ return onlyParams;
226
+ }
227
+ exports.pickExceptActionParamsFromParams = pickExceptActionParamsFromParams;
228
+ /**
229
+ * public function for transforming object to actionParams format
230
+ * @param params
231
+ */
232
+ function transformParamsToActionParams(params) {
233
+ if (!params || (0, isEmpty_1.default)(params)) {
234
+ return {};
235
+ }
236
+ const actionParams = {};
237
+ for (const [key, val] of Object.entries(params)) {
238
+ actionParams[`${constants_1.ACTION_PARAM_PREFIX}${key}`] = val;
239
+ }
240
+ return actionParams;
241
+ }
242
+ exports.transformParamsToActionParams = transformParamsToActionParams;
243
+ /**
244
+ * check if object contains actionParams
245
+ * @param conf
246
+ */
247
+ function hasActionParam(conf) {
248
+ return Object.keys(conf || {}).some((key) => key.startsWith(constants_1.ACTION_PARAM_PREFIX));
249
+ }
250
+ exports.hasActionParam = hasActionParam;
251
+ /**
252
+ * check if ItemStateAndParams object has actionParams in params or state field
253
+ * @param stateAndParams
254
+ */
255
+ function hasActionParams(stateAndParams) {
256
+ if (!stateAndParams || (0, isEmpty_1.default)(stateAndParams)) {
257
+ return false;
258
+ }
259
+ return hasActionParam(stateAndParams.params);
260
+ }
261
+ exports.hasActionParams = hasActionParams;
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getItemsStateAndParams = exports.getItemsState = exports.getItemsParams = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const groupBy_1 = tslib_1.__importDefault(require("lodash/groupBy"));
6
- const helpers_1 = require("./helpers");
6
+ const intersection_1 = tslib_1.__importDefault(require("lodash/intersection"));
7
+ const omit_1 = tslib_1.__importDefault(require("lodash/omit"));
7
8
  const constants_1 = require("../constants");
9
+ const helpers_1 = require("./helpers");
8
10
  function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, config, itemsStateAndParams, plugins, }) {
9
11
  const { aliases, connections } = config;
10
12
  const items = (0, helpers_1.prerenderItems)({ items: config.items, plugins });
@@ -29,7 +31,7 @@ function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, config, i
29
31
  return items.reduce((itemsParams, item) => {
30
32
  var _a;
31
33
  const { id, namespace } = item;
32
- const getMergedParams = (params) => (0, helpers_1.mergeParamsWithAliases)({ aliases, namespace, params: params || {} });
34
+ const getMergedParams = (params, actionParams) => (0, helpers_1.mergeParamsWithAliases)({ aliases, namespace, params: params || {}, actionParams });
33
35
  const itemIgnores = mapItemsIgnores[id];
34
36
  const affectingItemsWithDefaults = itemsWithDefaultsByNamespace[namespace].filter((itemWithDefaults) => !itemIgnores.includes(itemWithDefaults.id));
35
37
  let itemParams = Object.assign({}, getMergedParams(defaultGlobalParams),
@@ -41,14 +43,32 @@ function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, config, i
41
43
  itemParams = Object.assign(itemParams, ((_a = itemsStateAndParams === null || itemsStateAndParams === void 0 ? void 0 : itemsStateAndParams[id]) === null || _a === void 0 ? void 0 : _a.params) || {});
42
44
  }
43
45
  else {
44
- itemParams = Object.assign(itemParams,
45
- // Параметры согласно очереди применения параметров
46
- queueData.reduce((queueParams, data) => {
46
+ // params according to queue of its applying
47
+ let prevQueueDataWithActionParams = {};
48
+ let queueDataItems = {};
49
+ for (const data of Object.values(queueData)) {
47
50
  if (data.namespace !== namespace || itemIgnores.includes(data.id)) {
48
- return queueParams;
51
+ continue;
52
+ }
53
+ let actionParams;
54
+ let params = data.params;
55
+ const needAliasesForActionParams = data.id !== id && (0, helpers_1.hasActionParam)(data.params);
56
+ if (needAliasesForActionParams) {
57
+ actionParams = (0, helpers_1.pickActionParamsFromParams)(data.params);
58
+ params = (0, helpers_1.pickExceptActionParamsFromParams)(data.params);
59
+ }
60
+ const mergedParams = getMergedParams(params, actionParams);
61
+ const actionParamKeyToClear = (0, intersection_1.default)(Object.keys((0, helpers_1.transformParamsToActionParams)(mergedParams)), Object.keys(prevQueueDataWithActionParams));
62
+ let queueDataRes = Object.assign({}, queueDataItems);
63
+ if (actionParamKeyToClear.length) {
64
+ queueDataRes = (0, omit_1.default)(queueDataItems, actionParamKeyToClear);
49
65
  }
50
- return Object.assign(Object.assign({}, queueParams), getMergedParams(data.params));
51
- }, {}));
66
+ queueDataItems = Object.assign(Object.assign({}, queueDataRes), mergedParams);
67
+ prevQueueDataWithActionParams = (0, helpers_1.hasActionParam)(queueDataItems)
68
+ ? (0, helpers_1.pickActionParamsFromParams)(data.params, true)
69
+ : {};
70
+ }
71
+ itemParams = Object.assign(itemParams, queueDataItems);
52
72
  }
53
73
  return Object.assign(Object.assign({}, itemsParams), { [id]: itemParams });
54
74
  }, {});
@@ -261,6 +261,116 @@ exports.stateAndParams3 = {
261
261
  },
262
262
  },
263
263
  };
264
+ const stateAndParamsForAP1 = {
265
+ in: {
266
+ Q8: { params: { _ap_Country: 'Italy' } },
267
+ __meta__: { queue: [{ id: 'Q8', tabId: 'K0' }], version: 2 },
268
+ },
269
+ out: {
270
+ L5: {
271
+ params: { Country: 'Italy', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Italy' },
272
+ state: {},
273
+ },
274
+ Q8: {
275
+ params: {
276
+ Country: '',
277
+ _ap_Country: 'Italy',
278
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
279
+ },
280
+ state: {},
281
+ },
282
+ al: {
283
+ params: { Country: 'Italy', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Italy' },
284
+ state: {},
285
+ },
286
+ },
287
+ };
288
+ const stateAndParamsForAP2 = {
289
+ in: {
290
+ L5: {
291
+ params: { 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
292
+ },
293
+ Q8: {
294
+ params: { _ap_Country: 'Italy' },
295
+ },
296
+ __meta__: { queue: [{ id: 'Q8', tabId: 'K0' }, { id: 'L5' }], version: 2 },
297
+ },
298
+ out: {
299
+ L5: {
300
+ params: { Country: 'Belgium', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
301
+ state: {},
302
+ },
303
+ Q8: {
304
+ params: { Country: 'Belgium', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
305
+ state: {},
306
+ },
307
+ al: {
308
+ params: { Country: 'Belgium', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
309
+ state: {},
310
+ },
311
+ },
312
+ };
313
+ const stateAndParamsForAP3 = {
314
+ in: {
315
+ Q8: { params: { _ap_Country: 'Italy' } },
316
+ L5: { params: { 'd079937f-6bc4-4133-9171-40092bb20d6f': '' } },
317
+ __meta__: { queue: [{ id: 'Q8', tabId: 'K0' }, { id: 'L5' }], version: 2 },
318
+ },
319
+ out: {
320
+ L5: {
321
+ params: {
322
+ Country: '',
323
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
324
+ },
325
+ state: {},
326
+ },
327
+ Q8: {
328
+ params: {
329
+ Country: '',
330
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
331
+ },
332
+ state: {},
333
+ },
334
+ al: {
335
+ params: {
336
+ Country: '',
337
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
338
+ },
339
+ state: {},
340
+ },
341
+ },
342
+ };
343
+ const stateAndParamsForAP4 = {
344
+ in: {
345
+ Q8: { params: { _ap_Country: '' } },
346
+ L5: { params: { 'd079937f-6bc4-4133-9171-40092bb20d6f': '' } },
347
+ __meta__: { queue: [{ id: 'L5' }, { id: 'Q8', tabId: 'K0' }], version: 2 },
348
+ },
349
+ out: {
350
+ L5: {
351
+ params: {
352
+ Country: '',
353
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
354
+ },
355
+ state: {},
356
+ },
357
+ Q8: {
358
+ params: {
359
+ Country: '',
360
+ _ap_Country: '',
361
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
362
+ },
363
+ state: {},
364
+ },
365
+ al: {
366
+ params: {
367
+ Country: '',
368
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
369
+ },
370
+ state: {},
371
+ },
372
+ },
373
+ };
264
374
  const configs = configs_json_1.default.configs;
265
375
  describe('getItemsStateAndParamsDL', () => {
266
376
  describe('old version fallback', () => {
@@ -297,3 +407,49 @@ describe('getItemsStateAndParamsDL', () => {
297
407
  });
298
408
  });
299
409
  });
410
+ describe('getItemsStateAndParams actionParams variants check', () => {
411
+ describe('action and params state 1', () => {
412
+ const resultItemsStateAndParams = (0, datalens_1.getItemsStateAndParamsDL)({
413
+ defaultGlobalParams: {},
414
+ globalParams: {},
415
+ config: configs[2],
416
+ itemsStateAndParams: stateAndParamsForAP1.in,
417
+ });
418
+ it('return stateAndParamsForAP1.out', () => {
419
+ expect(resultItemsStateAndParams).toEqual((0, omit_1.default)(stateAndParamsForAP1.out, constants_1.META_KEY));
420
+ });
421
+ });
422
+ describe('action and params state 2', () => {
423
+ const resultItemsStateAndParams = (0, datalens_1.getItemsStateAndParamsDL)({
424
+ defaultGlobalParams: {},
425
+ globalParams: {},
426
+ config: configs[2],
427
+ itemsStateAndParams: stateAndParamsForAP2.in,
428
+ });
429
+ it('return stateAndParamsForAP2.out', () => {
430
+ expect(resultItemsStateAndParams).toEqual((0, omit_1.default)(stateAndParamsForAP2.out, constants_1.META_KEY));
431
+ });
432
+ });
433
+ describe('action and params state 3', () => {
434
+ const resultItemsStateAndParams = (0, datalens_1.getItemsStateAndParamsDL)({
435
+ defaultGlobalParams: {},
436
+ globalParams: {},
437
+ config: configs[2],
438
+ itemsStateAndParams: stateAndParamsForAP3.in,
439
+ });
440
+ it('return stateAndParamsForAP3.out', () => {
441
+ expect(resultItemsStateAndParams).toEqual((0, omit_1.default)(stateAndParamsForAP3.out, constants_1.META_KEY));
442
+ });
443
+ });
444
+ describe('action and params state 4', () => {
445
+ const resultItemsStateAndParams = (0, datalens_1.getItemsStateAndParamsDL)({
446
+ defaultGlobalParams: {},
447
+ globalParams: {},
448
+ config: configs[2],
449
+ itemsStateAndParams: stateAndParamsForAP4.in,
450
+ });
451
+ it('return stateAndParamsForAP4.out', () => {
452
+ expect(resultItemsStateAndParams).toEqual((0, omit_1.default)(stateAndParamsForAP4.out, constants_1.META_KEY));
453
+ });
454
+ });
455
+ });
@@ -64,9 +64,14 @@ function removeItemVersion1({ id, config, itemsStateAndParams }) {
64
64
  itemsStateAndParams: newItemsStateAndParams,
65
65
  };
66
66
  }
67
- function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams) {
67
+ function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams, paramsSettings) {
68
68
  var _a;
69
+ const paramsTypeName = (paramsSettings === null || paramsSettings === void 0 ? void 0 : paramsSettings.type) || 'params';
70
+ const isActionParamsMode = paramsTypeName === 'actionParams';
69
71
  let allowedParams = {};
72
+ const stateParamsConf = isActionParamsMode
73
+ ? (0, shared_1.pickActionParamsFromParams)(stateAndParams.params, false)
74
+ : stateAndParams.params;
70
75
  if ((0, shared_1.isItemWithTabs)(item)) {
71
76
  let tab;
72
77
  if ('state' in stateAndParams && ((_a = stateAndParams.state) === null || _a === void 0 ? void 0 : _a.tabId)) {
@@ -76,14 +81,19 @@ function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams) {
76
81
  const tabId = (0, shared_1.resolveItemInnerId)({ item, itemsStateAndParams });
77
82
  tab = item.data.tabs.find(({ id }) => id === tabId);
78
83
  }
79
- allowedParams = (0, pick_1.default)(stateAndParams.params, Object.keys((tab === null || tab === void 0 ? void 0 : tab.params) || {}));
84
+ allowedParams = (0, pick_1.default)(stateParamsConf, Object.keys((tab === null || tab === void 0 ? void 0 : tab.params) || {}));
80
85
  }
81
86
  else {
82
- allowedParams = (0, pick_1.default)(stateAndParams.params, Object.keys(item.defaults || {}));
87
+ allowedParams = (0, pick_1.default)(stateParamsConf, Object.keys(item.defaults || {}));
83
88
  }
84
- if (Object.keys(allowedParams).length !== Object.keys(stateAndParams.params || {}).length) {
89
+ if (Object.keys(allowedParams || {}).length !== Object.keys(stateParamsConf || {}).length) {
85
90
  console.warn('Параметры, которых нет в defaults, будут проигнорированы!');
86
91
  }
92
+ if (isActionParamsMode) {
93
+ return (paramsSettings === null || paramsSettings === void 0 ? void 0 : paramsSettings.returnPrefix)
94
+ ? (0, shared_1.transformParamsToActionParams)(allowedParams)
95
+ : allowedParams;
96
+ }
87
97
  return allowedParams;
88
98
  }
89
99
  function changeStateAndParamsVersion1({ id: initiatorId, config, stateAndParams, itemsStateAndParams, }) {
@@ -244,6 +254,7 @@ class UpdateManager {
244
254
  const currentMeta = (0, shared_1.getItemsStateAndParamsMeta)(itemsStateAndParams);
245
255
  if ('params' in stateAndParams) {
246
256
  const allowableParams = getAllowableChangedParams(initiatorItem, stateAndParams, itemsStateAndParams);
257
+ const allowableActionParams = getAllowableChangedParams(initiatorItem, stateAndParams, itemsStateAndParams, { type: 'actionParams', returnPrefix: true });
247
258
  const tabId = (0, shared_1.isItemWithTabs)(initiatorItem)
248
259
  ? newTabId || (0, shared_1.resolveItemInnerId)({ item: initiatorItem, itemsStateAndParams })
249
260
  : undefined;
@@ -254,15 +265,16 @@ class UpdateManager {
254
265
  if (isTabSwitched) {
255
266
  commandUpdateParams = '$set';
256
267
  }
257
- return (0, immutability_helper_1.default)(itemsStateAndParams, {
268
+ const obj = {
258
269
  $unset: unusedIds,
259
270
  [initiatorId]: {
260
271
  $auto: Object.assign({ params: {
261
- [commandUpdateParams]: allowableParams,
272
+ [commandUpdateParams]: Object.assign(Object.assign({}, allowableParams), allowableActionParams),
262
273
  } }, (hasState ? { state: { $set: stateAndParams.state } } : {})),
263
274
  },
264
275
  [shared_1.META_KEY]: { $set: meta },
265
- });
276
+ };
277
+ return (0, immutability_helper_1.default)(itemsStateAndParams, obj);
266
278
  }
267
279
  else if (hasState) {
268
280
  let metaSpec = {};
@@ -17,6 +17,7 @@ export interface OverlayControlItem {
17
17
  allWidgetsControls?: boolean;
18
18
  excludeWidgetsTypes?: Array<PluginBase['type']>;
19
19
  id?: string;
20
+ qa?: string;
20
21
  }
21
22
  export interface OverlayCustomControlItem {
22
23
  id: string;
@@ -26,6 +27,7 @@ export interface OverlayCustomControlItem {
26
27
  handler?: (item: ConfigItem, params: StringParams) => void;
27
28
  visible?: (item: ConfigItem) => boolean;
28
29
  className?: string;
30
+ qa?: string;
29
31
  }
30
32
  interface OverlayControlsDefaultProps {
31
33
  position: OverlayControlsPosition;
@@ -23,9 +23,9 @@ class OverlayControls extends React.Component {
23
23
  super(...arguments);
24
24
  this.renderControlsItem = (item, index, length) => {
25
25
  const { view, size } = this.props;
26
- const { title, handler, icon, iconSize } = item;
26
+ const { title, handler, icon, iconSize, qa } = item;
27
27
  const onItemClickHandler = typeof handler === 'function' ? handler : noop;
28
- return (React.createElement(Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => onItemClickHandler(this.props.configItem) },
28
+ return (React.createElement(Button, { key: index, view: view, size: size, title: title, pin: this.getControlItemPinStyle(index, length), onClick: () => onItemClickHandler(this.props.configItem), qa: qa },
29
29
  React.createElement(Icon, { data: icon || CogIcon, size: icon ? iconSize : 24 })));
30
30
  };
31
31
  this.getCustomLeftOverlayControls = () => {
@@ -168,10 +168,11 @@ class OverlayControls extends React.Component {
168
168
  icon: item.icon,
169
169
  action: itemAction,
170
170
  className: item.className,
171
+ qa: item.qa,
171
172
  };
172
173
  });
173
174
  items = items.filter(Boolean);
174
- return (React.createElement(DropdownMenu, { items: items, switcher: React.createElement(Button, { view: view, size: size, pin: "brick-round" },
175
+ return (React.createElement(DropdownMenu, { items: items, switcher: React.createElement(Button, { view: view, size: size, pin: "brick-round", qa: "dashkit-overlay-control-menu" },
175
176
  React.createElement(Icon, { data: DotsIcon, size: "16" })) }));
176
177
  }
177
178
  getControlItemPinStyle(index, itemsLength) {
@@ -1 +1,2 @@
1
1
  export * from './DashKit';
2
+ export { OverlayControlItem } from './OverlayControls/OverlayControls';
@@ -1,2 +1,3 @@
1
1
  export declare const CURRENT_VERSION = 2;
2
2
  export declare const META_KEY = "__meta__";
3
+ export declare const ACTION_PARAM_PREFIX = "_ap_";
@@ -1,2 +1,3 @@
1
1
  export const CURRENT_VERSION = 2;
2
2
  export const META_KEY = '__meta__';
3
+ export const ACTION_PARAM_PREFIX = '_ap_';
@@ -1,5 +1,5 @@
1
- import { META_KEY } from '../../constants';
2
- import { formQueueData } from '../helpers';
1
+ import { ACTION_PARAM_PREFIX, META_KEY } from '../../constants';
2
+ import { formQueueData, hasActionParams, pickExceptActionParamsFromParams, transformParamsToActionParams, } from '../helpers';
3
3
  const DEFAULT_CONTROL_ID = 'controlId';
4
4
  const DEFAULT_WIDGET_ID = 'widgetId';
5
5
  const DEFAULT_WIDGET_TAB_ID = 'widget_tabId';
@@ -11,6 +11,59 @@ const getMockedControlItem = ({ id = DEFAULT_CONTROL_ID, defaults, }) => ({
11
11
  type: 'control',
12
12
  namespace: NAMESPACE,
13
13
  });
14
+ const stateAndParamsWithParamsOnly = {
15
+ params: {
16
+ paramName: 'param1',
17
+ },
18
+ };
19
+ const stateAndParamsWithStateOnly = {
20
+ state: {
21
+ tabId: 'tabId1',
22
+ },
23
+ };
24
+ const stateAndParamsWithActionParamsInParamsOnly = {
25
+ params: {
26
+ _ap_paramName: 'param1',
27
+ },
28
+ };
29
+ const stateAndParamsWithStateAndActionParamsInParams = {
30
+ state: {
31
+ tabId: 'tabId1',
32
+ },
33
+ params: {
34
+ _ap_paramName: 'param1',
35
+ },
36
+ };
37
+ const stateAndParamsWithParamsAndActionParamsInParams = {
38
+ params: {
39
+ paramName2: 'param2',
40
+ _ap_paramName: 'param1',
41
+ },
42
+ };
43
+ const paramsToTransform = {
44
+ in: {
45
+ param1: 'val 1',
46
+ param2: 'val 2',
47
+ },
48
+ out: {
49
+ [`${ACTION_PARAM_PREFIX}param1`]: 'val 1',
50
+ [`${ACTION_PARAM_PREFIX}param2`]: 'val 2',
51
+ },
52
+ };
53
+ const exeptActionParam1 = {
54
+ in: stateAndParamsWithParamsOnly.params,
55
+ out: stateAndParamsWithParamsOnly.params,
56
+ };
57
+ const exeptActionParam2 = {
58
+ in: stateAndParamsWithActionParamsInParamsOnly.params,
59
+ out: {},
60
+ };
61
+ const exeptActionParam3 = {
62
+ in: stateAndParamsWithParamsAndActionParamsInParams.params,
63
+ out: {
64
+ paramName2: 'param2',
65
+ },
66
+ };
14
67
  const getMockedWidgetItem = ({ id = DEFAULT_WIDGET_ID, tabs }) => ({
15
68
  id,
16
69
  data: { tabs },
@@ -212,4 +265,28 @@ describe('modules.helpers', () => {
212
265
  }));
213
266
  });
214
267
  });
268
+ describe('actionParams helpers', () => {
269
+ it('check hasActionParams', () => {
270
+ const empty = hasActionParams({});
271
+ expect(empty).toBeFalsy();
272
+ const withParamsOnly = hasActionParams(stateAndParamsWithParamsOnly);
273
+ expect(withParamsOnly).toBeFalsy();
274
+ const withStateOnly = hasActionParams(stateAndParamsWithStateOnly);
275
+ expect(withStateOnly).toBeFalsy();
276
+ const withAPinParams = hasActionParams(stateAndParamsWithActionParamsInParamsOnly);
277
+ expect(withAPinParams).toBeTruthy();
278
+ const withAPinParamsNState = hasActionParams(stateAndParamsWithStateAndActionParamsInParams);
279
+ expect(withAPinParamsNState).toBeTruthy();
280
+ const withParamsAndAPinParams = hasActionParams(stateAndParamsWithParamsAndActionParamsInParams);
281
+ expect(withParamsAndAPinParams).toBeTruthy();
282
+ });
283
+ it('check transformParamsToActionParams', () => {
284
+ expect(paramsToTransform.out).toEqual(transformParamsToActionParams(paramsToTransform.in));
285
+ });
286
+ it('check pickExceptActionParamsFromParams', () => {
287
+ expect(exeptActionParam1.out).toEqual(pickExceptActionParamsFromParams(exeptActionParam1.in));
288
+ expect(exeptActionParam2.out).toEqual(pickExceptActionParamsFromParams(exeptActionParam2.in));
289
+ expect(exeptActionParam3.out).toEqual(pickExceptActionParamsFromParams(exeptActionParam3.in));
290
+ });
291
+ });
215
292
  });
@@ -1,4 +1,4 @@
1
- import { PluginBase, ConfigItem, ItemsStateAndParams, StateAndParamsMetaData, StringParams, ConfigConnection, ConfigAliases, ConfigItemWithTabs, Config } from '../types';
1
+ import { PluginBase, ConfigItem, ItemsStateAndParams, StateAndParamsMetaData, StringParams, ConfigConnection, ConfigAliases, ConfigItemWithTabs, Config, ItemStateAndParams } from '../types';
2
2
  export declare function prerenderItems({ items, plugins, }: {
3
3
  items: ConfigItem[];
4
4
  plugins: PluginBase[];
@@ -25,10 +25,11 @@ export declare function getMapItemsIgnores({ items, ignores, itemsStateAndParams
25
25
  itemsStateAndParams: ItemsStateAndParams;
26
26
  isFirstVersion: boolean;
27
27
  }): Record<string, string[]>;
28
- export declare function mergeParamsWithAliases({ aliases, namespace, params, }: {
28
+ export declare function mergeParamsWithAliases({ aliases, namespace, params, actionParams, }: {
29
29
  aliases: ConfigAliases;
30
30
  namespace: string;
31
31
  params: StringParams;
32
+ actionParams?: StringParams;
32
33
  }): StringParams;
33
34
  export declare function getInitialItemsStateAndParamsMeta(): StateAndParamsMetaData;
34
35
  interface ChangeQueueArg {
@@ -39,4 +40,33 @@ interface ChangeQueueArg {
39
40
  }
40
41
  export declare function addToQueue({ id, tabId, config, itemsStateAndParams, }: ChangeQueueArg): StateAndParamsMetaData;
41
42
  export declare function deleteFromQueue(data: ChangeQueueArg): StateAndParamsMetaData;
43
+ /**
44
+ * public function for getting only actionParams from object (all fields with keys that contains prefix)
45
+ * @param params - object for pick fields
46
+ * @param returnWithPrefix - format of returning actionParams fields (with actionParams prefix or without them)
47
+ *
48
+ * ex1: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}, true) returns {_ap_Year: '2023'}
49
+ * ex2: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}) returns {Year: '2023'}
50
+ */
51
+ export declare function pickActionParamsFromParams(params: ItemStateAndParams['params'], returnWithPrefix?: boolean): StringParams;
52
+ /**
53
+ * public function for getting params from object without actionParams
54
+ * @param params
55
+ */
56
+ export declare function pickExceptActionParamsFromParams(params: ItemStateAndParams['params']): StringParams;
57
+ /**
58
+ * public function for transforming object to actionParams format
59
+ * @param params
60
+ */
61
+ export declare function transformParamsToActionParams(params: ItemStateAndParams['params']): StringParams;
62
+ /**
63
+ * check if object contains actionParams
64
+ * @param conf
65
+ */
66
+ export declare function hasActionParam(conf?: StringParams): boolean;
67
+ /**
68
+ * check if ItemStateAndParams object has actionParams in params or state field
69
+ * @param stateAndParams
70
+ */
71
+ export declare function hasActionParams(stateAndParams: ItemStateAndParams): boolean;
42
72
  export {};
@@ -3,7 +3,7 @@ import get from 'lodash/get';
3
3
  import invert from 'lodash/invert';
4
4
  import isEmpty from 'lodash/isEmpty';
5
5
  import pick from 'lodash/pick';
6
- import { META_KEY, CURRENT_VERSION } from '../constants';
6
+ import { META_KEY, CURRENT_VERSION, ACTION_PARAM_PREFIX } from '../constants';
7
7
  function getNormalizedPlugins(plugins) {
8
8
  return keyBy(plugins, 'type');
9
9
  }
@@ -44,7 +44,7 @@ export function isItemWithTabs(item) {
44
44
  var _a;
45
45
  return Array.isArray((_a = item === null || item === void 0 ? void 0 : item.data) === null || _a === void 0 ? void 0 : _a.tabs);
46
46
  }
47
- // Массив параметров, которые исходят от виджетов, согласно очереди
47
+ // Array of parameters from widgets according to queue
48
48
  export function formQueueData({ items, itemsStateAndParams, }) {
49
49
  var _a;
50
50
  const queue = ((_a = getItemsStateAndParamsMeta(itemsStateAndParams)) === null || _a === void 0 ? void 0 : _a.queue) || [];
@@ -69,10 +69,24 @@ export function formQueueData({ items, itemsStateAndParams, }) {
69
69
  itemDefaultParams = item.defaults || {};
70
70
  }
71
71
  const itemQueueParams = get(itemsStateAndParams, [item.id, 'params'], {});
72
+ const filteredParamsByDefaults = pick(itemQueueParams, Object.keys(itemDefaultParams));
73
+ /**
74
+ * filtering actionParams without prefixes by defaults params
75
+ * ex.:
76
+ * itemDefaultParams contains 'Country' in defaults
77
+ * and we receive '_ap_Country' and '_ap_City' in itemQueueParams
78
+ * we need to ignore '_ap_City' param because we don't have actionParam without prefix ('City') in defaults
79
+ */
80
+ const actionParams = pickActionParamsFromParams(itemQueueParams, false) || {};
81
+ const filteredActionParamsByDefaults = pick(actionParams, Object.keys(itemDefaultParams));
82
+ /**
83
+ * merging filtered params and filtered actionParams with prefixes
84
+ */
85
+ const params = Object.assign(Object.assign({}, filteredParamsByDefaults), transformParamsToActionParams(filteredActionParamsByDefaults));
72
86
  return {
73
87
  id: item.id,
74
88
  namespace: item.namespace,
75
- params: pick(itemQueueParams, Object.keys(itemDefaultParams)),
89
+ params,
76
90
  };
77
91
  })
78
92
  .filter(nonNullable);
@@ -114,10 +128,11 @@ export function getMapItemsIgnores({ items, ignores, itemsStateAndParams, isFirs
114
128
  .map(({ to }) => invertedMapIds[to]) });
115
129
  }, {});
116
130
  }
117
- export function mergeParamsWithAliases({ aliases, namespace, params, }) {
131
+ export function mergeParamsWithAliases({ aliases, namespace, params, actionParams, }) {
118
132
  const aliasesByNamespace = get(aliases, [namespace], []);
119
- return Object.keys(params).reduce((matchedParams, paramKey) => {
120
- const paramValue = params[paramKey];
133
+ const items = Object.assign(Object.assign({}, (params || {})), (actionParams || {}));
134
+ return Object.keys(items).reduce((matchedParams, paramKey) => {
135
+ const paramValue = items[paramKey];
121
136
  const collectAliasesParamsKeys = aliasesByNamespace.reduce((collect, group) => {
122
137
  return group.includes(paramKey) ? collect.concat(group) : collect;
123
138
  }, [paramKey]);
@@ -155,3 +170,72 @@ export function deleteFromQueue(data) {
155
170
  const meta = addToQueue(data);
156
171
  return Object.assign(Object.assign({}, meta), { queue: meta.queue.slice(0, -1) });
157
172
  }
173
+ /**
174
+ * public function for getting only actionParams from object (all fields with keys that contains prefix)
175
+ * @param params - object for pick fields
176
+ * @param returnWithPrefix - format of returning actionParams fields (with actionParams prefix or without them)
177
+ *
178
+ * ex1: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}, true) returns {_ap_Year: '2023'}
179
+ * ex2: pickActionParamsFromParams({City: 'NY', _ap_Year: '2023'}) returns {Year: '2023'}
180
+ */
181
+ export function pickActionParamsFromParams(params, returnWithPrefix) {
182
+ if (!params || isEmpty(params)) {
183
+ return {};
184
+ }
185
+ const actionParams = {};
186
+ for (const [key, val] of Object.entries(params)) {
187
+ // starts with actionParams prefix (from'_ap_')
188
+ if (key.startsWith(ACTION_PARAM_PREFIX)) {
189
+ const paramName = returnWithPrefix ? key : key.slice(ACTION_PARAM_PREFIX.length);
190
+ actionParams[paramName] = val;
191
+ }
192
+ }
193
+ return actionParams;
194
+ }
195
+ /**
196
+ * public function for getting params from object without actionParams
197
+ * @param params
198
+ */
199
+ export function pickExceptActionParamsFromParams(params) {
200
+ if (!params || isEmpty(params)) {
201
+ return {};
202
+ }
203
+ const onlyParams = {};
204
+ for (const [key, val] of Object.entries(params)) {
205
+ if (!key.startsWith(ACTION_PARAM_PREFIX)) {
206
+ onlyParams[key] = val;
207
+ }
208
+ }
209
+ return onlyParams;
210
+ }
211
+ /**
212
+ * public function for transforming object to actionParams format
213
+ * @param params
214
+ */
215
+ export function transformParamsToActionParams(params) {
216
+ if (!params || isEmpty(params)) {
217
+ return {};
218
+ }
219
+ const actionParams = {};
220
+ for (const [key, val] of Object.entries(params)) {
221
+ actionParams[`${ACTION_PARAM_PREFIX}${key}`] = val;
222
+ }
223
+ return actionParams;
224
+ }
225
+ /**
226
+ * check if object contains actionParams
227
+ * @param conf
228
+ */
229
+ export function hasActionParam(conf) {
230
+ return Object.keys(conf || {}).some((key) => key.startsWith(ACTION_PARAM_PREFIX));
231
+ }
232
+ /**
233
+ * check if ItemStateAndParams object has actionParams in params or state field
234
+ * @param stateAndParams
235
+ */
236
+ export function hasActionParams(stateAndParams) {
237
+ if (!stateAndParams || isEmpty(stateAndParams)) {
238
+ return false;
239
+ }
240
+ return hasActionParam(stateAndParams.params);
241
+ }
@@ -1,6 +1,8 @@
1
1
  import groupBy from 'lodash/groupBy';
2
- import { prerenderItems, formQueueData, getMapItemsIgnores, mergeParamsWithAliases, getCurrentVersion, } from './helpers';
2
+ import intersection from 'lodash/intersection';
3
+ import omit from 'lodash/omit';
3
4
  import { META_KEY } from '../constants';
5
+ import { prerenderItems, formQueueData, getMapItemsIgnores, mergeParamsWithAliases, getCurrentVersion, pickActionParamsFromParams, hasActionParam, pickExceptActionParamsFromParams, transformParamsToActionParams, } from './helpers';
4
6
  export function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, config, itemsStateAndParams, plugins, }) {
5
7
  const { aliases, connections } = config;
6
8
  const items = prerenderItems({ items: config.items, plugins });
@@ -25,7 +27,7 @@ export function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, co
25
27
  return items.reduce((itemsParams, item) => {
26
28
  var _a;
27
29
  const { id, namespace } = item;
28
- const getMergedParams = (params) => mergeParamsWithAliases({ aliases, namespace, params: params || {} });
30
+ const getMergedParams = (params, actionParams) => mergeParamsWithAliases({ aliases, namespace, params: params || {}, actionParams });
29
31
  const itemIgnores = mapItemsIgnores[id];
30
32
  const affectingItemsWithDefaults = itemsWithDefaultsByNamespace[namespace].filter((itemWithDefaults) => !itemIgnores.includes(itemWithDefaults.id));
31
33
  let itemParams = Object.assign({}, getMergedParams(defaultGlobalParams),
@@ -37,14 +39,32 @@ export function getItemsParams({ defaultGlobalParams = {}, globalParams = {}, co
37
39
  itemParams = Object.assign(itemParams, ((_a = itemsStateAndParams === null || itemsStateAndParams === void 0 ? void 0 : itemsStateAndParams[id]) === null || _a === void 0 ? void 0 : _a.params) || {});
38
40
  }
39
41
  else {
40
- itemParams = Object.assign(itemParams,
41
- // Параметры согласно очереди применения параметров
42
- queueData.reduce((queueParams, data) => {
42
+ // params according to queue of its applying
43
+ let prevQueueDataWithActionParams = {};
44
+ let queueDataItems = {};
45
+ for (const data of Object.values(queueData)) {
43
46
  if (data.namespace !== namespace || itemIgnores.includes(data.id)) {
44
- return queueParams;
47
+ continue;
45
48
  }
46
- return Object.assign(Object.assign({}, queueParams), getMergedParams(data.params));
47
- }, {}));
49
+ let actionParams;
50
+ let params = data.params;
51
+ const needAliasesForActionParams = data.id !== id && hasActionParam(data.params);
52
+ if (needAliasesForActionParams) {
53
+ actionParams = pickActionParamsFromParams(data.params);
54
+ params = pickExceptActionParamsFromParams(data.params);
55
+ }
56
+ const mergedParams = getMergedParams(params, actionParams);
57
+ const actionParamKeyToClear = intersection(Object.keys(transformParamsToActionParams(mergedParams)), Object.keys(prevQueueDataWithActionParams));
58
+ let queueDataRes = Object.assign({}, queueDataItems);
59
+ if (actionParamKeyToClear.length) {
60
+ queueDataRes = omit(queueDataItems, actionParamKeyToClear);
61
+ }
62
+ queueDataItems = Object.assign(Object.assign({}, queueDataRes), mergedParams);
63
+ prevQueueDataWithActionParams = hasActionParam(queueDataItems)
64
+ ? pickActionParamsFromParams(data.params, true)
65
+ : {};
66
+ }
67
+ itemParams = Object.assign(itemParams, queueDataItems);
48
68
  }
49
69
  return Object.assign(Object.assign({}, itemsParams), { [id]: itemParams });
50
70
  }, {});
@@ -257,6 +257,116 @@ export const stateAndParams3 = {
257
257
  },
258
258
  },
259
259
  };
260
+ const stateAndParamsForAP1 = {
261
+ in: {
262
+ Q8: { params: { _ap_Country: 'Italy' } },
263
+ __meta__: { queue: [{ id: 'Q8', tabId: 'K0' }], version: 2 },
264
+ },
265
+ out: {
266
+ L5: {
267
+ params: { Country: 'Italy', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Italy' },
268
+ state: {},
269
+ },
270
+ Q8: {
271
+ params: {
272
+ Country: '',
273
+ _ap_Country: 'Italy',
274
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
275
+ },
276
+ state: {},
277
+ },
278
+ al: {
279
+ params: { Country: 'Italy', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Italy' },
280
+ state: {},
281
+ },
282
+ },
283
+ };
284
+ const stateAndParamsForAP2 = {
285
+ in: {
286
+ L5: {
287
+ params: { 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
288
+ },
289
+ Q8: {
290
+ params: { _ap_Country: 'Italy' },
291
+ },
292
+ __meta__: { queue: [{ id: 'Q8', tabId: 'K0' }, { id: 'L5' }], version: 2 },
293
+ },
294
+ out: {
295
+ L5: {
296
+ params: { Country: 'Belgium', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
297
+ state: {},
298
+ },
299
+ Q8: {
300
+ params: { Country: 'Belgium', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
301
+ state: {},
302
+ },
303
+ al: {
304
+ params: { Country: 'Belgium', 'd079937f-6bc4-4133-9171-40092bb20d6f': 'Belgium' },
305
+ state: {},
306
+ },
307
+ },
308
+ };
309
+ const stateAndParamsForAP3 = {
310
+ in: {
311
+ Q8: { params: { _ap_Country: 'Italy' } },
312
+ L5: { params: { 'd079937f-6bc4-4133-9171-40092bb20d6f': '' } },
313
+ __meta__: { queue: [{ id: 'Q8', tabId: 'K0' }, { id: 'L5' }], version: 2 },
314
+ },
315
+ out: {
316
+ L5: {
317
+ params: {
318
+ Country: '',
319
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
320
+ },
321
+ state: {},
322
+ },
323
+ Q8: {
324
+ params: {
325
+ Country: '',
326
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
327
+ },
328
+ state: {},
329
+ },
330
+ al: {
331
+ params: {
332
+ Country: '',
333
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
334
+ },
335
+ state: {},
336
+ },
337
+ },
338
+ };
339
+ const stateAndParamsForAP4 = {
340
+ in: {
341
+ Q8: { params: { _ap_Country: '' } },
342
+ L5: { params: { 'd079937f-6bc4-4133-9171-40092bb20d6f': '' } },
343
+ __meta__: { queue: [{ id: 'L5' }, { id: 'Q8', tabId: 'K0' }], version: 2 },
344
+ },
345
+ out: {
346
+ L5: {
347
+ params: {
348
+ Country: '',
349
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
350
+ },
351
+ state: {},
352
+ },
353
+ Q8: {
354
+ params: {
355
+ Country: '',
356
+ _ap_Country: '',
357
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
358
+ },
359
+ state: {},
360
+ },
361
+ al: {
362
+ params: {
363
+ Country: '',
364
+ 'd079937f-6bc4-4133-9171-40092bb20d6f': '',
365
+ },
366
+ state: {},
367
+ },
368
+ },
369
+ };
260
370
  const configs = mockConfigs.configs;
261
371
  describe('getItemsStateAndParamsDL', () => {
262
372
  describe('old version fallback', () => {
@@ -293,3 +403,49 @@ describe('getItemsStateAndParamsDL', () => {
293
403
  });
294
404
  });
295
405
  });
406
+ describe('getItemsStateAndParams actionParams variants check', () => {
407
+ describe('action and params state 1', () => {
408
+ const resultItemsStateAndParams = getItemsStateAndParamsDL({
409
+ defaultGlobalParams: {},
410
+ globalParams: {},
411
+ config: configs[2],
412
+ itemsStateAndParams: stateAndParamsForAP1.in,
413
+ });
414
+ it('return stateAndParamsForAP1.out', () => {
415
+ expect(resultItemsStateAndParams).toEqual(omit(stateAndParamsForAP1.out, META_KEY));
416
+ });
417
+ });
418
+ describe('action and params state 2', () => {
419
+ const resultItemsStateAndParams = getItemsStateAndParamsDL({
420
+ defaultGlobalParams: {},
421
+ globalParams: {},
422
+ config: configs[2],
423
+ itemsStateAndParams: stateAndParamsForAP2.in,
424
+ });
425
+ it('return stateAndParamsForAP2.out', () => {
426
+ expect(resultItemsStateAndParams).toEqual(omit(stateAndParamsForAP2.out, META_KEY));
427
+ });
428
+ });
429
+ describe('action and params state 3', () => {
430
+ const resultItemsStateAndParams = getItemsStateAndParamsDL({
431
+ defaultGlobalParams: {},
432
+ globalParams: {},
433
+ config: configs[2],
434
+ itemsStateAndParams: stateAndParamsForAP3.in,
435
+ });
436
+ it('return stateAndParamsForAP3.out', () => {
437
+ expect(resultItemsStateAndParams).toEqual(omit(stateAndParamsForAP3.out, META_KEY));
438
+ });
439
+ });
440
+ describe('action and params state 4', () => {
441
+ const resultItemsStateAndParams = getItemsStateAndParamsDL({
442
+ defaultGlobalParams: {},
443
+ globalParams: {},
444
+ config: configs[2],
445
+ itemsStateAndParams: stateAndParamsForAP4.in,
446
+ });
447
+ it('return stateAndParamsForAP4.out', () => {
448
+ expect(resultItemsStateAndParams).toEqual(omit(stateAndParamsForAP4.out, META_KEY));
449
+ });
450
+ });
451
+ });
@@ -1,7 +1,7 @@
1
1
  import update, { extend } from 'immutability-helper';
2
2
  import omit from 'lodash/omit';
3
3
  import pick from 'lodash/pick';
4
- import { mergeParamsWithAliases, isItemWithTabs, getCurrentVersion, META_KEY, deleteFromQueue, addToQueue, getInitialItemsStateAndParamsMeta, resolveItemInnerId, getItemsStateAndParamsMeta, } from '../shared';
4
+ import { mergeParamsWithAliases, isItemWithTabs, getCurrentVersion, META_KEY, deleteFromQueue, addToQueue, getInitialItemsStateAndParamsMeta, resolveItemInnerId, getItemsStateAndParamsMeta, pickActionParamsFromParams, transformParamsToActionParams, } from '../shared';
5
5
  import { DEFAULT_NAMESPACE } from '../constants';
6
6
  import { getNewId } from './get-new-id';
7
7
  extend('$auto', (value, object) => (object ? update(object, value) : update({}, value)));
@@ -60,9 +60,14 @@ function removeItemVersion1({ id, config, itemsStateAndParams }) {
60
60
  itemsStateAndParams: newItemsStateAndParams,
61
61
  };
62
62
  }
63
- function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams) {
63
+ function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams, paramsSettings) {
64
64
  var _a;
65
+ const paramsTypeName = (paramsSettings === null || paramsSettings === void 0 ? void 0 : paramsSettings.type) || 'params';
66
+ const isActionParamsMode = paramsTypeName === 'actionParams';
65
67
  let allowedParams = {};
68
+ const stateParamsConf = isActionParamsMode
69
+ ? pickActionParamsFromParams(stateAndParams.params, false)
70
+ : stateAndParams.params;
66
71
  if (isItemWithTabs(item)) {
67
72
  let tab;
68
73
  if ('state' in stateAndParams && ((_a = stateAndParams.state) === null || _a === void 0 ? void 0 : _a.tabId)) {
@@ -72,14 +77,19 @@ function getAllowableChangedParams(item, stateAndParams, itemsStateAndParams) {
72
77
  const tabId = resolveItemInnerId({ item, itemsStateAndParams });
73
78
  tab = item.data.tabs.find(({ id }) => id === tabId);
74
79
  }
75
- allowedParams = pick(stateAndParams.params, Object.keys((tab === null || tab === void 0 ? void 0 : tab.params) || {}));
80
+ allowedParams = pick(stateParamsConf, Object.keys((tab === null || tab === void 0 ? void 0 : tab.params) || {}));
76
81
  }
77
82
  else {
78
- allowedParams = pick(stateAndParams.params, Object.keys(item.defaults || {}));
83
+ allowedParams = pick(stateParamsConf, Object.keys(item.defaults || {}));
79
84
  }
80
- if (Object.keys(allowedParams).length !== Object.keys(stateAndParams.params || {}).length) {
85
+ if (Object.keys(allowedParams || {}).length !== Object.keys(stateParamsConf || {}).length) {
81
86
  console.warn('Параметры, которых нет в defaults, будут проигнорированы!');
82
87
  }
88
+ if (isActionParamsMode) {
89
+ return (paramsSettings === null || paramsSettings === void 0 ? void 0 : paramsSettings.returnPrefix)
90
+ ? transformParamsToActionParams(allowedParams)
91
+ : allowedParams;
92
+ }
83
93
  return allowedParams;
84
94
  }
85
95
  function changeStateAndParamsVersion1({ id: initiatorId, config, stateAndParams, itemsStateAndParams, }) {
@@ -240,6 +250,7 @@ export class UpdateManager {
240
250
  const currentMeta = getItemsStateAndParamsMeta(itemsStateAndParams);
241
251
  if ('params' in stateAndParams) {
242
252
  const allowableParams = getAllowableChangedParams(initiatorItem, stateAndParams, itemsStateAndParams);
253
+ const allowableActionParams = getAllowableChangedParams(initiatorItem, stateAndParams, itemsStateAndParams, { type: 'actionParams', returnPrefix: true });
243
254
  const tabId = isItemWithTabs(initiatorItem)
244
255
  ? newTabId || resolveItemInnerId({ item: initiatorItem, itemsStateAndParams })
245
256
  : undefined;
@@ -250,15 +261,16 @@ export class UpdateManager {
250
261
  if (isTabSwitched) {
251
262
  commandUpdateParams = '$set';
252
263
  }
253
- return update(itemsStateAndParams, {
264
+ const obj = {
254
265
  $unset: unusedIds,
255
266
  [initiatorId]: {
256
267
  $auto: Object.assign({ params: {
257
- [commandUpdateParams]: allowableParams,
268
+ [commandUpdateParams]: Object.assign(Object.assign({}, allowableParams), allowableActionParams),
258
269
  } }, (hasState ? { state: { $set: stateAndParams.state } } : {})),
259
270
  },
260
271
  [META_KEY]: { $set: meta },
261
- });
272
+ };
273
+ return update(itemsStateAndParams, obj);
262
274
  }
263
275
  else if (hasState) {
264
276
  let metaSpec = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dashkit",
3
- "version": "5.1.0",
3
+ "version": "5.3.0",
4
4
  "description": "Library for rendering dashboard grid layout",
5
5
  "license": "MIT",
6
6
  "repository": {