@snack-uikit/table 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +2 -2
  3. package/dist/cjs/components/ServerTable/ServerTable.js +1 -4
  4. package/dist/cjs/components/Table/Table.js +47 -16
  5. package/dist/cjs/components/Table/hooks/useSaveTableSettings/index.d.ts +1 -0
  6. package/dist/cjs/components/Table/hooks/useSaveTableSettings/index.js +25 -0
  7. package/dist/cjs/components/Table/hooks/useSaveTableSettings/types.d.ts +7 -0
  8. package/dist/cjs/components/Table/hooks/useSaveTableSettings/types.js +5 -0
  9. package/dist/cjs/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.d.ts +12 -0
  10. package/dist/cjs/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.js +44 -0
  11. package/dist/cjs/components/Table/hooks/useSaveTableSettings/utils/index.d.ts +2 -0
  12. package/dist/cjs/components/Table/hooks/useSaveTableSettings/utils/index.js +26 -0
  13. package/dist/cjs/components/Table/hooks/useSaveTableSettings/utils/parser.d.ts +3 -0
  14. package/dist/cjs/components/Table/hooks/useSaveTableSettings/utils/parser.js +42 -0
  15. package/dist/cjs/components/Table/hooks/useSaveTableSettings/utils/serializer.d.ts +3 -0
  16. package/dist/cjs/components/Table/hooks/useSaveTableSettings/utils/serializer.js +43 -0
  17. package/dist/cjs/components/Table/hooks/useSaveTableSettings/vallidators.d.ts +5 -0
  18. package/dist/cjs/components/Table/hooks/useSaveTableSettings/vallidators.js +12 -0
  19. package/dist/cjs/components/Table/hooks/useStateControl.d.ts +1 -4
  20. package/dist/cjs/components/Table/hooks/useStateControl.js +7 -9
  21. package/dist/cjs/components/types.d.ts +1 -0
  22. package/dist/cjs/constants.d.ts +3 -0
  23. package/dist/cjs/constants.js +5 -2
  24. package/dist/cjs/utils.d.ts +1 -0
  25. package/dist/cjs/utils.js +14 -2
  26. package/dist/esm/components/ServerTable/ServerTable.js +1 -1
  27. package/dist/esm/components/Table/Table.js +39 -8
  28. package/dist/esm/components/Table/hooks/useSaveTableSettings/index.d.ts +1 -0
  29. package/dist/esm/components/Table/hooks/useSaveTableSettings/index.js +1 -0
  30. package/dist/esm/components/Table/hooks/useSaveTableSettings/types.d.ts +7 -0
  31. package/dist/esm/components/Table/hooks/useSaveTableSettings/types.js +1 -0
  32. package/dist/esm/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.d.ts +12 -0
  33. package/dist/esm/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.js +26 -0
  34. package/dist/esm/components/Table/hooks/useSaveTableSettings/utils/index.d.ts +2 -0
  35. package/dist/esm/components/Table/hooks/useSaveTableSettings/utils/index.js +2 -0
  36. package/dist/esm/components/Table/hooks/useSaveTableSettings/utils/parser.d.ts +3 -0
  37. package/dist/esm/components/Table/hooks/useSaveTableSettings/utils/parser.js +30 -0
  38. package/dist/esm/components/Table/hooks/useSaveTableSettings/utils/serializer.d.ts +3 -0
  39. package/dist/esm/components/Table/hooks/useSaveTableSettings/utils/serializer.js +34 -0
  40. package/dist/esm/components/Table/hooks/useSaveTableSettings/vallidators.d.ts +5 -0
  41. package/dist/esm/components/Table/hooks/useSaveTableSettings/vallidators.js +5 -0
  42. package/dist/esm/components/Table/hooks/useStateControl.d.ts +1 -4
  43. package/dist/esm/components/Table/hooks/useStateControl.js +7 -9
  44. package/dist/esm/components/types.d.ts +1 -0
  45. package/dist/esm/constants.d.ts +3 -0
  46. package/dist/esm/constants.js +3 -0
  47. package/dist/esm/utils.d.ts +1 -0
  48. package/dist/esm/utils.js +10 -0
  49. package/package.json +17 -16
  50. package/src/components/ServerTable/ServerTable.tsx +1 -1
  51. package/src/components/Table/Table.tsx +72 -11
  52. package/src/components/Table/hooks/useSaveTableSettings/index.ts +1 -0
  53. package/src/components/Table/hooks/useSaveTableSettings/types.ts +8 -0
  54. package/src/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.ts +54 -0
  55. package/src/components/Table/hooks/useSaveTableSettings/utils/index.ts +2 -0
  56. package/src/components/Table/hooks/useSaveTableSettings/utils/parser.ts +40 -0
  57. package/src/components/Table/hooks/useSaveTableSettings/utils/serializer.ts +53 -0
  58. package/src/components/Table/hooks/useSaveTableSettings/vallidators.ts +17 -0
  59. package/src/components/Table/hooks/useStateControl.ts +12 -10
  60. package/src/components/types.ts +1 -0
  61. package/src/constants.tsx +3 -0
  62. package/src/utils.ts +14 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 0.33.0 (2025-03-04)
