@snack-uikit/table 0.28.5 → 0.28.6-preview-f7ec3fa7.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/README.md +2 -0
- 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 +3 -1
- 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/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 +3 -1
- 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/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 +4 -1
- package/src/helperComponents/TablePagination/TablePagination.tsx +2 -0
- package/src/utils.ts +14 -0
package/README.md
CHANGED
|
@@ -118,6 +118,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
|
|
|
118
118
|
| expanding | `{ getSubRows: (element: TData) => TData[]; expandingColumnDefinition: TreeColumnDefinitionProps<TData>; }` | - | Параметр отвечает за общие настройки раскрывающихся строк |
|
|
119
119
|
| rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
|
|
120
120
|
| search | `{ initialState?: string; state?: string; placeholder?: string; loading?: boolean; onChange?(value: string): void; }` | 'Search'<br> <strong>loading</strong>: Состояние загрузки в строке поиска <br> <strong>onChange</strong>: Колбэк на изменение данных в строке поиска | Параметры отвечают за глобальный поиск в таблице <br> <strong>initialState</strong>: Начальное состояние строки поиска <br> <strong>state</strong>: Состояние строки поиска, жестко устанавливаемое снаружи <br> <strong>placeholder</strong>: Placeholder строки поиска |
|
|
121
|
+
| saveStateSettings | `FilterStateOptions<TFilters>` | - | Настройки для сохранения состояний таблицы в query params и local storage |
|
|
121
122
|
| enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
|
|
122
123
|
| pageSize | `number` | 10 | Максимальное кол-во строк на страницу |
|
|
123
124
|
| 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>: Текст для селектора кол-ва строк на страницу |
|
|
@@ -182,6 +183,7 @@ const columnDefinitions: ColumnDefinition<TableData>[] = [
|
|
|
182
183
|
| sorting | `{ initialState?: SortingState; state?: SortingState; onChange?(state: SortingState): void; }` | - | Параметры отвечают за возможность сортировки, их стоит использовать если нужно отслеживать состояние <br> <strong>initialState</strong>: Начальное состояние сортировки <br> <strong>state</strong>: Состояние сортировки, жестко устанавливаемое снаружи <br> <strong>onChange</strong>: Колбэк на изменение сортировки |
|
|
183
184
|
| expanding | `{ getSubRows: (element: TData) => TData[]; expandingColumnDefinition: TreeColumnDefinitionProps<TData>; }` | - | Параметр отвечает за общие настройки раскрывающихся строк |
|
|
184
185
|
| rowSelection | `{ initialState?: RowSelectionState; state?: RowSelectionState; enable?: boolean \| ((row: Row<TData>) => boolean); multiRow?: boolean; onChange?(state: RowSelectionState): void; }` | - | Параметры отвечают за возможность выбора строк <br> <strong>initialState</strong>: Начальное состояние выбора строк <br> <strong>state</strong>: Состояние выбора строк, жестко устанавливаемое снаружи <br> <strong>enable</strong>: Колбэк определяющий можно ли выбрать строку <br> <strong>multiRow</strong>: Мульти-выбор строк (включен по-умолчанию, когда включается выбор) <br> <strong>onChange</strong>: Колбэк на выбор строк |
|
|
186
|
+
| saveStateSettings | `FilterStateOptions<TFilters>` | - | Настройки для сохранения состояний таблицы в query params и local storage |
|
|
185
187
|
| enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
|
|
186
188
|
| autoResetPageIndex | `boolean` | - | Автоматический сброс пагинации к первой странице при изменении данных или состояния (e.g фильтры, сортировки, и т.д) |
|
|
187
189
|
| onRowClick | `RowClickHandler<TData>` | - | Колбэк клика по строке |
|
|
@@ -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,7 +2,7 @@ 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';
|
|
@@ -64,6 +64,8 @@ export type TableProps<TData extends object, TFilters extends FiltersState = Rec
|
|
|
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 */
|
|
@@ -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,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,7 +2,7 @@ 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';
|
|
@@ -64,6 +64,8 @@ export type TableProps<TData extends object, TFilters extends FiltersState = Rec
|
|
|
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 */
|
|
@@ -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-f7ec3fa7.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-f7ec3fa7.0",
|
|
40
|
+
"@snack-uikit/chips": "0.25.3-preview-f7ec3fa7.0",
|
|
41
|
+
"@snack-uikit/icon-predefined": "0.7.4-preview-f7ec3fa7.0",
|
|
42
|
+
"@snack-uikit/icons": "0.24.3-preview-f7ec3fa7.0",
|
|
43
|
+
"@snack-uikit/info-block": "0.6.14-preview-f7ec3fa7.0",
|
|
44
|
+
"@snack-uikit/list": "0.25.1-preview-f7ec3fa7.0",
|
|
45
|
+
"@snack-uikit/pagination": "0.10.3-preview-f7ec3fa7.0",
|
|
46
|
+
"@snack-uikit/scroll": "0.9.4-preview-f7ec3fa7.0",
|
|
47
|
+
"@snack-uikit/skeleton": "0.6.3-preview-f7ec3fa7.0",
|
|
48
|
+
"@snack-uikit/toggles": "0.13.6-preview-f7ec3fa7.0",
|
|
49
|
+
"@snack-uikit/toolbar": "0.11.6-preview-f7ec3fa7.0",
|
|
50
|
+
"@snack-uikit/truncate-string": "0.6.10-preview-f7ec3fa7.0",
|
|
51
|
+
"@snack-uikit/typography": "0.8.5-preview-f7ec3fa7.0",
|
|
52
|
+
"@snack-uikit/utils": "3.7.1-preview-f7ec3fa7.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": "41cd467095dc6f8b733bff37101ea84ab0e55351"
|
|
65
65
|
}
|
|
@@ -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';
|
|
@@ -80,6 +80,9 @@ export type TableProps<
|
|
|
80
80
|
onChange?(value: string): void;
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
+
/** Настройки для сохранения состояний таблицы в query params и local storage*/
|
|
84
|
+
saveStateSettings?: FilterStateOptions<TFilters>;
|
|
85
|
+
|
|
83
86
|
/** Включить нечеткий поиск */
|
|
84
87
|
enableFuzzySearch?: boolean;
|
|
85
88
|
|
|
@@ -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;
|