@snack-uikit/table 0.28.4 → 0.28.6-preview-e840ab81.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 +11 -0
- package/README.md +2 -0
- package/dist/cjs/components/ServerTable/ServerTable.d.ts +1 -1
- package/dist/cjs/components/Table/Table.d.ts +1 -1
- package/dist/cjs/components/Table/Table.js +24 -3
- package/dist/cjs/components/Table/hooks/useSaveTableSettings/index.d.ts +1 -0
- package/dist/cjs/components/Table/hooks/useSaveTableSettings/index.js +25 -0
- package/dist/cjs/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.d.ts +21 -0
- package/dist/cjs/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.js +81 -0
- package/dist/cjs/components/Table/hooks/useSaveTableSettings/vallidators.d.ts +3 -0
- package/dist/cjs/components/Table/hooks/useSaveTableSettings/vallidators.js +10 -0
- package/dist/cjs/components/types.d.ts +5 -3
- package/dist/cjs/helperComponents/TablePagination/TablePagination.js +2 -0
- package/dist/cjs/utils.d.ts +1 -0
- package/dist/cjs/utils.js +14 -2
- package/dist/esm/components/ServerTable/ServerTable.d.ts +1 -1
- package/dist/esm/components/Table/Table.d.ts +1 -1
- package/dist/esm/components/Table/Table.js +11 -3
- package/dist/esm/components/Table/hooks/useSaveTableSettings/index.d.ts +1 -0
- package/dist/esm/components/Table/hooks/useSaveTableSettings/index.js +1 -0
- package/dist/esm/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.d.ts +21 -0
- package/dist/esm/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.js +53 -0
- package/dist/esm/components/Table/hooks/useSaveTableSettings/vallidators.d.ts +3 -0
- package/dist/esm/components/Table/hooks/useSaveTableSettings/vallidators.js +2 -0
- package/dist/esm/components/types.d.ts +5 -3
- package/dist/esm/helperComponents/TablePagination/TablePagination.js +2 -1
- package/dist/esm/utils.d.ts +1 -0
- package/dist/esm/utils.js +10 -0
- package/package.json +16 -16
- package/src/components/ServerTable/ServerTable.tsx +1 -1
- package/src/components/Table/Table.tsx +13 -3
- package/src/components/Table/hooks/useSaveTableSettings/index.ts +1 -0
- package/src/components/Table/hooks/useSaveTableSettings/useSaveTableSettings.ts +108 -0
- package/src/components/Table/hooks/useSaveTableSettings/vallidators.ts +7 -0
- package/src/components/types.ts +9 -3
- package/src/helperComponents/TablePagination/TablePagination.tsx +2 -0
- 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.28.5 (2025-02-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **PDS-1081:** make type for filters in generic non required ([136ea97](https://github.com/cloud-ru-tech/snack-uikit/commit/136ea971801290030eb6ad68bfcb8c06b2b3e732))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## 0.28.4 (2025-02-10)
|
|
7
18
|
|
|
8
19
|
### Only dependencies have been changed
|
package/README.md
CHANGED
|
@@ -109,6 +109,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
|
|
|
109
109
|
### Props
|
|
110
110
|
| name | type | default value | description |
|
|
111
111
|
|------|------|---------------|-------------|
|
|
112
|
+
| saveStateSettings* | `FilterStateOptions<TFilters>` | - | Настройки для сохранения состояний таблицы в query params и local storage |
|
|
112
113
|
| columnDefinitions* | `ColumnDefinition<TData>[]` | - | Определение внешнего вида и функционала колонок |
|
|
113
114
|
| data* | `TData[]` | - | Данные для отрисовки |
|
|
114
115
|
| keepPinnedRows | `boolean` | - | Параметр отвечает за отображение закрепленных строк на всех страницах таблицы |
|
|
@@ -175,6 +176,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
|
|
|
175
176
|
| name | type | default value | description |
|
|
176
177
|
|------|------|---------------|-------------|
|
|
177
178
|
| onChangePage* | `(offset: number, limit: number) => void` | - | |
|
|
179
|
+
| saveStateSettings* | `FilterStateOptions<TFilters>` | - | Настройки для сохранения состояний таблицы в query params и local storage |
|
|
178
180
|
| columnDefinitions* | `ColumnDefinition<TData>[]` | - | Определение внешнего вида и функционала колонок |
|
|
179
181
|
| keepPinnedRows | `boolean` | false | Параметр отвечает за отображение закрепленных строк на всех страницах таблицы |
|
|
180
182
|
| copyPinnedRows | `boolean` | false | Параметр отвечает за сохранение закрепленных строк в теле таблицы |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FiltersState } from '@snack-uikit/chips';
|
|
2
2
|
import { ServerTableProps } from '../types';
|
|
3
|
-
export declare function ServerTable<TData extends object, TFilters extends FiltersState
|
|
3
|
+
export declare function ServerTable<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ items, total, limit, offset, onChangePage, search: searchProp, pagination, columnFilters, manualSorting, manualPagination, manualFiltering, ...rest }: ServerTableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
export declare namespace ServerTable {
|
|
5
5
|
var getRowActionsColumnDef: typeof import("../../helperComponents").getRowActionsColumnDef;
|
|
6
6
|
var statusAppearances: Record<string, string>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FiltersState } from '@snack-uikit/chips';
|
|
2
2
|
import { TableProps } from '../types';
|
|
3
3
|
/** Компонент таблицы */
|
|
4
|
-
export declare function Table<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, rowPinning, columnDefinitions, keepPinnedRows, copyPinnedRows, enableSelectPinned, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize, pageCount, loading, outline, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, suppressSearch, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp, ...rest }: TableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare function Table<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, rowPinning, columnDefinitions, keepPinnedRows, copyPinnedRows, enableSelectPinned, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize, pageCount, loading, outline, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, suppressSearch, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, saveStateSettings, bulkActions: bulkActionsProp, ...rest }: TableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
export declare namespace Table {
|
|
6
6
|
var getStatusColumnDef: typeof import("../../helperComponents").getStatusColumnDef;
|
|
7
7
|
var statusAppearances: Record<string, string>;
|
|
@@ -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/useSaveTableSettings");
|
|
37
38
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
38
39
|
const utils_3 = require("./utils");
|
|
39
40
|
/** Компонент таблицы */
|
|
@@ -80,9 +81,10 @@ function Table(_a) {
|
|
|
80
81
|
enableFuzzySearch,
|
|
81
82
|
savedState,
|
|
82
83
|
expanding,
|
|
84
|
+
saveStateSettings,
|
|
83
85
|
bulkActions: bulkActionsProp
|
|
84
86
|
} = _a,
|
|
85
|
-
rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "bulkActions"]);
|
|
87
|
+
rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "saveStateSettings", "bulkActions"]);
|
|
86
88
|
const {
|
|
87
89
|
state: globalFilter,
|
|
88
90
|
onStateChange: onGlobalFilterChange
|
|
@@ -103,6 +105,25 @@ function Table(_a) {
|
|
|
103
105
|
state: pagination,
|
|
104
106
|
onStateChange: onPaginationChange
|
|
105
107
|
} = (0, hooks_1.useStateControl)(paginationProp, defaultPaginationState);
|
|
108
|
+
const {
|
|
109
|
+
patchedFilter,
|
|
110
|
+
isSettingsLoaded
|
|
111
|
+
} = (0, useSaveTableSettings_1.useSaveTableSettings)({
|
|
112
|
+
pagination: {
|
|
113
|
+
state: pagination,
|
|
114
|
+
handler: onPaginationChange
|
|
115
|
+
},
|
|
116
|
+
search: {
|
|
117
|
+
state: globalFilter,
|
|
118
|
+
handler: onGlobalFilterChange
|
|
119
|
+
},
|
|
120
|
+
sorting: {
|
|
121
|
+
state: sorting,
|
|
122
|
+
handler: onSortingChange
|
|
123
|
+
},
|
|
124
|
+
filters: columnFilters,
|
|
125
|
+
options: saveStateSettings
|
|
126
|
+
});
|
|
106
127
|
const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
|
|
107
128
|
const tableColumns = (0, react_1.useMemo)(() => {
|
|
108
129
|
let cols = columnDefinitions;
|
|
@@ -334,7 +355,7 @@ function Table(_a) {
|
|
|
334
355
|
},
|
|
335
356
|
className: (0, classnames_1.default)(styles_module_scss_1.default.wrapper, className)
|
|
336
357
|
}, (0, utils_1.extractSupportProps)(rest), {
|
|
337
|
-
children: [showToolbar && (0, jsx_runtime_1.jsx)("div", {
|
|
358
|
+
children: [showToolbar && isSettingsLoaded && (0, jsx_runtime_1.jsx)("div", {
|
|
338
359
|
className: styles_module_scss_1.default.header,
|
|
339
360
|
children: (0, jsx_runtime_1.jsx)(toolbar_1.Toolbar, {
|
|
340
361
|
search: suppressSearch ? undefined : {
|
|
@@ -361,7 +382,7 @@ function Table(_a) {
|
|
|
361
382
|
})]
|
|
362
383
|
}) : undefined,
|
|
363
384
|
moreActions: moreActions,
|
|
364
|
-
filterRow:
|
|
385
|
+
filterRow: patchedFilter,
|
|
365
386
|
"data-test-id": constants_1.TEST_IDS.toolbar
|
|
366
387
|
})
|
|
367
388
|
}), (0, jsx_runtime_1.jsx)("div", {
|
|
@@ -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,21 @@
|
|
|
1
|
+
import { PaginationState, SortingState } from '@tanstack/react-table';
|
|
2
|
+
import { Handler } from 'uncontrollable';
|
|
3
|
+
import { ChipChoiceRowProps, FiltersState } from '@snack-uikit/chips';
|
|
4
|
+
import { FilterRow } from '@snack-uikit/toolbar/src/components/Toolbar/types';
|
|
5
|
+
import { FilterStateOptions } from '@snack-uikit/utils';
|
|
6
|
+
type State<T> = {
|
|
7
|
+
state: T;
|
|
8
|
+
handler: Handler;
|
|
9
|
+
};
|
|
10
|
+
type TableSettings<TFilter extends FiltersState = Record<string, unknown>> = {
|
|
11
|
+
options?: FilterStateOptions<TFilter>;
|
|
12
|
+
filters?: ChipChoiceRowProps<TFilter>;
|
|
13
|
+
pagination: State<PaginationState>;
|
|
14
|
+
search: State<string>;
|
|
15
|
+
sorting: State<SortingState>;
|
|
16
|
+
};
|
|
17
|
+
export declare const useSaveTableSettings: <TFilter extends FiltersState = Record<string, unknown>>({ options, filters, pagination: { state: paginationState, handler: paginationHandler }, search: { state: searchState, handler: searchHandler }, sorting: { state: sortingState, handler: sortingHandler }, }: TableSettings<TFilter>) => {
|
|
18
|
+
patchedFilter: FilterRow<TFilter> | undefined;
|
|
19
|
+
isSettingsLoaded: boolean;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
filters,
|
|
15
|
+
pagination: {
|
|
16
|
+
state: paginationState,
|
|
17
|
+
handler: paginationHandler
|
|
18
|
+
},
|
|
19
|
+
search: {
|
|
20
|
+
state: searchState,
|
|
21
|
+
handler: searchHandler
|
|
22
|
+
},
|
|
23
|
+
sorting: {
|
|
24
|
+
state: sortingState,
|
|
25
|
+
handler: sortingHandler
|
|
26
|
+
}
|
|
27
|
+
} = _ref;
|
|
28
|
+
const [filter, setFilter] = (0, react_1.useState)(filters === null || filters === void 0 ? void 0 : filters.value);
|
|
29
|
+
const [isSettingsLoaded, setIsSettingsLoaded] = (0, react_1.useState)(false);
|
|
30
|
+
(0, react_1.useEffect)(() => {
|
|
31
|
+
setFilter(filters === null || filters === void 0 ? void 0 : filters.value);
|
|
32
|
+
}, [filters === null || filters === void 0 ? void 0 : filters.value]);
|
|
33
|
+
const settings = (0, react_1.useMemo)(() => ({
|
|
34
|
+
pagination: paginationState,
|
|
35
|
+
filter,
|
|
36
|
+
search: searchState,
|
|
37
|
+
sorting: sortingState
|
|
38
|
+
}), [paginationState, filter, searchState, sortingState]);
|
|
39
|
+
const onFilterChange = (0, react_1.useCallback)(value => {
|
|
40
|
+
(filters === null || filters === void 0 ? void 0 : filters.onChange) && filters.onChange(value);
|
|
41
|
+
setFilter(value);
|
|
42
|
+
},
|
|
43
|
+
// eslint-disable-next-line
|
|
44
|
+
[filters === null || filters === void 0 ? void 0 : filters.onChange]);
|
|
45
|
+
const validate = (0, react_1.useCallback)(data => {
|
|
46
|
+
const isPaginationValid = (0, vallidators_1.validatePaging)(data === null || data === void 0 ? void 0 : data.pagination);
|
|
47
|
+
const isSortingValid = (0, vallidators_1.validateSorting)(data === null || data === void 0 ? void 0 : data.sorting);
|
|
48
|
+
const isSearchValid = typeof (data === null || data === void 0 ? void 0 : data.search) === 'string';
|
|
49
|
+
const isFilterValid = Boolean(options === null || options === void 0 ? void 0 : options.validateData(data === null || data === void 0 ? void 0 : data.filter));
|
|
50
|
+
return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
|
|
51
|
+
}, [options]);
|
|
52
|
+
const onInitPage = (0, react_1.useCallback)(data => {
|
|
53
|
+
if (!data) {
|
|
54
|
+
setIsSettingsLoaded(true);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
data.pagination && paginationHandler(data.pagination);
|
|
58
|
+
data.search && searchHandler(data.search);
|
|
59
|
+
data.sorting && sortingHandler(data.sorting);
|
|
60
|
+
data.filter && onFilterChange((0, utils_2.customDateParser)(data.filter));
|
|
61
|
+
setIsSettingsLoaded(true);
|
|
62
|
+
// eslint-disable-next-line
|
|
63
|
+
}, []);
|
|
64
|
+
const filterStateOptions = (0, react_1.useMemo)(() => options ? Object.assign(Object.assign({}, options), {
|
|
65
|
+
validateData: validate
|
|
66
|
+
}) : undefined, [options, validate]);
|
|
67
|
+
(0, utils_1.useSaveFilterState)({
|
|
68
|
+
filter: settings,
|
|
69
|
+
options: filterStateOptions,
|
|
70
|
+
onLoadFilter: onInitPage
|
|
71
|
+
});
|
|
72
|
+
const patchedFilter = (0, react_1.useMemo)(() => filters ? Object.assign(Object.assign({}, filters), {
|
|
73
|
+
value: filter,
|
|
74
|
+
onChange: onFilterChange
|
|
75
|
+
}) : undefined, [filters, onFilterChange, filter]);
|
|
76
|
+
return {
|
|
77
|
+
patchedFilter,
|
|
78
|
+
isSettingsLoaded
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
exports.useSaveTableSettings = useSaveTableSettings;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
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;
|
|
@@ -2,14 +2,14 @@ import { PaginationState, Row, RowPinningState, RowSelectionOptions, RowSelectio
|
|
|
2
2
|
import { ReactNode, RefObject } from 'react';
|
|
3
3
|
import { ChipChoiceRowProps, FiltersState } from '@snack-uikit/chips';
|
|
4
4
|
import { ToolbarProps } from '@snack-uikit/toolbar';
|
|
5
|
-
import { WithSupportProps } from '@snack-uikit/utils';
|
|
5
|
+
import { FilterStateOptions, WithSupportProps } from '@snack-uikit/utils';
|
|
6
6
|
import { EmptyStateProps, ExportButtonProps, RowClickHandler } from '../helperComponents';
|
|
7
7
|
import { TreeColumnDefinitionProps } from '../helperComponents/Cells/TreeCell';
|
|
8
8
|
import { ColumnDefinition } from '../types';
|
|
9
9
|
type BulkAction = Omit<NonNullable<ToolbarProps<Record<string, string>>['bulkActions']>[number], 'onClick'> & {
|
|
10
10
|
onClick?(selectionState: RowSelectionState, resetRowSelection: (defaultState?: boolean) => void): void;
|
|
11
11
|
};
|
|
12
|
-
export type TableProps<TData extends object, TFilters extends FiltersState
|
|
12
|
+
export type TableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = WithSupportProps<{
|
|
13
13
|
/** Данные для отрисовки */
|
|
14
14
|
data: TData[];
|
|
15
15
|
/** Определение внешнего вида и функционала колонок */
|
|
@@ -64,6 +64,8 @@ export type TableProps<TData extends object, TFilters extends FiltersState> = Wi
|
|
|
64
64
|
loading?: boolean;
|
|
65
65
|
onChange?(value: string): void;
|
|
66
66
|
};
|
|
67
|
+
/** Настройки для сохранения состояний таблицы в query params и local storage*/
|
|
68
|
+
saveStateSettings: FilterStateOptions<TFilters>;
|
|
67
69
|
/** Включить нечеткий поиск */
|
|
68
70
|
enableFuzzySearch?: boolean;
|
|
69
71
|
/** Максимальное кол-во строк на страницу @default 10 */
|
|
@@ -143,7 +145,7 @@ export type TableProps<TData extends object, TFilters extends FiltersState> = Wi
|
|
|
143
145
|
resize?: boolean;
|
|
144
146
|
};
|
|
145
147
|
}>;
|
|
146
|
-
export type ServerTableProps<TData extends object, TFilters extends FiltersState
|
|
148
|
+
export type ServerTableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Omit<TableProps<TData, TFilters>, 'pageSize' | 'pageCount' | 'pagination' | 'search' | 'data'> & {
|
|
147
149
|
/** Данные для отрисовки */
|
|
148
150
|
items?: TData[];
|
|
149
151
|
/**
|
|
@@ -14,6 +14,7 @@ const react_1 = require("react");
|
|
|
14
14
|
const chips_1 = require("@snack-uikit/chips");
|
|
15
15
|
const locale_1 = require("@snack-uikit/locale");
|
|
16
16
|
const pagination_1 = require("@snack-uikit/pagination");
|
|
17
|
+
const utils_1 = require("@snack-uikit/utils");
|
|
17
18
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
18
19
|
function TablePagination(_ref) {
|
|
19
20
|
let {
|
|
@@ -52,6 +53,7 @@ function TablePagination(_ref) {
|
|
|
52
53
|
value: String(tablePaginationState.pageSize),
|
|
53
54
|
onChange: handleRowsVolumeOnChange,
|
|
54
55
|
placement: 'top-end',
|
|
56
|
+
onClick: () => (0, utils_1.isBrowser)() && window.location.reload(),
|
|
55
57
|
options: options,
|
|
56
58
|
label: optionsLabel,
|
|
57
59
|
widthStrategy: 'auto',
|
package/dist/cjs/utils.d.ts
CHANGED
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;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FiltersState } from '@snack-uikit/chips';
|
|
2
2
|
import { ServerTableProps } from '../types';
|
|
3
|
-
export declare function ServerTable<TData extends object, TFilters extends FiltersState
|
|
3
|
+
export declare function ServerTable<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ items, total, limit, offset, onChangePage, search: searchProp, pagination, columnFilters, manualSorting, manualPagination, manualFiltering, ...rest }: ServerTableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
export declare namespace ServerTable {
|
|
5
5
|
var getRowActionsColumnDef: typeof import("../../helperComponents").getRowActionsColumnDef;
|
|
6
6
|
var statusAppearances: Record<string, string>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FiltersState } from '@snack-uikit/chips';
|
|
2
2
|
import { TableProps } from '../types';
|
|
3
3
|
/** Компонент таблицы */
|
|
4
|
-
export declare function Table<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, rowPinning, columnDefinitions, keepPinnedRows, copyPinnedRows, enableSelectPinned, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize, pageCount, loading, outline, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, suppressSearch, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp, ...rest }: TableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare function Table<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({ data, rowPinning, columnDefinitions, keepPinnedRows, copyPinnedRows, enableSelectPinned, rowSelection: rowSelectionProp, search, sorting: sortingProp, columnFilters, pagination: paginationProp, className, onRowClick, onRefresh, pageSize, pageCount, loading, outline, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar, suppressSearch, toolbarAfter, suppressPagination, manualSorting, manualPagination, manualFiltering, autoResetPageIndex, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, saveStateSettings, bulkActions: bulkActionsProp, ...rest }: TableProps<TData, TFilters>): import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
export declare namespace Table {
|
|
6
6
|
var getStatusColumnDef: typeof import("../../helperComponents").getStatusColumnDef;
|
|
7
7
|
var statusAppearances: Record<string, string>;
|
|
@@ -26,13 +26,14 @@ import { getTreeColumnDef } from '../../helperComponents/Cells/TreeCell';
|
|
|
26
26
|
import { fuzzyFilter } from '../../utils';
|
|
27
27
|
import { useLoadingTable, useStateControl } from './hooks';
|
|
28
28
|
import { usePageReset } from './hooks/usePageReset';
|
|
29
|
+
import { useSaveTableSettings } from './hooks/useSaveTableSettings/useSaveTableSettings';
|
|
29
30
|
import styles from './styles.module.css';
|
|
30
31
|
import { getColumnStyleVars, getCurrentlyConfiguredHeaderWidth, getInitColumnSizeFromLocalStorage, saveStateToLocalStorage, } from './utils';
|
|
31
32
|
/** Компонент таблицы */
|
|
32
33
|
export function Table(_a) {
|
|
33
34
|
var { data, rowPinning = {
|
|
34
35
|
top: [],
|
|
35
|
-
}, 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, outline = false, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, suppressSearch = false, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, autoResetPageIndex = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, bulkActions: bulkActionsProp } = _a, rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "bulkActions"]);
|
|
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, outline = false, moreActions, exportSettings, dataFiltered, dataError, noDataState, noResultsState, errorDataState, suppressToolbar = false, suppressSearch = false, toolbarAfter, suppressPagination = false, manualSorting = false, manualPagination = false, manualFiltering = false, autoResetPageIndex = false, scrollRef, scrollContainerRef, getRowId, enableFuzzySearch, savedState, expanding, saveStateSettings, bulkActions: bulkActionsProp } = _a, rest = __rest(_a, ["data", "rowPinning", "columnDefinitions", "keepPinnedRows", "copyPinnedRows", "enableSelectPinned", "rowSelection", "search", "sorting", "columnFilters", "pagination", "className", "onRowClick", "onRefresh", "pageSize", "pageCount", "loading", "outline", "moreActions", "exportSettings", "dataFiltered", "dataError", "noDataState", "noResultsState", "errorDataState", "suppressToolbar", "suppressSearch", "toolbarAfter", "suppressPagination", "manualSorting", "manualPagination", "manualFiltering", "autoResetPageIndex", "scrollRef", "scrollContainerRef", "getRowId", "enableFuzzySearch", "savedState", "expanding", "saveStateSettings", "bulkActions"]);
|
|
36
37
|
const { state: globalFilter, onStateChange: onGlobalFilterChange } = useStateControl(search, '');
|
|
37
38
|
const { state: rowSelection, onStateChange: onRowSelectionChange } = useStateControl(rowSelectionProp, {});
|
|
38
39
|
const defaultPaginationState = useMemo(() => ({
|
|
@@ -41,6 +42,13 @@ export function Table(_a) {
|
|
|
41
42
|
}), [pageSize]);
|
|
42
43
|
const { state: sorting, onStateChange: onSortingChange } = useStateControl(sortingProp, []);
|
|
43
44
|
const { state: pagination, onStateChange: onPaginationChange } = useStateControl(paginationProp, defaultPaginationState);
|
|
45
|
+
const { patchedFilter, isSettingsLoaded } = useSaveTableSettings({
|
|
46
|
+
pagination: { state: pagination, handler: onPaginationChange },
|
|
47
|
+
search: { state: globalFilter, handler: onGlobalFilterChange },
|
|
48
|
+
sorting: { state: sorting, handler: onSortingChange },
|
|
49
|
+
filters: columnFilters,
|
|
50
|
+
options: saveStateSettings,
|
|
51
|
+
});
|
|
44
52
|
const enableSelection = Boolean(rowSelectionProp === null || rowSelectionProp === void 0 ? void 0 : rowSelectionProp.enable);
|
|
45
53
|
const tableColumns = useMemo(() => {
|
|
46
54
|
let cols = columnDefinitions;
|
|
@@ -237,14 +245,14 @@ export function Table(_a) {
|
|
|
237
245
|
const showToolbar = !suppressToolbar;
|
|
238
246
|
return (_jsx(CellAutoResizeContext.Provider, { value: { updateCellMap }, children: _jsxs("div", Object.assign({ style: {
|
|
239
247
|
'--page-size': cssPageSize,
|
|
240
|
-
}, className: cn(styles.wrapper, className) }, extractSupportProps(rest), { children: [showToolbar && (_jsx("div", { className: styles.header, children: _jsx(Toolbar, { search: suppressSearch
|
|
248
|
+
}, className: cn(styles.wrapper, className) }, extractSupportProps(rest), { children: [showToolbar && isSettingsLoaded && (_jsx("div", { className: styles.header, children: _jsx(Toolbar, { search: suppressSearch
|
|
241
249
|
? undefined
|
|
242
250
|
: {
|
|
243
251
|
value: globalFilter,
|
|
244
252
|
onChange: onGlobalFilterChange,
|
|
245
253
|
loading: search === null || search === void 0 ? void 0 : search.loading,
|
|
246
254
|
placeholder: (search === null || search === void 0 ? void 0 : search.placeholder) || t('searchPlaceholder'),
|
|
247
|
-
}, 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 ? handleOnCheck : 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:
|
|
255
|
+
}, 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 ? handleOnCheck : 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 }) })), _jsx("div", { className: styles.scrollWrapper, "data-outline": outline || undefined, children: _jsxs(Scroll, { size: 's', className: styles.table, ref: scrollContainerRef, children: [_jsx("div", { className: styles.tableContent, style: columnSizeVars, children: _jsx(TableContext.Provider, { value: { table }, children: loading ? (_jsxs(SkeletonContextProvider, { loading: true, children: [_jsx(HeaderRow, {}), loadingTableRows.map(row => (_jsx(BodyRow, { row: row }, 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 }, row.id))) })) : null, centerRows.map(row => (_jsx(BodyRow, { row: row, onRowClick: onRowClick }, 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 })] }) }), !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 }))] })) }));
|
|
248
256
|
}
|
|
249
257
|
Table.getStatusColumnDef = getStatusColumnDef;
|
|
250
258
|
Table.statusAppearances = STATUS_APPEARANCE;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useSaveTableSettings';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useSaveTableSettings';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PaginationState, SortingState } from '@tanstack/react-table';
|
|
2
|
+
import { Handler } from 'uncontrollable';
|
|
3
|
+
import { ChipChoiceRowProps, FiltersState } from '@snack-uikit/chips';
|
|
4
|
+
import { FilterRow } from '@snack-uikit/toolbar/src/components/Toolbar/types';
|
|
5
|
+
import { FilterStateOptions } from '@snack-uikit/utils';
|
|
6
|
+
type State<T> = {
|
|
7
|
+
state: T;
|
|
8
|
+
handler: Handler;
|
|
9
|
+
};
|
|
10
|
+
type TableSettings<TFilter extends FiltersState = Record<string, unknown>> = {
|
|
11
|
+
options?: FilterStateOptions<TFilter>;
|
|
12
|
+
filters?: ChipChoiceRowProps<TFilter>;
|
|
13
|
+
pagination: State<PaginationState>;
|
|
14
|
+
search: State<string>;
|
|
15
|
+
sorting: State<SortingState>;
|
|
16
|
+
};
|
|
17
|
+
export declare const useSaveTableSettings: <TFilter extends FiltersState = Record<string, unknown>>({ options, filters, pagination: { state: paginationState, handler: paginationHandler }, search: { state: searchState, handler: searchHandler }, sorting: { state: sortingState, handler: sortingHandler }, }: TableSettings<TFilter>) => {
|
|
18
|
+
patchedFilter: FilterRow<TFilter> | undefined;
|
|
19
|
+
isSettingsLoaded: boolean;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { useSaveFilterState } from '@snack-uikit/utils';
|
|
3
|
+
import { customDateParser } from '../../../../utils';
|
|
4
|
+
import { validatePaging, validateSorting } from './vallidators';
|
|
5
|
+
export const useSaveTableSettings = ({ options, filters, pagination: { state: paginationState, handler: paginationHandler }, search: { state: searchState, handler: searchHandler }, sorting: { state: sortingState, handler: sortingHandler }, }) => {
|
|
6
|
+
const [filter, setFilter] = useState(filters === null || filters === void 0 ? void 0 : filters.value);
|
|
7
|
+
const [isSettingsLoaded, setIsSettingsLoaded] = useState(false);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setFilter(filters === null || filters === void 0 ? void 0 : filters.value);
|
|
10
|
+
}, [filters === null || filters === void 0 ? void 0 : filters.value]);
|
|
11
|
+
const settings = useMemo(() => ({
|
|
12
|
+
pagination: paginationState,
|
|
13
|
+
filter,
|
|
14
|
+
search: searchState,
|
|
15
|
+
sorting: sortingState,
|
|
16
|
+
}), [paginationState, filter, searchState, sortingState]);
|
|
17
|
+
const onFilterChange = useCallback((value) => {
|
|
18
|
+
(filters === null || filters === void 0 ? void 0 : filters.onChange) && filters.onChange(value);
|
|
19
|
+
setFilter(value);
|
|
20
|
+
},
|
|
21
|
+
// eslint-disable-next-line
|
|
22
|
+
[filters === null || filters === void 0 ? void 0 : filters.onChange]);
|
|
23
|
+
const validate = useCallback((data) => {
|
|
24
|
+
const isPaginationValid = validatePaging(data === null || data === void 0 ? void 0 : data.pagination);
|
|
25
|
+
const isSortingValid = validateSorting(data === null || data === void 0 ? void 0 : data.sorting);
|
|
26
|
+
const isSearchValid = typeof (data === null || data === void 0 ? void 0 : data.search) === 'string';
|
|
27
|
+
const isFilterValid = Boolean(options === null || options === void 0 ? void 0 : options.validateData(data === null || data === void 0 ? void 0 : data.filter));
|
|
28
|
+
return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
|
|
29
|
+
}, [options]);
|
|
30
|
+
const onInitPage = useCallback((data) => {
|
|
31
|
+
if (!data) {
|
|
32
|
+
setIsSettingsLoaded(true);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
data.pagination && paginationHandler(data.pagination);
|
|
36
|
+
data.search && searchHandler(data.search);
|
|
37
|
+
data.sorting && sortingHandler(data.sorting);
|
|
38
|
+
data.filter && onFilterChange(customDateParser(data.filter));
|
|
39
|
+
setIsSettingsLoaded(true);
|
|
40
|
+
// eslint-disable-next-line
|
|
41
|
+
}, []);
|
|
42
|
+
const filterStateOptions = useMemo(() => (options ? Object.assign(Object.assign({}, options), { validateData: validate }) : undefined), [options, validate]);
|
|
43
|
+
useSaveFilterState({
|
|
44
|
+
filter: settings,
|
|
45
|
+
options: filterStateOptions,
|
|
46
|
+
onLoadFilter: onInitPage,
|
|
47
|
+
});
|
|
48
|
+
const patchedFilter = useMemo(() => (filters ? Object.assign(Object.assign({}, filters), { value: filter, onChange: onFilterChange }) : undefined), [filters, onFilterChange, filter]);
|
|
49
|
+
return {
|
|
50
|
+
patchedFilter,
|
|
51
|
+
isSettingsLoaded,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export 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';
|
|
2
|
+
export 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');
|
|
@@ -2,14 +2,14 @@ import { PaginationState, Row, RowPinningState, RowSelectionOptions, RowSelectio
|
|
|
2
2
|
import { ReactNode, RefObject } from 'react';
|
|
3
3
|
import { ChipChoiceRowProps, FiltersState } from '@snack-uikit/chips';
|
|
4
4
|
import { ToolbarProps } from '@snack-uikit/toolbar';
|
|
5
|
-
import { WithSupportProps } from '@snack-uikit/utils';
|
|
5
|
+
import { FilterStateOptions, WithSupportProps } from '@snack-uikit/utils';
|
|
6
6
|
import { EmptyStateProps, ExportButtonProps, RowClickHandler } from '../helperComponents';
|
|
7
7
|
import { TreeColumnDefinitionProps } from '../helperComponents/Cells/TreeCell';
|
|
8
8
|
import { ColumnDefinition } from '../types';
|
|
9
9
|
type BulkAction = Omit<NonNullable<ToolbarProps<Record<string, string>>['bulkActions']>[number], 'onClick'> & {
|
|
10
10
|
onClick?(selectionState: RowSelectionState, resetRowSelection: (defaultState?: boolean) => void): void;
|
|
11
11
|
};
|
|
12
|
-
export type TableProps<TData extends object, TFilters extends FiltersState
|
|
12
|
+
export type TableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = WithSupportProps<{
|
|
13
13
|
/** Данные для отрисовки */
|
|
14
14
|
data: TData[];
|
|
15
15
|
/** Определение внешнего вида и функционала колонок */
|
|
@@ -64,6 +64,8 @@ export type TableProps<TData extends object, TFilters extends FiltersState> = Wi
|
|
|
64
64
|
loading?: boolean;
|
|
65
65
|
onChange?(value: string): void;
|
|
66
66
|
};
|
|
67
|
+
/** Настройки для сохранения состояний таблицы в query params и local storage*/
|
|
68
|
+
saveStateSettings: FilterStateOptions<TFilters>;
|
|
67
69
|
/** Включить нечеткий поиск */
|
|
68
70
|
enableFuzzySearch?: boolean;
|
|
69
71
|
/** Максимальное кол-во строк на страницу @default 10 */
|
|
@@ -143,7 +145,7 @@ export type TableProps<TData extends object, TFilters extends FiltersState> = Wi
|
|
|
143
145
|
resize?: boolean;
|
|
144
146
|
};
|
|
145
147
|
}>;
|
|
146
|
-
export type ServerTableProps<TData extends object, TFilters extends FiltersState
|
|
148
|
+
export type ServerTableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Omit<TableProps<TData, TFilters>, 'pageSize' | 'pageCount' | 'pagination' | 'search' | 'data'> & {
|
|
147
149
|
/** Данные для отрисовки */
|
|
148
150
|
items?: TData[];
|
|
149
151
|
/**
|
|
@@ -3,6 +3,7 @@ import { useCallback, useMemo } from 'react';
|
|
|
3
3
|
import { ChipChoice } from '@snack-uikit/chips';
|
|
4
4
|
import { useLocale } from '@snack-uikit/locale';
|
|
5
5
|
import { Pagination } from '@snack-uikit/pagination';
|
|
6
|
+
import { isBrowser } from '@snack-uikit/utils';
|
|
6
7
|
import styles from './styles.module.css';
|
|
7
8
|
export function TablePagination({ table, options: optionsProp, optionsLabel: optionsLabelProp, optionsRender, }) {
|
|
8
9
|
const { t } = useLocale('Table');
|
|
@@ -21,5 +22,5 @@ export function TablePagination({ table, options: optionsProp, optionsLabel: opt
|
|
|
21
22
|
if (table.getPageCount() <= 1 && !options) {
|
|
22
23
|
return null;
|
|
23
24
|
}
|
|
24
|
-
return (_jsxs("div", { className: styles.footer, children: [table.getPageCount() > 1 && (_jsx(Pagination, { total: table.getPageCount(), page: tablePaginationState.pageIndex + 1, onChange: handlePaginationOnChange, size: 'xs', className: styles.pagination })), options && table.getRowModel().rows.length >= Number(options[0].value) && (_jsx(ChipChoice.Single, { value: String(tablePaginationState.pageSize), onChange: handleRowsVolumeOnChange, placement: 'top-end', options: options, label: optionsLabel, widthStrategy: 'auto', size: 'xs' }))] }));
|
|
25
|
+
return (_jsxs("div", { className: styles.footer, children: [table.getPageCount() > 1 && (_jsx(Pagination, { total: table.getPageCount(), page: tablePaginationState.pageIndex + 1, onChange: handlePaginationOnChange, size: 'xs', className: styles.pagination })), options && table.getRowModel().rows.length >= Number(options[0].value) && (_jsx(ChipChoice.Single, { value: String(tablePaginationState.pageSize), onChange: handleRowsVolumeOnChange, placement: 'top-end', onClick: () => isBrowser() && window.location.reload(), options: options, label: optionsLabel, widthStrategy: 'auto', size: 'xs' }))] }));
|
|
25
26
|
}
|
package/dist/esm/utils.d.ts
CHANGED
package/dist/esm/utils.js
CHANGED
|
@@ -15,3 +15,13 @@ export const preciseFilter = (row, columnId, value, addMeta) => {
|
|
|
15
15
|
});
|
|
16
16
|
return itemRank.passed;
|
|
17
17
|
};
|
|
18
|
+
const isDateString = (value) => typeof value === 'string' && !isNaN(Number(new Date(value)));
|
|
19
|
+
export const customDateParser = (value) => Object.fromEntries(Object.entries(value).map(([key, value]) => {
|
|
20
|
+
if (isDateString(value)) {
|
|
21
|
+
return [key, new Date(value)];
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(value) && value.some(isDateString)) {
|
|
24
|
+
return [key, value.map(element => (isDateString(element) ? new Date(element) : element))];
|
|
25
|
+
}
|
|
26
|
+
return [key, value];
|
|
27
|
+
}));
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Table",
|
|
7
|
-
"version": "0.28.
|
|
7
|
+
"version": "0.28.6-preview-e840ab81.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -36,20 +36,20 @@
|
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
37
|
"scripts": {},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@snack-uikit/button": "0.19.
|
|
40
|
-
"@snack-uikit/chips": "0.25.
|
|
41
|
-
"@snack-uikit/icon-predefined": "0.7.
|
|
42
|
-
"@snack-uikit/icons": "0.24.
|
|
43
|
-
"@snack-uikit/info-block": "0.6.
|
|
44
|
-
"@snack-uikit/list": "0.25.0",
|
|
45
|
-
"@snack-uikit/pagination": "0.10.
|
|
46
|
-
"@snack-uikit/scroll": "0.9.
|
|
47
|
-
"@snack-uikit/skeleton": "0.6.
|
|
48
|
-
"@snack-uikit/toggles": "0.13.
|
|
49
|
-
"@snack-uikit/toolbar": "0.11.
|
|
50
|
-
"@snack-uikit/truncate-string": "0.6.
|
|
51
|
-
"@snack-uikit/typography": "0.8.
|
|
52
|
-
"@snack-uikit/utils": "3.7.0",
|
|
39
|
+
"@snack-uikit/button": "0.19.8-preview-e840ab81.0",
|
|
40
|
+
"@snack-uikit/chips": "0.25.3-preview-e840ab81.0",
|
|
41
|
+
"@snack-uikit/icon-predefined": "0.7.4-preview-e840ab81.0",
|
|
42
|
+
"@snack-uikit/icons": "0.24.3-preview-e840ab81.0",
|
|
43
|
+
"@snack-uikit/info-block": "0.6.14-preview-e840ab81.0",
|
|
44
|
+
"@snack-uikit/list": "0.25.1-preview-e840ab81.0",
|
|
45
|
+
"@snack-uikit/pagination": "0.10.3-preview-e840ab81.0",
|
|
46
|
+
"@snack-uikit/scroll": "0.9.4-preview-e840ab81.0",
|
|
47
|
+
"@snack-uikit/skeleton": "0.6.3-preview-e840ab81.0",
|
|
48
|
+
"@snack-uikit/toggles": "0.13.6-preview-e840ab81.0",
|
|
49
|
+
"@snack-uikit/toolbar": "0.11.6-preview-e840ab81.0",
|
|
50
|
+
"@snack-uikit/truncate-string": "0.6.10-preview-e840ab81.0",
|
|
51
|
+
"@snack-uikit/typography": "0.8.5-preview-e840ab81.0",
|
|
52
|
+
"@snack-uikit/utils": "3.7.1-preview-e840ab81.0",
|
|
53
53
|
"@tanstack/match-sorter-utils": "8.11.8",
|
|
54
54
|
"@tanstack/react-table": "8.12.0",
|
|
55
55
|
"classnames": "2.5.1",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@snack-uikit/locale": "*"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "1dc61e115ed2debadc06541b10d10df416d1d5e5"
|
|
65
65
|
}
|
|
@@ -10,7 +10,7 @@ import { ServerTableProps } from '../types';
|
|
|
10
10
|
import { DEFAULT_PAGINATION_LIMIT } from './constants';
|
|
11
11
|
import { onSearchDebounced } from './utils';
|
|
12
12
|
|
|
13
|
-
export function ServerTable<TData extends object, TFilters extends FiltersState
|
|
13
|
+
export function ServerTable<TData extends object, TFilters extends FiltersState = Record<string, unknown>>({
|
|
14
14
|
items,
|
|
15
15
|
total = DEFAULT_PAGINATION_LIMIT,
|
|
16
16
|
limit = DEFAULT_PAGINATION_LIMIT,
|
|
@@ -45,6 +45,7 @@ import { fuzzyFilter } from '../../utils';
|
|
|
45
45
|
import { TableProps } from '../types';
|
|
46
46
|
import { useLoadingTable, useStateControl } from './hooks';
|
|
47
47
|
import { usePageReset } from './hooks/usePageReset';
|
|
48
|
+
import { useSaveTableSettings } from './hooks/useSaveTableSettings/useSaveTableSettings';
|
|
48
49
|
import styles from './styles.module.scss';
|
|
49
50
|
import {
|
|
50
51
|
getColumnStyleVars,
|
|
@@ -96,6 +97,7 @@ export function Table<TData extends object, TFilters extends FiltersState = Reco
|
|
|
96
97
|
enableFuzzySearch,
|
|
97
98
|
savedState,
|
|
98
99
|
expanding,
|
|
100
|
+
saveStateSettings,
|
|
99
101
|
bulkActions: bulkActionsProp,
|
|
100
102
|
...rest
|
|
101
103
|
}: TableProps<TData, TFilters>) {
|
|
@@ -104,7 +106,6 @@ export function Table<TData extends object, TFilters extends FiltersState = Reco
|
|
|
104
106
|
rowSelectionProp,
|
|
105
107
|
{},
|
|
106
108
|
);
|
|
107
|
-
|
|
108
109
|
const defaultPaginationState = useMemo(
|
|
109
110
|
() => ({
|
|
110
111
|
pageIndex: 0,
|
|
@@ -117,6 +118,15 @@ export function Table<TData extends object, TFilters extends FiltersState = Reco
|
|
|
117
118
|
paginationProp,
|
|
118
119
|
defaultPaginationState,
|
|
119
120
|
);
|
|
121
|
+
|
|
122
|
+
const { patchedFilter, isSettingsLoaded } = useSaveTableSettings({
|
|
123
|
+
pagination: { state: pagination, handler: onPaginationChange },
|
|
124
|
+
search: { state: globalFilter, handler: onGlobalFilterChange },
|
|
125
|
+
sorting: { state: sorting, handler: onSortingChange },
|
|
126
|
+
filters: columnFilters,
|
|
127
|
+
options: saveStateSettings,
|
|
128
|
+
});
|
|
129
|
+
|
|
120
130
|
const enableSelection = Boolean(rowSelectionProp?.enable);
|
|
121
131
|
|
|
122
132
|
const tableColumns: ColumnDefinition<TData>[] = useMemo(() => {
|
|
@@ -366,7 +376,7 @@ export function Table<TData extends object, TFilters extends FiltersState = Reco
|
|
|
366
376
|
className={cn(styles.wrapper, className)}
|
|
367
377
|
{...extractSupportProps(rest)}
|
|
368
378
|
>
|
|
369
|
-
{showToolbar && (
|
|
379
|
+
{showToolbar && isSettingsLoaded && (
|
|
370
380
|
<div className={styles.header}>
|
|
371
381
|
<Toolbar
|
|
372
382
|
search={
|
|
@@ -404,7 +414,7 @@ export function Table<TData extends object, TFilters extends FiltersState = Reco
|
|
|
404
414
|
) : undefined
|
|
405
415
|
}
|
|
406
416
|
moreActions={moreActions}
|
|
407
|
-
filterRow={
|
|
417
|
+
filterRow={patchedFilter}
|
|
408
418
|
data-test-id={TEST_IDS.toolbar}
|
|
409
419
|
/>
|
|
410
420
|
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useSaveTableSettings';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { PaginationState, SortingState } from '@tanstack/react-table';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { Handler } from 'uncontrollable';
|
|
4
|
+
|
|
5
|
+
import { ChipChoiceRowProps, FiltersState } from '@snack-uikit/chips';
|
|
6
|
+
import { FilterRow } from '@snack-uikit/toolbar/src/components/Toolbar/types';
|
|
7
|
+
import { FilterStateOptions, useSaveFilterState } from '@snack-uikit/utils';
|
|
8
|
+
|
|
9
|
+
import { customDateParser } from '../../../../utils';
|
|
10
|
+
import { validatePaging, validateSorting } from './vallidators';
|
|
11
|
+
|
|
12
|
+
type State<T> = {
|
|
13
|
+
state: T;
|
|
14
|
+
handler: Handler;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type Settings<TFilter> = {
|
|
18
|
+
filter?: TFilter;
|
|
19
|
+
pagination: PaginationState;
|
|
20
|
+
search: string;
|
|
21
|
+
sorting: SortingState;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type ValidationFn<TFilter> = (value: unknown) => value is Settings<TFilter>;
|
|
25
|
+
|
|
26
|
+
type TableSettings<TFilter extends FiltersState = Record<string, unknown>> = {
|
|
27
|
+
options?: FilterStateOptions<TFilter>;
|
|
28
|
+
filters?: ChipChoiceRowProps<TFilter>;
|
|
29
|
+
pagination: State<PaginationState>;
|
|
30
|
+
search: State<string>;
|
|
31
|
+
sorting: State<SortingState>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const useSaveTableSettings = <TFilter extends FiltersState = Record<string, unknown>>({
|
|
35
|
+
options,
|
|
36
|
+
filters,
|
|
37
|
+
pagination: { state: paginationState, handler: paginationHandler },
|
|
38
|
+
search: { state: searchState, handler: searchHandler },
|
|
39
|
+
sorting: { state: sortingState, handler: sortingHandler },
|
|
40
|
+
}: TableSettings<TFilter>) => {
|
|
41
|
+
const [filter, setFilter] = useState<TFilter | undefined>(filters?.value);
|
|
42
|
+
const [isSettingsLoaded, setIsSettingsLoaded] = useState<boolean>(false);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
setFilter(filters?.value);
|
|
45
|
+
}, [filters?.value]);
|
|
46
|
+
|
|
47
|
+
const settings = useMemo<Settings<TFilter>>(
|
|
48
|
+
() => ({
|
|
49
|
+
pagination: paginationState,
|
|
50
|
+
filter,
|
|
51
|
+
search: searchState,
|
|
52
|
+
sorting: sortingState,
|
|
53
|
+
}),
|
|
54
|
+
[paginationState, filter, searchState, sortingState],
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const onFilterChange = useCallback(
|
|
58
|
+
(value: TFilter) => {
|
|
59
|
+
filters?.onChange && filters.onChange(value);
|
|
60
|
+
setFilter(value);
|
|
61
|
+
},
|
|
62
|
+
// eslint-disable-next-line
|
|
63
|
+
[filters?.onChange],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const validate = useCallback<ValidationFn<TFilter>>(
|
|
67
|
+
(data: unknown): data is Settings<TFilter> => {
|
|
68
|
+
const isPaginationValid = validatePaging((data as Settings<TFilter>)?.pagination);
|
|
69
|
+
const isSortingValid = validateSorting((data as Settings<TFilter>)?.sorting);
|
|
70
|
+
const isSearchValid = typeof (data as Settings<TFilter>)?.search === 'string';
|
|
71
|
+
const isFilterValid = Boolean(options?.validateData((data as Settings<TFilter>)?.filter));
|
|
72
|
+
return isPaginationValid && isSortingValid && isSearchValid && isFilterValid;
|
|
73
|
+
},
|
|
74
|
+
[options],
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const onInitPage = useCallback((data: Settings<TFilter> | null) => {
|
|
78
|
+
if (!data) {
|
|
79
|
+
setIsSettingsLoaded(true);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
data.pagination && paginationHandler(data.pagination);
|
|
83
|
+
data.search && searchHandler(data.search);
|
|
84
|
+
data.sorting && sortingHandler(data.sorting);
|
|
85
|
+
data.filter && onFilterChange(customDateParser(data.filter));
|
|
86
|
+
setIsSettingsLoaded(true);
|
|
87
|
+
// eslint-disable-next-line
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
const filterStateOptions = useMemo<FilterStateOptions<Settings<TFilter>> | undefined>(
|
|
91
|
+
() => (options ? { ...options, validateData: validate } : undefined),
|
|
92
|
+
[options, validate],
|
|
93
|
+
);
|
|
94
|
+
useSaveFilterState<Settings<TFilter>>({
|
|
95
|
+
filter: settings,
|
|
96
|
+
options: filterStateOptions,
|
|
97
|
+
onLoadFilter: onInitPage,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const patchedFilter = useMemo<FilterRow<TFilter> | undefined>(
|
|
101
|
+
() => (filters ? { ...filters, value: filter, onChange: onFilterChange } : undefined),
|
|
102
|
+
[filters, onFilterChange, filter],
|
|
103
|
+
);
|
|
104
|
+
return {
|
|
105
|
+
patchedFilter,
|
|
106
|
+
isSettingsLoaded,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PaginationState, SortingState } from '@tanstack/react-table';
|
|
2
|
+
|
|
3
|
+
export const validatePaging = (value: unknown): value is PaginationState =>
|
|
4
|
+
typeof (value as PaginationState)?.pageSize === 'number' && typeof (value as PaginationState)?.pageIndex === 'number';
|
|
5
|
+
|
|
6
|
+
export const validateSorting = (value: unknown): value is SortingState =>
|
|
7
|
+
(value as SortingState)?.every(column => typeof column?.id === 'string' && typeof column?.desc === 'boolean');
|
package/src/components/types.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { ReactNode, RefObject } from 'react';
|
|
|
10
10
|
|
|
11
11
|
import { ChipChoiceRowProps, FiltersState } from '@snack-uikit/chips';
|
|
12
12
|
import { ToolbarProps } from '@snack-uikit/toolbar';
|
|
13
|
-
import { WithSupportProps } from '@snack-uikit/utils';
|
|
13
|
+
import { FilterStateOptions, WithSupportProps } from '@snack-uikit/utils';
|
|
14
14
|
|
|
15
15
|
import { EmptyStateProps, ExportButtonProps, RowClickHandler } from '../helperComponents';
|
|
16
16
|
import { TreeColumnDefinitionProps } from '../helperComponents/Cells/TreeCell';
|
|
@@ -20,7 +20,10 @@ type BulkAction = Omit<NonNullable<ToolbarProps<Record<string, string>>['bulkAct
|
|
|
20
20
|
onClick?(selectionState: RowSelectionState, resetRowSelection: (defaultState?: boolean) => void): void;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
export type TableProps<
|
|
23
|
+
export type TableProps<
|
|
24
|
+
TData extends object,
|
|
25
|
+
TFilters extends FiltersState = Record<string, unknown>,
|
|
26
|
+
> = WithSupportProps<{
|
|
24
27
|
/** Данные для отрисовки */
|
|
25
28
|
data: TData[];
|
|
26
29
|
/** Определение внешнего вида и функционала колонок */
|
|
@@ -77,6 +80,9 @@ export type TableProps<TData extends object, TFilters extends FiltersState> = Wi
|
|
|
77
80
|
onChange?(value: string): void;
|
|
78
81
|
};
|
|
79
82
|
|
|
83
|
+
/** Настройки для сохранения состояний таблицы в query params и local storage*/
|
|
84
|
+
saveStateSettings: FilterStateOptions<TFilters>;
|
|
85
|
+
|
|
80
86
|
/** Включить нечеткий поиск */
|
|
81
87
|
enableFuzzySearch?: boolean;
|
|
82
88
|
|
|
@@ -175,7 +181,7 @@ export type TableProps<TData extends object, TFilters extends FiltersState> = Wi
|
|
|
175
181
|
};
|
|
176
182
|
}>;
|
|
177
183
|
|
|
178
|
-
export type ServerTableProps<TData extends object, TFilters extends FiltersState
|
|
184
|
+
export type ServerTableProps<TData extends object, TFilters extends FiltersState = Record<string, unknown>> = Omit<
|
|
179
185
|
TableProps<TData, TFilters>,
|
|
180
186
|
'pageSize' | 'pageCount' | 'pagination' | 'search' | 'data'
|
|
181
187
|
> & {
|
|
@@ -4,6 +4,7 @@ import { useCallback, useMemo } from 'react';
|
|
|
4
4
|
import { ChipChoice } from '@snack-uikit/chips';
|
|
5
5
|
import { useLocale } from '@snack-uikit/locale';
|
|
6
6
|
import { Pagination } from '@snack-uikit/pagination';
|
|
7
|
+
import { isBrowser } from '@snack-uikit/utils';
|
|
7
8
|
|
|
8
9
|
import styles from './styles.module.scss';
|
|
9
10
|
|
|
@@ -72,6 +73,7 @@ export function TablePagination<TData>({
|
|
|
72
73
|
value={String(tablePaginationState.pageSize)}
|
|
73
74
|
onChange={handleRowsVolumeOnChange}
|
|
74
75
|
placement='top-end'
|
|
76
|
+
onClick={() => isBrowser() && window.location.reload()}
|
|
75
77
|
options={options}
|
|
76
78
|
label={optionsLabel}
|
|
77
79
|
widthStrategy='auto'
|
package/src/utils.ts
CHANGED
|
@@ -22,3 +22,17 @@ export const preciseFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
|
|
|
22
22
|
|
|
23
23
|
return itemRank.passed;
|
|
24
24
|
};
|
|
25
|
+
|
|
26
|
+
const isDateString = (value: unknown): value is string => typeof value === 'string' && !isNaN(Number(new Date(value)));
|
|
27
|
+
export const customDateParser = <T>(value: Record<string, unknown>): T =>
|
|
28
|
+
Object.fromEntries(
|
|
29
|
+
Object.entries(value).map(([key, value]) => {
|
|
30
|
+
if (isDateString(value)) {
|
|
31
|
+
return [key, new Date(value)];
|
|
32
|
+
}
|
|
33
|
+
if (Array.isArray(value) && value.some(isDateString)) {
|
|
34
|
+
return [key, value.map(element => (isDateString(element) ? new Date(element) : element))];
|
|
35
|
+
}
|
|
36
|
+
return [key, value];
|
|
37
|
+
}),
|
|
38
|
+
) as T;
|