7
+
8
+
9
+ ### Features
10
+
11
+ * **PDS-681:** add save filter ([1406c6c](https://github.com/cloud-ru-tech/snack-uikit/commit/1406c6c447f337b5140135f8741b52ed1a0dfbf0))
12
+
13
+
14
+
15
+
16
+
6
17
  # 0.32.0 (2025-03-03)
7
18
 
8
19
 
package/README.md CHANGED
@@ -144,7 +144,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
144
144
  | scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
145
145
  | scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
146
146
  | rowPinning | `Pick<RowPinningState, "top">` | { top: [], } | Определение какие строки должны быть закреплены в таблице |
147
- | savedState | `{ id: string; resize?: boolean; }` | - | Конфиг для сохранения состояния в localStorage. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
147
+ | savedState | `{ id: string; filterQueryKey?: string; resize?: boolean; }` | - | Конфиг для сохранения состояния в localStorage. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
148
148
  | pagination | `{ state?: PaginationState; options?: number[]; optionsLabel?: string; onChange?(state: PaginationState): void; optionsRender?(value: string \| number, idx: number): string \| number; }` | 'Rows volume: ' <br> <strong>onChange</strong>: Колбэк на изменение пагинации | Параметры отвечают за пагинацию в таблице <br> <strong>state</strong>: Состояние строки поиска, жестко устанавливаемое снаружи <br> <strong>options</strong>: Варианты в выпадающем селекторе для установки кол-ва строк на страницу <br> <strong>optionsLabel</strong>: Текст для селектора кол-ва строк на страницу |
149
149
  | autoResetPageIndex | `boolean` | - | Автоматический сброс пагинации к первой странице при изменении данных или состояния (e.g фильтры, сортировки, и т.д) |
150
150
  | pageCount | `number` | - | Кол-во страниц (используется для внешнего управления) |
@@ -209,7 +209,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
209
209
  | scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
210
210
  | scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
211
211
  | rowPinning | `Pick<RowPinningState, "top">` | - | Определение какие строки должны быть закреплены в таблице |
212
- | savedState | `{ id: string; resize?: boolean; }` | - | Конфиг для сохранения состояния в localStorage. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
212
+ | savedState | `{ id: string; filterQueryKey?: string; resize?: boolean; }` | - | Конфиг для сохранения состояния в localStorage. <br> Поле id должно быть уникальным для разных таблиц в рамках приложения. <br> Для корректной работы необходимо наличие id в конфиге columnDefinitions |
213
213
  | autoResetPageIndex | `boolean` | - | Автоматический сброс пагинации к первой странице при изменении данных или состояния (e.g фильтры, сортировки, и т.д) |
214
214
  | suppressPagination | `boolean` | - | Отключение пагинации |
215
215
  | manualPagination | `boolean` | true | |
@@ -34,10 +34,7 @@ function ServerTable(_a) {
34
34
  manualFiltering = true
35
35
  } = _a,
36
36
  rest = __rest(_a, ["items", "total", "limit", "offset", "onChangePage", "search", "pagination", "columnFilters", "manualSorting", "manualPagination", "manualFiltering"]);
37
- const {
38
- state: search,
39
- onStateChange: setSearch
40
- } = (0, hooks_1.useStateControl)(searchProp, '');
37
+ const [search, setSearch] = (0, hooks_1.useStateControl)(searchProp, '');
41
38
  const [tempSearch, setTempSearch] = (0, react_1.useState)(search || '');
42
39
  (0, react_1.useEffect)(() => {
43
40
  var _a;
@@ -34,6 +34,7 @@ const TreeCell_1 = require("../../helperComponents/Cells/TreeCell");
34
34
  const utils_2 = require("../../utils");
35
35
  const hooks_1 = require("./hooks");
36
36
  const usePageReset_1 = require("./hooks/usePageReset");
37
+ const useSaveTableSettings_1 = require("./hooks/useSaveTableSettings");
37
38
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
38
39
  const utils_3 = require("./utils");
39
40
  /** Компонент таблицы */
@@ -86,25 +87,55 @@ function Table(_a) {
86
87
  } = _a,
87
88
  rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "infiniteLoading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "bulkActions", "rowAutoHeight"]);
88
89
  const {
89
- state: globalFilter,
90
- onStateChange: onGlobalFilterChange
91
- } = (0, hooks_1.useStateControl)(search, '');
92
- const {
93
- state: rowSelection,
94
- onStateChange: onRowSelectionChange
95
- } = (0, hooks_1.useStateControl)(rowSelectionProp, {});
90
+ setDataToStorages,
91
+ defaultFilter
92
+ } = (0, useSaveTableSettings_1.useSaveTableSettings)({
93
+ options: savedState,
94
+ filterSettings: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters
95
+ });
96
+ const [globalFilter, onGlobalFilterChange] = (0, hooks_1.useStateControl)(search, '');
97
+ const [rowSelection, onRowSelectionChange] = (0, hooks_1.useStateControl)(rowSelectionProp, constants_1.DEFAULT_ROW_SELECTION);
96
98
  const defaultPaginationState = (0, react_1.useMemo)(() => ({
97
99
  pageIndex: 0,
98
100
  pageSize
99
101
  }), [pageSize]);
100
- const {
101
- state: sorting,
102
- onStateChange: onSortingChange
103
- } = (0, hooks_1.useStateControl)(sortingProp, []);
104
- const {
105
- state: pagination,
106
- onStateChange: onPaginationChange
107
- } = (0, hooks_1.useStateControl)(paginationProp, defaultPaginationState);
102
+ const [sorting, onSortingChange] = (0, hooks_1.useStateControl)(sortingProp, constants_1.DEFAULT_SORTING);
103
+ const [pagination, onPaginationChange] = (0, hooks_1.useStateControl)(paginationProp, defaultPaginationState);
104
+ const [filter, setFilter] = (0, hooks_1.useStateControl)({
105
+ state: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.value,
106
+ initialState: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.defaultValue,
107
+ onChange: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.onChange
108
+ }, undefined);
109
+ const [filterVisibility, setFilterVisibility] = (0, hooks_1.useStateControl)({
110
+ state: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.visibleFilters,
111
+ initialState: [],
112
+ onChange: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.onVisibleFiltersChange
113
+ }, constants_1.DEFAULT_FILTER_VISIBILITY);
114
+ (0, react_1.useEffect)(() => {
115
+ setDataToStorages({
116
+ pagination,
117
+ sorting,
118
+ filter,
119
+ search: globalFilter || ''
120
+ });
121
+ }, [pagination, sorting, filter, setDataToStorages, globalFilter]);
122
+ (0, utils_1.useLayoutEffect)(() => {
123
+ if (defaultFilter) {
124
+ defaultFilter.pagination && onPaginationChange(defaultFilter.pagination);
125
+ defaultFilter.search && onGlobalFilterChange(defaultFilter.search);
126
+ defaultFilter.sorting && onSortingChange(defaultFilter.sorting);
127
+ defaultFilter.filter && setFilter((0, utils_2.customDateParser)(defaultFilter.filter));
128
+ defaultFilter.filter && setFilterVisibility(Object.keys(defaultFilter.filter));
129
+ }
130
+ // Только для первого рендера, чтобы проинициализировать фильтр
131
+ // eslint-disable-next-line
132
+ }, [defaultFilter]);
133
+ const patchedFilter = (0, react_1.useMemo)(() => columnFilters ? Object.assign(Object.assign({}, columnFilters), {
134
+ value: filter,
135
+ onChange: setFilter,
136
+ visibleFilters: filterVisibility,
137
+ onVisibleFiltersChange: setFilterVisibility
138
+ }) : undefined, [columnFilters, filter, setFilter, filterVisibility, setFilterVisibility]);
108
139
  const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
109
140
  const manualPagination = infiniteLoading || manualPaginationProp;
110
141
  const tableColumns = (0, react_1.useMemo)(() => {
@@ -368,7 +399,7 @@ function Table(_a) {
368
399
  })]
369
400
  }) : undefined,
370
401
  moreActions: moreActions,
371
- filterRow: columnFilters,
402
+ filterRow: patchedFilter,
372
403
  "data-test-id": constants_1.TEST_IDS.toolbar
373
404
  })
374
405
  }), (0, jsx_runtime_1.jsxs)(scroll_1.Scroll, {
@@ -0,0 +1 @@
1
+ export * from './useSaveTableSettings';
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ var __createBinding = void 0 && (void 0).__createBinding || (Object.create ? function (o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = {
8
+ enumerable: true,
9
+ get: function () {
10
+ return m[k];
11
+ }
12
+ };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ } : function (o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ });
19
+ var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
20
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
+ };
22
+ Object.defineProperty(exports, "__esModule", {
23
+ value: true
24
+ });
25
+ __exportStar(require("./useSaveTableSettings"), exports);
@@ -0,0 +1,7 @@
1
+ import { PaginationState, SortingState } from '@tanstack/react-table';
2
+ export type Settings<TFilter> = {
3
+ filter?: TFilter;
4
+ pagination: PaginationState;
5
+ search: string;
6
+ sorting: SortingState;
7
+ };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1,12 @@
1
+ import { ChipChoiceRowProps, FiltersState } from '@snack-uikit/chips';
2
+ import { TableProps } from '../../../types';
3
+ import { Settings } from './types';
4
+ type TableSettings<TFilter extends FiltersState = Record<string, unknown>> = {
5
+ options?: TableProps<TFilter>['savedState'];
6
+ filterSettings?: ChipChoiceRowProps<TFilter>['filters'];
7
+ };
8
+ export declare const useSaveTableSettings: <TFilter extends FiltersState = Record<string, unknown>>({ options, filterSettings, }: TableSettings<TFilter>) => {
9
+ defaultFilter: Settings<TFilter> | null | undefined;
10
+ setDataToStorages: (data: Settings<TFilter>) => void;
11
+ };
12
+ export {};
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useSaveTableSettings = void 0;
7
+ const react_1 = require("react");
8
+ const utils_1 = require("@snack-uikit/utils");
9
+ const utils_2 = require("./utils");
10
+ const vallidators_1 = require("./vallidators");
11
+ const useSaveTableSettings = _ref => {
12
+ let {
13
+ options,
14
+ filterSettings
15
+ } = _ref;
16
+ const validate = (0, react_1.useCallback)(data => {
17
+ const isPaginationValid = (0, vallidators_1.validatePaging)(data === null || data === void 0 ? void 0 : data.pagination);
18
+ const isSortingValid = (0, vallidators_1.validateSorting)(data === null || data === void 0 ? void 0 : data.sorting);
19
+ const isSearchValid = typeof (data === null || data === void 0 ? void 0 : data.search) === 'string';
20
+ const isFilterValid = Boolean(filterSettings && (0, vallidators_1.validateFilter)(data.filter, filterSettings));
21
+ return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
22
+ }, [filterSettings]);
23
+ const filterQueryKey = options === null || options === void 0 ? void 0 : options.filterQueryKey;
24
+ const filterLocalStorageKey = (options === null || options === void 0 ? void 0 : options.id) ? `${options === null || options === void 0 ? void 0 : options.id}_filter` : '';
25
+ const filterStateOptions = (0, react_1.useMemo)(() => filterQueryKey ? {
26
+ filterQueryKey,
27
+ filterLocalStorageKey,
28
+ validateData: validate
29
+ } : undefined, [filterQueryKey, validate, filterLocalStorageKey]);
30
+ const {
31
+ getDefaultFilter,
32
+ setDataToStorages
33
+ } = (0, utils_1.useDataPersist)({
34
+ options: filterStateOptions,
35
+ serializer: utils_2.serializer,
36
+ parser: utils_2.parser
37
+ });
38
+ const defaultFilter = (0, react_1.useMemo)(getDefaultFilter, [getDefaultFilter]);
39
+ return {
40
+ defaultFilter,
41
+ setDataToStorages
42
+ };
43
+ };
44
+ exports.useSaveTableSettings = useSaveTableSettings;
@@ -0,0 +1,2 @@
1
+ export * from './serializer';
2
+ export * from './parser';
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ var __createBinding = void 0 && (void 0).__createBinding || (Object.create ? function (o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = {
8
+ enumerable: true,
9
+ get: function () {
10
+ return m[k];
11
+ }
12
+ };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ } : function (o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ });
19
+ var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
20
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
+ };
22
+ Object.defineProperty(exports, "__esModule", {
23
+ value: true
24
+ });
25
+ __exportStar(require("./serializer"), exports);
26
+ __exportStar(require("./parser"), exports);
@@ -0,0 +1,3 @@
1
+ import { FiltersState } from '@snack-uikit/chips';
2
+ import { Settings } from '../types';
3
+ export declare const parser: <TFilter extends FiltersState = Record<string, unknown>>(value: string) => Settings<TFilter>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.parser = void 0;
7
+ const ft_request_payload_transform_1 = require("@cloud-ru/ft-request-payload-transform");
8
+ const constants_1 = require("../../../../../constants");
9
+ const mapPagination = value => {
10
+ if (!value || !value.offset || !value.limit) return {
11
+ pageSize: constants_1.DEFAULT_PAGE_SIZE,
12
+ pageIndex: 0
13
+ };
14
+ return {
15
+ pageSize: value.limit || constants_1.DEFAULT_PAGE_SIZE,
16
+ pageIndex: Math.floor(value.offset / value.limit)
17
+ };
18
+ };
19
+ const mapSort = function () {
20
+ let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
21
+ return value.map(column => ({
22
+ id: column.field,
23
+ desc: column.direction === 'd'
24
+ }));
25
+ };
26
+ const mapFilter = value => {
27
+ if (!value) {
28
+ return undefined;
29
+ }
30
+ return Object.fromEntries(value.map(filter => [filter.field, filter.value]));
31
+ };
32
+ const parser = value => {
33
+ var _a;
34
+ const parsedValue = (0, ft_request_payload_transform_1.parseQueryParamsString)(value);
35
+ return {
36
+ pagination: mapPagination(parsedValue === null || parsedValue === void 0 ? void 0 : parsedValue.pagination),
37
+ search: ((_a = parsedValue === null || parsedValue === void 0 ? void 0 : parsedValue.search) === null || _a === void 0 ? void 0 : _a.toString()) || '',
38
+ sorting: mapSort(parsedValue === null || parsedValue === void 0 ? void 0 : parsedValue.sort),
39
+ filter: mapFilter(parsedValue === null || parsedValue === void 0 ? void 0 : parsedValue.filter)
40
+ };
41
+ };
42
+ exports.parser = parser;
@@ -0,0 +1,3 @@
1
+ import { FiltersState } from '@snack-uikit/chips';
2
+ import { Settings } from '../types';
3
+ export declare const serializer: <TFilter extends FiltersState = Record<string, unknown>>(value: Settings<TFilter>) => string;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.serializer = void 0;
7
+ const ft_request_payload_transform_1 = require("@cloud-ru/ft-request-payload-transform");
8
+ const mapPagination = value => ({
9
+ limit: value.pageSize,
10
+ offset: value.pageSize * value.pageIndex
11
+ });
12
+ const mapSort = value => value.map(column => ({
13
+ field: column.id,
14
+ direction: column.desc ? 'd' : 'a'
15
+ }));
16
+ const mapDateToString = filter => filter instanceof Date ? filter.toISOString() : filter;
17
+ const mapFilter = value => {
18
+ if (!value) {
19
+ return undefined;
20
+ }
21
+ return Object.entries(value).filter(_ref => {
22
+ let [_, value] = _ref;
23
+ return value !== undefined;
24
+ }).map(_ref2 => {
25
+ let [key, value] = _ref2;
26
+ return Array.isArray(value) ? {
27
+ value: value.map(mapDateToString),
28
+ condition: 'in',
29
+ field: key
30
+ } : {
31
+ value: mapDateToString(value),
32
+ condition: 'eq',
33
+ field: key
34
+ };
35
+ });
36
+ };
37
+ const serializer = value => (0, ft_request_payload_transform_1.createRequestPayload)({
38
+ pagination: mapPagination(value.pagination),
39
+ search: value.search,
40
+ sort: mapSort(value.sorting),
41
+ filter: mapFilter(value.filter)
42
+ }).toString();
43
+ exports.serializer = serializer;
@@ -0,0 +1,5 @@
1
+ import { PaginationState, SortingState } from '@tanstack/react-table';
2
+ import { ChipChoiceRowProps } from '@snack-uikit/chips';
3
+ export declare const validatePaging: (value: unknown) => value is PaginationState;
4
+ export declare const validateSorting: (value: unknown) => value is SortingState;
5
+ export declare const validateFilter: <TFilter extends Record<string, unknown>>(value: unknown, filterSettings: ChipChoiceRowProps<TFilter>["filters"]) => value is TFilter;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.validateFilter = exports.validateSorting = exports.validatePaging = void 0;
7
+ const validatePaging = value => typeof (value === null || value === void 0 ? void 0 : value.pageSize) === 'number' && typeof (value === null || value === void 0 ? void 0 : value.pageIndex) === 'number';
8
+ exports.validatePaging = validatePaging;
9
+ const validateSorting = value => value === null || value === void 0 ? void 0 : value.every(column => typeof (column === null || column === void 0 ? void 0 : column.id) === 'string' && typeof (column === null || column === void 0 ? void 0 : column.desc) === 'boolean');
10
+ exports.validateSorting = validateSorting;
11
+ const validateFilter = (value, filterSettings) => typeof value === 'object' && value !== null && Object.keys(value).every(field => Boolean(filterSettings.find(setting => setting.id === field)));
12
+ exports.validateFilter = validateFilter;
@@ -2,7 +2,4 @@ export declare function useStateControl<TState>(control: {
2
2
  initialState?: TState;
3
3
  state?: TState;
4
4
  onChange?(state: TState): void;
5
- } | undefined, defaultState: TState): {
6
- state: TState;
7
- onStateChange: import("uncontrollable").Handler;
8
- };
5
+ } | undefined, defaultState: TState): readonly [TState, import("uncontrollable").Handler];
@@ -4,16 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.useStateControl = useStateControl;
7
+ const react_1 = require("react");
7
8
  const uncontrollable_1 = require("uncontrollable");
8
9
  function useStateControl(control, defaultState) {
9
10
  var _a, _b;
10
- const [state, onStateChange] = (0, uncontrollable_1.useUncontrolledProp)(control === null || control === void 0 ? void 0 : control.state, (_b = (_a = control === null || control === void 0 ? void 0 : control.state) !== null && _a !== void 0 ? _a : control === null || control === void 0 ? void 0 : control.initialState) !== null && _b !== void 0 ? _b : defaultState, controlState => {
11
- var _a;
12
- const newState = typeof controlState === 'function' ? controlState(state) : controlState;
13
- (_a = control === null || control === void 0 ? void 0 : control.onChange) === null || _a === void 0 ? void 0 : _a.call(control, newState);
14
- });
15
- return {
16
- state,
17
- onStateChange
18
- };
11
+ const state = control === null || control === void 0 ? void 0 : control.state;
12
+ const onChange = control === null || control === void 0 ? void 0 : control.onChange;
13
+ return (0, uncontrollable_1.useUncontrolledProp)(control === null || control === void 0 ? void 0 : control.state, (_b = (_a = control === null || control === void 0 ? void 0 : control.state) !== null && _a !== void 0 ? _a : control === null || control === void 0 ? void 0 : control.initialState) !== null && _b !== void 0 ? _b : defaultState, (0, react_1.useCallback)(controlState => {
14
+ const newState = typeof controlState === 'function' ? controlState(state || defaultState) : controlState;
15
+ onChange === null || onChange === void 0 ? void 0 : onChange(newState);
16
+ }, [state, defaultState, onChange]));
19
17
  }
@@ -119,6 +119,7 @@ type BaseTableProps<TData extends object, TFilters extends FiltersState = Record
119
119
  * */
120
120
  savedState?: {
121
121
  id: string;
122
+ filterQueryKey?: string;
122
123
  resize?: boolean;
123
124
  };
124
125
  }>;
@@ -35,3 +35,6 @@ export declare const SORT_FN: {
35
35
  readonly AlphaNumeric: "alphanumeric";
36
36
  };
37
37
  export declare const DEFAULT_PAGE_SIZE = 10;
38
+ export declare const DEFAULT_SORTING: never[];
39
+ export declare const DEFAULT_FILTER_VISIBILITY: never[];
40
+ export declare const DEFAULT_ROW_SELECTION: {};
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.DEFAULT_PAGE_SIZE = exports.SORT_FN = exports.TEST_IDS = exports.COLUMN_ALIGN = exports.COLUMN_PIN_POSITION = void 0;
6
+ exports.DEFAULT_ROW_SELECTION = exports.DEFAULT_FILTER_VISIBILITY = exports.DEFAULT_SORTING = exports.DEFAULT_PAGE_SIZE = exports.SORT_FN = exports.TEST_IDS = exports.COLUMN_ALIGN = exports.COLUMN_PIN_POSITION = void 0;
7
7
  exports.COLUMN_PIN_POSITION = {
8
8
  Left: 'left',
9
9
  Right: 'right'
@@ -40,4 +40,7 @@ exports.SORT_FN = {
40
40
  DateTime: 'datetime',
41
41
  AlphaNumeric: 'alphanumeric'
42
42
  };
43
- exports.DEFAULT_PAGE_SIZE = 10;
43
+ exports.DEFAULT_PAGE_SIZE = 10;
44
+ exports.DEFAULT_SORTING = [];
45
+ exports.DEFAULT_FILTER_VISIBILITY = [];
46
+ exports.DEFAULT_ROW_SELECTION = {};
@@ -1,3 +1,4 @@
1
1
  import { FilterFn } from '@tanstack/react-table';
2
2
  export declare const fuzzyFilter: FilterFn<any>;
3
3
  export declare const preciseFilter: FilterFn<any>;
4
+ export declare const customDateParser: <T>(value: Record<string, unknown>) => T;
package/dist/cjs/utils.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.preciseFilter = exports.fuzzyFilter = void 0;
6
+ exports.customDateParser = exports.preciseFilter = exports.fuzzyFilter = void 0;
7
7
  const match_sorter_utils_1 = require("@tanstack/match-sorter-utils");
8
8
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
9
  const fuzzyFilter = (row, columnId, value, addMeta) => {
@@ -22,4 +22,16 @@ const preciseFilter = (row, columnId, value, addMeta) => {
22
22
  });
23
23
  return itemRank.passed;
24
24
  };
25
- exports.preciseFilter = preciseFilter;
25
+ exports.preciseFilter = preciseFilter;
26
+ const isDateString = value => typeof value === 'string' && !isNaN(Number(new Date(value)));
27
+ const customDateParser = value => Object.fromEntries(Object.entries(value).map(_ref => {
28
+ let [key, value] = _ref;
29
+ if (isDateString(value)) {
30
+ return [key, new Date(value)];
31
+ }
32
+ if (Array.isArray(value) && value.some(isDateString)) {
33
+ return [key, value.map(element => isDateString(element) ? new Date(element) : element)];
34
+ }
35
+ return [key, value];
36
+ }));
37
+ exports.customDateParser = customDateParser;
@@ -18,7 +18,7 @@ import { DEFAULT_PAGINATION_LIMIT } from './constants';
18
18
  import { onSearchDebounced } from './utils';
19
19
  export function ServerTable(_a) {
20
20
  var { items, total = DEFAULT_PAGINATION_LIMIT, limit = DEFAULT_PAGINATION_LIMIT, offset = 0, onChangePage, search: searchProp, pagination, columnFilters, manualSorting = true, manualPagination = true, manualFiltering = true } = _a, rest = __rest(_a, ["items", "total", "limit", "offset", "onChangePage", "search", "pagination", "columnFilters", "manualSorting", "manualPagination", "manualFiltering"]);
21
- const { state: search, onStateChange: setSearch } = useStateControl(searchProp, '');
21
+ const [search, setSearch] = useStateControl(searchProp, '');
22
22
  const [tempSearch, setTempSearch] = useState(search || '');
23
23
  useEffect(() => {
24
24
  var _a;
@@ -18,14 +18,15 @@ import { Scroll } from '@snack-uikit/scroll';
18
18
  import { SkeletonContextProvider } from '@snack-uikit/skeleton';
19
19
  import { Toolbar } from '@snack-uikit/toolbar';
20
20
  import { TruncateString } from '@snack-uikit/truncate-string';
21
- import { extractSupportProps } from '@snack-uikit/utils';
22
- import { DEFAULT_PAGE_SIZE, TEST_IDS } from '../../constants';
21
+ import { extractSupportProps, useLayoutEffect } from '@snack-uikit/utils';
22
+ import { DEFAULT_FILTER_VISIBILITY, DEFAULT_PAGE_SIZE, DEFAULT_ROW_SELECTION, DEFAULT_SORTING, TEST_IDS, } from '../../constants';
23
23
  import { CellAutoResizeContext, useCellAutoResizeController } from '../../contexts';
24
24
  import { BodyRow, ExportButton, getColumnId, getRowActionsColumnDef, getSelectionCellColumnDef, getStatusColumnDef, HeaderRow, STATUS_APPEARANCE, TableContext, TableEmptyState, TablePagination, useEmptyState, } from '../../helperComponents';
25
25
  import { getTreeColumnDef } from '../../helperComponents/Cells/TreeCell';
26
- import { fuzzyFilter } from '../../utils';
26
+ import { customDateParser, fuzzyFilter } from '../../utils';
27
27
  import { useLoadingTable, useStateControl } from './hooks';
28
28
  import { usePageReset } from './hooks/usePageReset';
29
+ import { useSaveTableSettings } from './hooks/useSaveTableSettings';
29
30
  import styles from './styles.module.css';
30
31
  import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth, getInitColumnSizeFromLocalStorage, saveStateToLocalStorage, } from './utils';
31
32
  /** Компонент таблицы */
@@ -33,14 +34,44 @@ export function Table(_a) {
33
34
  var { data, rowPinning = {
34
35
  top: [],
35
36
  }, columnDefinitions, keepPinnedRows = false, copyPinnedRows = false, enableSelectPinned = false, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize = DEFAULT_PAGE_SIZE, pageCount, loading = false, infiniteLoading = false, outline = false, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, suppressSearch = false, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination: manualPaginationProp = false, manualFiltering = false, autoResetPageIndex = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp, rowAutoHeight } = _a, rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "infiniteLoading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "bulkActions", "rowAutoHeight"]);
36
- const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
37
- const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
37
+ const { setDataToStorages, defaultFilter } = useSaveTableSettings({
38
+ options: savedState,
39
+ filterSettings: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.filters,
40
+ });
41
+ const [globalFilter, onGlobalFilterChange] = useStateControl(search, '');
42
+ const [rowSelection, onRowSelectionChange] = useStateControl(rowSelectionProp, DEFAULT_ROW_SELECTION);
38
43
  const defaultPaginationState = useMemo(() => ({
39
44
  pageIndex: 0,
40
45
  pageSize,
41
46
  }), [pageSize]);
42
- const { state: sorting, onStateChange: onSortingChange } = useStateControl(sortingProp, []);
43
- const { state: pagination, onStateChange: onPaginationChange } = useStateControl(paginationProp, defaultPaginationState);
47
+ const [sorting, onSortingChange] = useStateControl(sortingProp, DEFAULT_SORTING);
48
+ const [pagination, onPaginationChange] = useStateControl(paginationProp, defaultPaginationState);
49
+ const [filter, setFilter] = useStateControl({
50
+ state: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.value,
51
+ initialState: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.defaultValue,
52
+ onChange: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.onChange,
53
+ }, undefined);
54
+ const [filterVisibility, setFilterVisibility] = useStateControl({
55
+ state: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.visibleFilters,
56
+ initialState: [],
57
+ onChange: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters.onVisibleFiltersChange,
58
+ }, DEFAULT_FILTER_VISIBILITY);
59
+ useEffect(() => {
60
+ setDataToStorages({ pagination, sorting, filter, search: globalFilter || '' });
61
+ }, [pagination, sorting, filter, setDataToStorages, globalFilter]);
62
+ useLayoutEffect(() => {
63
+ if (defaultFilter) {
64
+ defaultFilter.pagination && onPaginationChange(defaultFilter.pagination);
65
+ defaultFilter.search && onGlobalFilterChange(defaultFilter.search);
66
+ defaultFilter.sorting && onSortingChange(defaultFilter.sorting);
67
+ defaultFilter.filter && setFilter(customDateParser(defaultFilter.filter));
68
+ defaultFilter.filter && setFilterVisibility(Object.keys(defaultFilter.filter));
69
+ }
70
+ // Только для первого рендера, чтобы проинициализировать фильтр
71
+ // eslint-disable-next-line
72
+ }, [defaultFilter]);
73
+ const patchedFilter = useMemo(() => columnFilters
74
+ ? Object.assign(Object.assign({}, columnFilters), { value: filter, onChange: setFilter, visibleFilters: filterVisibility, onVisibleFiltersChange: setFilterVisibility }) : undefined, [columnFilters, filter, setFilter, filterVisibility, setFilterVisibility]);
44
75
  const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
45
76
  const manualPagination = infiniteLoading || manualPaginationProp;
46
77
  const tableColumns = useMemo(() => {
@@ -248,7 +279,7 @@ export function Table(_a) {
248
279
  onChange: onGlobalFilterChange,
249
280
  loading: search === null || search === void 0 ? void 0 : search.loading,
250
281
  placeholder: (search === null || search === void 0 ? void 0 : search.placeholder) || t('searchPlaceholder'),
251
- }, className: styles.toolbar, onRefresh: onRefresh ? handleOnRefresh : undefined, bulkActions: bulkActions, selectionMode: (rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow) ? 'multiple' : 'single', checked: table.getIsAllPageRowsSelected(), indeterminate: table.getIsSomePageRowsSelected(), onCheck: enableSelection ? handleOnToolbarCheck : undefined, outline: outline, after: toolbarAfter || exportSettings ? (_jsxs(_Fragment, { children: [toolbarAfter, exportSettings && (_jsx(ExportButton, { settings: exportSettings, columnDefinitions: columnDefinitions, data: data, topRows: filteredTopRows, centerRows: centerRows }))] })) : undefined, moreActions: moreActions, filterRow: columnFilters, "data-test-id": TEST_IDS.toolbar }) })), _jsxs(Scroll, { size: 's', className: styles.table, ref: scrollContainerRef, "data-outline": outline || undefined, children: [_jsx("div", { className: styles.tableContent, style: columnSizes.vars, children: _jsx(CellAutoResizeContext.Provider, { value: { updateCellMap }, children: _jsx(TableContext.Provider, { value: { table }, children: (!infiniteLoading || !data.length) && loading ? (_jsxs(SkeletonContextProvider, { loading: true, children: [_jsx(HeaderRow, { rowAutoHeight: rowAutoHeight }), loadingTableRows.map(row => (_jsx(BodyRow, { row: row, rowAutoHeight: rowAutoHeight }, row.id)))] })) : (_jsxs(_Fragment, { children: [centerRows.length || filteredTopRows.length ? _jsx(HeaderRow, {}) : null, filteredTopRows.length ? (_jsx("div", { className: styles.topRowWrapper, children: filteredTopRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick, rowAutoHeight: rowAutoHeight }, row.id))) })) : null, centerRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick, rowAutoHeight: rowAutoHeight }, row.id))), data.length > 0 && infiniteLoading && loading && !dataError && (_jsx(SkeletonContextProvider, { loading: true, children: loadingTableRows.slice(0, 3).map(row => (_jsx(BodyRow, { row: row }, row.id))) })), _jsx(TableEmptyState, { emptyStates: emptyStates, dataError: dataError, dataFiltered: dataFiltered || Boolean(table.getState().globalFilter), tableRowsLength: tableRows.length + filteredTopRows.length })] })) }) }) }), _jsx("div", { className: styles.scrollStub, ref: scrollRef })] }), !infiniteLoading && !suppressPagination && (_jsx(TablePagination, { table: table, options: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.options, optionsLabel: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsLabel, pageCount: pageCount, optionsRender: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsRender }))] })));
282
+ }, className: styles.toolbar, onRefresh: onRefresh ? handleOnRefresh : undefined, bulkActions: bulkActions, selectionMode: (rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.multiRow) ? 'multiple' : 'single', checked: table.getIsAllPageRowsSelected(), indeterminate: table.getIsSomePageRowsSelected(), onCheck: enableSelection ? handleOnToolbarCheck : undefined, outline: outline, after: toolbarAfter || exportSettings ? (_jsxs(_Fragment, { children: [toolbarAfter, exportSettings && (_jsx(ExportButton, { settings: exportSettings, columnDefinitions: columnDefinitions, data: data, topRows: filteredTopRows, centerRows: centerRows }))] })) : undefined, moreActions: moreActions, filterRow: patchedFilter, "data-test-id": TEST_IDS.toolbar }) })), _jsxs(Scroll, { size: 's', className: styles.table, ref: scrollContainerRef, "data-outline": outline || undefined, children: [_jsx("div", { className: styles.tableContent, style: columnSizes.vars, children: _jsx(CellAutoResizeContext.Provider, { value: { updateCellMap }, children: _jsx(TableContext.Provider, { value: { table }, children: (!infiniteLoading || !data.length) && loading ? (_jsxs(SkeletonContextProvider, { loading: true, children: [_jsx(HeaderRow, { rowAutoHeight: rowAutoHeight }), loadingTableRows.map(row => (_jsx(BodyRow, { row: row, rowAutoHeight: rowAutoHeight }, row.id)))] })) : (_jsxs(_Fragment, { children: [centerRows.length || filteredTopRows.length ? _jsx(HeaderRow, {}) : null, filteredTopRows.length ? (_jsx("div", { className: styles.topRowWrapper, children: filteredTopRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick, rowAutoHeight: rowAutoHeight }, row.id))) })) : null, centerRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick, rowAutoHeight: rowAutoHeight }, row.id))), data.length > 0 && infiniteLoading && loading && !dataError && (_jsx(SkeletonContextProvider, { loading: true, children: loadingTableRows.slice(0, 3).map(row => (_jsx(BodyRow, { row: row }, row.id))) })), _jsx(TableEmptyState, { emptyStates: emptyStates, dataError: dataError, dataFiltered: dataFiltered || Boolean(table.getState().globalFilter), tableRowsLength: tableRows.length + filteredTopRows.length })] })) }) }) }), _jsx("div", { className: styles.scrollStub, ref: scrollRef })] }), !infiniteLoading && !suppressPagination && (_jsx(TablePagination, { table: table, options: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.options, optionsLabel: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsLabel, pageCount: pageCount, optionsRender: paginationProp === null || paginationProp === void 0 ? void 0 : paginationProp.optionsRender }))] })));
252
283
  }
253
284
  Table.getStatusColumnDef = getStatusColumnDef;
254
285
  Table.statusAppearances = STATUS_APPEARANCE;
@@ -0,0 +1 @@
1
+ export * from './useSaveTableSettings';
@@ -0,0 +1 @@
1
+ export * from './useSaveTableSettings';
@@ -0,0 +1,7 @@
1
+ import { PaginationState, SortingState } from '@tanstack/react-table';
2
+ export type Settings<TFilter> = {
3
+ filter?: TFilter;
4
+ pagination: PaginationState;
5
+ search: string;
6
+ sorting: SortingState;
7
+ };