@addev-be/ui 0.2.6 → 0.2.8
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/assets/icons/arrow-down-1-9.svg +1 -0
- package/assets/icons/arrow-down-big-small.svg +1 -0
- package/assets/icons/arrow-up-9-1.svg +1 -0
- package/assets/icons/arrow-up-big-small.svg +1 -0
- package/assets/icons/chevron-down.svg +1 -0
- package/assets/icons/ellipsis.svg +1 -0
- package/assets/icons/sigma.svg +1 -0
- package/assets/icons/table-footer-slash.svg +5 -0
- package/assets/icons/table-footer.svg +4 -0
- package/assets/icons/table.svg +1 -0
- package/assets/icons/tally.svg +1 -0
- package/assets/icons/x-bar.svg +4 -0
- package/dist/Icons.d.ts +13 -1
- package/dist/Icons.js +25 -1
- package/dist/components/data/AdvancedRequestDataGrid/index.js +3 -3
- package/dist/components/data/DataGrid/DataGridColumnsModal/hooks.js +2 -1
- package/dist/components/data/DataGrid/DataGridFilterMenu/index.js +85 -7
- package/dist/components/data/DataGrid/DataGridFilterMenu/styles.d.ts +3 -9
- package/dist/components/data/DataGrid/DataGridFilterMenu/styles.js +10 -37
- package/dist/components/data/DataGrid/DataGridFooter.d.ts +1 -1
- package/dist/components/data/DataGrid/DataGridFooter.js +35 -12
- package/dist/components/data/DataGrid/DataGridHeader.js +1 -1
- package/dist/components/data/DataGrid/DataGridHeaderCell.js +6 -22
- package/dist/components/data/DataGrid/helpers/columns.d.ts +1 -1
- package/dist/components/data/DataGrid/helpers/columns.js +71 -16
- package/dist/components/data/DataGrid/hooks/useDataGrid.d.ts +1 -1
- package/dist/components/data/DataGrid/hooks/useDataGrid.js +60 -30
- package/dist/components/data/DataGrid/hooks/useDataGridCopy.d.ts +2 -2
- package/dist/components/data/DataGrid/hooks/useDataGridCopy.js +41 -39
- package/dist/components/data/DataGrid/index.d.ts +4 -2
- package/dist/components/data/DataGrid/index.js +22 -12
- package/dist/components/data/DataGrid/styles.d.ts +8 -4
- package/dist/components/data/DataGrid/styles.js +27 -17
- package/dist/components/data/DataGrid/types.d.ts +8 -1
- package/dist/components/data/SqlRequestDataGrid/helpers/columns.d.ts +1 -1
- package/dist/components/data/SqlRequestDataGrid/helpers/columns.js +24 -11
- package/dist/components/data/SqlRequestDataGrid/index.js +105 -33
- package/dist/components/ui/ContextMenu/index.d.ts +11 -0
- package/dist/components/ui/ContextMenu/index.js +58 -0
- package/dist/components/ui/ContextMenu/styles.d.ts +18 -0
- package/dist/components/ui/ContextMenu/styles.js +56 -0
- package/dist/services/advancedRequests.d.ts +1 -1
- package/dist/services/sqlRequests.d.ts +9 -4
- package/dist/services/sqlRequests.js +1 -0
- package/package.json +1 -1
- package/src/Icons.tsx +24 -0
- package/src/components/data/AdvancedRequestDataGrid/index.tsx +3 -5
- package/src/components/data/DataGrid/DataGridColumnsModal/hooks.tsx +2 -1
- package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +180 -22
- package/src/components/data/DataGrid/DataGridFilterMenu/styles.ts +13 -64
- package/src/components/data/DataGrid/DataGridFooter.tsx +20 -22
- package/src/components/data/DataGrid/DataGridHeader.tsx +5 -5
- package/src/components/data/DataGrid/DataGridHeaderCell.tsx +3 -38
- package/src/components/data/DataGrid/FilterValuesScroller.tsx +33 -27
- package/src/components/data/DataGrid/helpers/columns.tsx +103 -8
- package/src/components/data/DataGrid/helpers/filters.ts +29 -19
- package/src/components/data/DataGrid/hooks/useDataGrid.tsx +58 -17
- package/src/components/data/DataGrid/hooks/useDataGridCopy.ts +35 -30
- package/src/components/data/DataGrid/index.tsx +22 -14
- package/src/components/data/DataGrid/styles.ts +50 -9
- package/src/components/data/DataGrid/types.ts +24 -3
- package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +39 -3
- package/src/components/data/SqlRequestDataGrid/index.tsx +116 -21
- package/src/components/ui/ContextMenu/index.tsx +79 -0
- package/src/components/ui/ContextMenu/styles.ts +119 -0
- package/src/services/advancedRequests.ts +1 -1
- package/src/services/sqlRequests.ts +16 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,15 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
import * as styles from './styles';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
ArrowDownAZIcon,
|
|
8
|
-
ArrowUpZAIcon,
|
|
9
|
-
ArrowsUpDownIcon,
|
|
10
|
-
FilterFullIcon,
|
|
11
|
-
FilterIcon,
|
|
12
|
-
} from '../../../Icons';
|
|
13
6
|
import { MouseEvent, useCallback, useMemo, useRef, useState } from 'react';
|
|
14
7
|
|
|
8
|
+
import { ChevronDownIcon } from '../../../Icons';
|
|
15
9
|
import { DataGridFilterMenu } from './DataGridFilterMenu';
|
|
16
10
|
import { DataGridHeaderCellProps } from './types';
|
|
17
11
|
import { Dropdown } from '../../layout';
|
|
@@ -29,33 +23,12 @@ export const DataGridHeaderCell = <R,>({
|
|
|
29
23
|
const contextValue = useDataGridContext(context);
|
|
30
24
|
const {
|
|
31
25
|
filters = {},
|
|
32
|
-
sorts = {},
|
|
33
|
-
setSorts,
|
|
34
26
|
setColumnWidth,
|
|
35
27
|
saveSettings,
|
|
36
28
|
headerColor,
|
|
37
29
|
} = contextValue;
|
|
38
30
|
const filterButtonRef = useRef<HTMLButtonElement | null>(null);
|
|
39
31
|
|
|
40
|
-
/** SORTING */
|
|
41
|
-
const SortIcon = sorts[columnKey]
|
|
42
|
-
? sorts[columnKey] === 'desc'
|
|
43
|
-
? ArrowUpZAIcon
|
|
44
|
-
: ArrowDownAZIcon
|
|
45
|
-
: ArrowsUpDownIcon;
|
|
46
|
-
|
|
47
|
-
const onSortButtonClicked = useCallback(
|
|
48
|
-
(columnKey: string) => {
|
|
49
|
-
const sort = sorts[columnKey];
|
|
50
|
-
if (!sort || sort === 'desc') {
|
|
51
|
-
setSorts({ [columnKey]: 'asc' });
|
|
52
|
-
} else {
|
|
53
|
-
setSorts({ [columnKey]: 'desc' });
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
[setSorts, sorts]
|
|
57
|
-
);
|
|
58
|
-
|
|
59
32
|
/** RESIZING */
|
|
60
33
|
|
|
61
34
|
const [isResizing, setIsResizing] = useState(false);
|
|
@@ -97,7 +70,7 @@ export const DataGridHeaderCell = <R,>({
|
|
|
97
70
|
$sourceRect={filterButtonRect}
|
|
98
71
|
onClose={() => setIsFilterDropdownVisible(false)}
|
|
99
72
|
$width={320}
|
|
100
|
-
$height={[
|
|
73
|
+
$height={[250, 400]}
|
|
101
74
|
$autoPositionX
|
|
102
75
|
>
|
|
103
76
|
<DataGridFilterMenu
|
|
@@ -129,20 +102,12 @@ export const DataGridHeaderCell = <R,>({
|
|
|
129
102
|
>
|
|
130
103
|
{filterDropdown}
|
|
131
104
|
<span>{column.name}</span>
|
|
132
|
-
{!!column.sortGetter && (
|
|
133
|
-
<IconButton
|
|
134
|
-
color={headerColor}
|
|
135
|
-
size="small"
|
|
136
|
-
icon={SortIcon}
|
|
137
|
-
onClick={() => onSortButtonClicked?.(columnKey)}
|
|
138
|
-
/>
|
|
139
|
-
)}
|
|
140
105
|
{!!column.filter && (
|
|
141
106
|
<IconButton
|
|
142
107
|
size="small"
|
|
143
108
|
className={hasFilters ? 'danger' : ''}
|
|
144
109
|
ref={filterButtonRef}
|
|
145
|
-
icon={
|
|
110
|
+
icon={ChevronDownIcon}
|
|
146
111
|
color={hasFilters ? 'danger' : headerColor}
|
|
147
112
|
onClick={onFilterButtonClicked}
|
|
148
113
|
/>
|
|
@@ -29,33 +29,39 @@ const CheckboxTemplate = ({
|
|
|
29
29
|
className?: string;
|
|
30
30
|
style?: React.CSSProperties;
|
|
31
31
|
onToggle?: (values: DataGridFilterValue[]) => void;
|
|
32
|
-
}) =>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// className="inline-block mr-2"
|
|
51
|
-
/>
|
|
52
|
-
<span
|
|
53
|
-
// className="mr-2 truncate"
|
|
32
|
+
}) => {
|
|
33
|
+
const checked = useMemo(
|
|
34
|
+
() => value.values.every((v) => selectedValues.includes(v)),
|
|
35
|
+
[selectedValues, value.values]
|
|
36
|
+
);
|
|
37
|
+
return (
|
|
38
|
+
<styles.FilterValueContainer
|
|
39
|
+
key={index}
|
|
40
|
+
className={join(
|
|
41
|
+
[
|
|
42
|
+
// 'absolute left-0 right-0 flex flex-row cursor-pointer hover:bg-gray-50',
|
|
43
|
+
className,
|
|
44
|
+
],
|
|
45
|
+
' '
|
|
46
|
+
)}
|
|
47
|
+
style={{ ...style, paddingLeft: `${value.level}rem` }}
|
|
48
|
+
title={value.title}
|
|
49
|
+
onClick={() => onToggle?.(value.values)}
|
|
54
50
|
>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
<input
|
|
52
|
+
type="checkbox"
|
|
53
|
+
checked={checked}
|
|
54
|
+
readOnly
|
|
55
|
+
// className="inline-block mr-2"
|
|
56
|
+
/>
|
|
57
|
+
<span
|
|
58
|
+
// className="mr-2 truncate"
|
|
59
|
+
>
|
|
60
|
+
{value.displayValue || '(Vides)'}
|
|
61
|
+
</span>
|
|
62
|
+
</styles.FilterValueContainer>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
59
65
|
|
|
60
66
|
type FilterValuesScrollerProps = {
|
|
61
67
|
values: DataGridFilterValue[];
|
|
@@ -96,7 +102,7 @@ export const FilterValuesScroller = ({
|
|
|
96
102
|
);
|
|
97
103
|
|
|
98
104
|
const checkboxes = useMemo(
|
|
99
|
-
() => getCheckboxes(values, renderer, formatter, groups),
|
|
105
|
+
() => getCheckboxes(values, '', renderer, formatter, groups),
|
|
100
106
|
[values, groups, renderer, formatter]
|
|
101
107
|
);
|
|
102
108
|
const visibleCheckboxes = checkboxes.slice(
|
|
@@ -9,11 +9,15 @@ import {
|
|
|
9
9
|
import { numberFilter, textFilter } from './filters';
|
|
10
10
|
|
|
11
11
|
import moment from 'moment';
|
|
12
|
+
import { repeat } from 'lodash';
|
|
12
13
|
|
|
13
14
|
export const isColumnVisible = <R,>(
|
|
14
15
|
obj: DataGridColumn<R> | DataGridSettings
|
|
15
16
|
): boolean => obj?.order !== -1;
|
|
16
17
|
|
|
18
|
+
const buildExcelFormat = (decimals = 2, suffix = '') =>
|
|
19
|
+
`#0${decimals > 0 ? `.${repeat('0', decimals)}` : ''}${suffix}`;
|
|
20
|
+
|
|
17
21
|
export const textColumn = <R extends Record<string, any>>(
|
|
18
22
|
key: string,
|
|
19
23
|
title: string,
|
|
@@ -24,6 +28,7 @@ export const textColumn = <R extends Record<string, any>>(
|
|
|
24
28
|
render: (row) => row[key] ?? '',
|
|
25
29
|
getter: (row) => row[key] ?? '',
|
|
26
30
|
sortGetter: (row) => row[key] ?? '',
|
|
31
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
27
32
|
filter: textFilter(key),
|
|
28
33
|
...options,
|
|
29
34
|
},
|
|
@@ -46,6 +51,7 @@ export const mailColumn = <R extends Record<string, any>>(
|
|
|
46
51
|
),
|
|
47
52
|
getter: (row) => row[key] ?? '',
|
|
48
53
|
sortGetter: (row) => row[key] ?? '',
|
|
54
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
49
55
|
filter: textFilter(key),
|
|
50
56
|
...options,
|
|
51
57
|
},
|
|
@@ -68,6 +74,7 @@ export const phoneColumn = <R extends Record<string, any>>(
|
|
|
68
74
|
),
|
|
69
75
|
getter: (row) => row[key] ?? '',
|
|
70
76
|
sortGetter: (row) => row[key] ?? '',
|
|
77
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
71
78
|
filter: textFilter(key),
|
|
72
79
|
...options,
|
|
73
80
|
},
|
|
@@ -80,10 +87,15 @@ export const dateColumn = <R extends Record<string, any>>(
|
|
|
80
87
|
): DataGridColumns<R> => ({
|
|
81
88
|
[key]: {
|
|
82
89
|
name: title,
|
|
90
|
+
type: 'date',
|
|
83
91
|
render: (row) => moment(row[key]).format('DD/MM/YYYY') ?? '',
|
|
84
92
|
getter: (row) => row[key] ?? '',
|
|
85
93
|
sortGetter: (row) => row[key] ?? '',
|
|
86
|
-
|
|
94
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
95
|
+
filter: {
|
|
96
|
+
...textFilter(key),
|
|
97
|
+
renderer: (value) => moment(value).format('DD/MM/YYYY') ?? '',
|
|
98
|
+
},
|
|
87
99
|
...options,
|
|
88
100
|
},
|
|
89
101
|
});
|
|
@@ -98,6 +110,7 @@ export const monthColumn = <R extends Record<string, any>>(
|
|
|
98
110
|
render: (row) => (row[key] ? `${row[key]} mois ` : ''),
|
|
99
111
|
getter: (row) => row[key] ?? '',
|
|
100
112
|
sortGetter: (row) => row[key] ?? '',
|
|
113
|
+
footer: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
101
114
|
filter: textFilter(key),
|
|
102
115
|
...options,
|
|
103
116
|
},
|
|
@@ -115,11 +128,33 @@ export const numberColumn = <R extends Record<string, any>>(
|
|
|
115
128
|
excelFormatter: () => '#',
|
|
116
129
|
getter: (row) => row[key] ?? '',
|
|
117
130
|
sortGetter: (row) => row[key] ?? '',
|
|
131
|
+
footer: {
|
|
132
|
+
sum: (_, filteredRows) =>
|
|
133
|
+
formatNumber(
|
|
134
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0),
|
|
135
|
+
decimals
|
|
136
|
+
),
|
|
137
|
+
average: (_, filteredRows) =>
|
|
138
|
+
formatNumber(
|
|
139
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0) /
|
|
140
|
+
(filteredRows.length || 1),
|
|
141
|
+
decimals
|
|
142
|
+
),
|
|
143
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
144
|
+
max: (_, filteredRows) =>
|
|
145
|
+
formatNumber(
|
|
146
|
+
Math.max(...filteredRows.map((row) => row[key] ?? 0)),
|
|
147
|
+
decimals
|
|
148
|
+
),
|
|
149
|
+
min: (_, filteredRows) =>
|
|
150
|
+
formatNumber(
|
|
151
|
+
Math.min(...filteredRows.map((row) => row[key] ?? 0)),
|
|
152
|
+
decimals
|
|
153
|
+
),
|
|
154
|
+
},
|
|
118
155
|
filter: {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
values: [0],
|
|
122
|
-
getter: (value) => value ?? 0,
|
|
156
|
+
...numberFilter(key),
|
|
157
|
+
renderer: (value) => formatNumber(value, decimals) ?? '',
|
|
123
158
|
},
|
|
124
159
|
...options,
|
|
125
160
|
},
|
|
@@ -134,10 +169,37 @@ export const moneyColumn = <R extends Record<string, any>>(
|
|
|
134
169
|
[key]: {
|
|
135
170
|
name: title,
|
|
136
171
|
render: (row) => formatMoney(row[key], decimals) ?? '',
|
|
137
|
-
excelFormatter: () => '
|
|
172
|
+
excelFormatter: () => buildExcelFormat(decimals, ' €'),
|
|
138
173
|
getter: (row) => row[key] ?? '',
|
|
139
174
|
sortGetter: (row) => row[key] ?? '',
|
|
140
|
-
filter:
|
|
175
|
+
filter: {
|
|
176
|
+
...numberFilter(key),
|
|
177
|
+
renderer: (value) => formatMoney(value, decimals) ?? '',
|
|
178
|
+
},
|
|
179
|
+
footer: {
|
|
180
|
+
sum: (_, filteredRows) =>
|
|
181
|
+
formatMoney(
|
|
182
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0),
|
|
183
|
+
decimals
|
|
184
|
+
),
|
|
185
|
+
average: (_, filteredRows) =>
|
|
186
|
+
formatMoney(
|
|
187
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0) /
|
|
188
|
+
(filteredRows.length || 1),
|
|
189
|
+
decimals
|
|
190
|
+
),
|
|
191
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
192
|
+
max: (_, filteredRows) =>
|
|
193
|
+
formatMoney(
|
|
194
|
+
Math.max(...filteredRows.map((row) => row[key] ?? 0)),
|
|
195
|
+
decimals
|
|
196
|
+
),
|
|
197
|
+
min: (_, filteredRows) =>
|
|
198
|
+
formatMoney(
|
|
199
|
+
Math.min(...filteredRows.map((row) => row[key] ?? 0)),
|
|
200
|
+
decimals
|
|
201
|
+
),
|
|
202
|
+
},
|
|
141
203
|
...options,
|
|
142
204
|
},
|
|
143
205
|
});
|
|
@@ -145,15 +207,40 @@ export const moneyColumn = <R extends Record<string, any>>(
|
|
|
145
207
|
export const percentageColumn = <R extends Record<string, any>>(
|
|
146
208
|
key: string,
|
|
147
209
|
title: string,
|
|
210
|
+
decimals = 2,
|
|
148
211
|
options?: Partial<DataGridColumn<R>>
|
|
149
212
|
): DataGridColumns<R> => ({
|
|
150
213
|
[key]: {
|
|
151
214
|
name: title,
|
|
152
215
|
render: (row) => formatPercentage(row[key]) ?? '',
|
|
153
|
-
excelFormatter: () =>
|
|
216
|
+
excelFormatter: () => buildExcelFormat(decimals),
|
|
154
217
|
getter: (row) => row[key] ?? '',
|
|
155
218
|
sortGetter: (row) => row[key] ?? '',
|
|
156
219
|
filter: numberFilter(key),
|
|
220
|
+
footer: {
|
|
221
|
+
average: (_, filteredRows) =>
|
|
222
|
+
formatNumber(
|
|
223
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0) /
|
|
224
|
+
(filteredRows.length || 1),
|
|
225
|
+
decimals
|
|
226
|
+
),
|
|
227
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
228
|
+
max: (_, filteredRows) =>
|
|
229
|
+
formatNumber(
|
|
230
|
+
Math.max(...filteredRows.map((row) => row[key] ?? 0)),
|
|
231
|
+
decimals
|
|
232
|
+
),
|
|
233
|
+
min: (_, filteredRows) =>
|
|
234
|
+
formatNumber(
|
|
235
|
+
Math.min(...filteredRows.map((row) => row[key] ?? 0)),
|
|
236
|
+
decimals
|
|
237
|
+
),
|
|
238
|
+
sum: (_, filteredRows) =>
|
|
239
|
+
formatNumber(
|
|
240
|
+
filteredRows.reduce((acc, row) => acc + (row[key] ?? 0), 0),
|
|
241
|
+
decimals
|
|
242
|
+
),
|
|
243
|
+
},
|
|
157
244
|
...options,
|
|
158
245
|
},
|
|
159
246
|
});
|
|
@@ -174,6 +261,13 @@ export const checkboxColumn = <R extends Record<string, any>>(
|
|
|
174
261
|
getter: (row) => row[key] ?? '',
|
|
175
262
|
sortGetter: (row) => row[key] ?? '',
|
|
176
263
|
filter: numberFilter(key),
|
|
264
|
+
footer: {
|
|
265
|
+
count: (_, filteredRows) => `${filteredRows.length} éléments`,
|
|
266
|
+
checked: (_, filteredRows) =>
|
|
267
|
+
`${filteredRows.filter((row) => !!row[key]).length} cochés`,
|
|
268
|
+
unchecked: (_, filteredRows) =>
|
|
269
|
+
`${filteredRows.filter((row) => !row[key]).length} décochés`,
|
|
270
|
+
},
|
|
177
271
|
...options,
|
|
178
272
|
},
|
|
179
273
|
});
|
|
@@ -191,6 +285,7 @@ export const colorColumn = <R extends Record<string, any>>(
|
|
|
191
285
|
getter: (row) => row[key] ?? '',
|
|
192
286
|
sortGetter: (row) => row[key] ?? '',
|
|
193
287
|
filter: textFilter(key),
|
|
288
|
+
footer: (rows) => `${rows.length} éléments`,
|
|
194
289
|
...options,
|
|
195
290
|
},
|
|
196
291
|
});
|
|
@@ -168,8 +168,10 @@ export const getDateGroups = (dates: any[]): DataGridFilterGroup[] => {
|
|
|
168
168
|
const grouperDates = groupDatesByYearAndMonth(dates);
|
|
169
169
|
return Object.entries(grouperDates).map(([year, months]) => ({
|
|
170
170
|
name: year,
|
|
171
|
+
displayValue: year,
|
|
171
172
|
values: Object.values(months).flat(),
|
|
172
173
|
groups: Object.entries(months).map(([month, dates]) => ({
|
|
174
|
+
displayValue: month,
|
|
173
175
|
name: month,
|
|
174
176
|
values: dates,
|
|
175
177
|
})),
|
|
@@ -181,29 +183,37 @@ export const defaultRendererAndFormatter = (value: any) =>
|
|
|
181
183
|
|
|
182
184
|
export const getCheckboxes = (
|
|
183
185
|
values: DataGridFilterValue[],
|
|
186
|
+
displayValue: DataGridFilterValue,
|
|
184
187
|
renderer: DataGridFilterRenderer,
|
|
185
188
|
formatter: DataGridFilterFormatter,
|
|
186
189
|
groups?: DataGridFilterGroup[],
|
|
187
190
|
level = 0
|
|
188
|
-
): DataGridFilterCheckbox[] =>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
]
|
|
191
|
+
): DataGridFilterCheckbox[] =>
|
|
192
|
+
groups
|
|
193
|
+
? groups
|
|
194
|
+
.map<DataGridFilterCheckbox[]>((group) => [
|
|
195
|
+
{
|
|
196
|
+
displayValue: group.displayValue,
|
|
197
|
+
title: formatter(group.displayValue),
|
|
198
|
+
values: group.values ?? [],
|
|
199
|
+
level,
|
|
200
|
+
},
|
|
201
|
+
...getCheckboxes(
|
|
202
|
+
group.values ?? [],
|
|
203
|
+
group.displayValue,
|
|
204
|
+
renderer,
|
|
205
|
+
formatter,
|
|
206
|
+
group.groups,
|
|
207
|
+
level + 1
|
|
208
|
+
),
|
|
209
|
+
])
|
|
210
|
+
.flat()
|
|
211
|
+
: values.map<DataGridFilterCheckbox>((value) => ({
|
|
212
|
+
displayValue: renderer(value),
|
|
213
|
+
title: formatter(value),
|
|
214
|
+
values: [value ?? ''],
|
|
215
|
+
level,
|
|
216
|
+
}));
|
|
207
217
|
|
|
208
218
|
export const textFilter = (key: string): DataGridFilter<'text'> => ({
|
|
209
219
|
type: 'text',
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DataGridContext,
|
|
8
8
|
DataGridContextProps,
|
|
9
9
|
DataGridFilters,
|
|
10
|
+
DataGridFooterFunction,
|
|
10
11
|
DataGridProps,
|
|
11
12
|
DataGridSort,
|
|
12
13
|
} from '../types';
|
|
@@ -26,7 +27,8 @@ import { useDataGridSettings } from './useDataGridSettings';
|
|
|
26
27
|
import { useElementSize } from '../../../../hooks';
|
|
27
28
|
|
|
28
29
|
export const useDataGrid = <R,>(
|
|
29
|
-
props: DataGridProps<R
|
|
30
|
+
props: DataGridProps<R>,
|
|
31
|
+
override?: Partial<DataGridContextProps<R>>
|
|
30
32
|
): [DataGridContextProps<R>, DataGridContext<R>] => {
|
|
31
33
|
const {
|
|
32
34
|
rows,
|
|
@@ -59,7 +61,7 @@ export const useDataGrid = <R,>(
|
|
|
59
61
|
const gridTemplateColumns = useMemo(
|
|
60
62
|
() =>
|
|
61
63
|
[
|
|
62
|
-
...(selectable ? ['var(--space-
|
|
64
|
+
...(selectable ? ['var(--space-10)'] : []),
|
|
63
65
|
...visibleColumns.map(([, col]) => `${col.width ?? 150}px`),
|
|
64
66
|
].join(' '),
|
|
65
67
|
[selectable, visibleColumns]
|
|
@@ -173,9 +175,39 @@ export const useDataGrid = <R,>(
|
|
|
173
175
|
onVisibleRowsChange?.(indexWithTolerance, lengthWithTolerance);
|
|
174
176
|
}, [indexWithTolerance, lengthWithTolerance, onVisibleRowsChange]);
|
|
175
177
|
|
|
178
|
+
/** FOOTERS */
|
|
179
|
+
const [footers, setFooters] = useState<Record<string, string>>(
|
|
180
|
+
props.initialFooters ?? {}
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const footerFunctions = useMemo(
|
|
184
|
+
() =>
|
|
185
|
+
Object.entries(footers).reduce((acc, [columnKey, footerKey]) => {
|
|
186
|
+
const column = columns[columnKey];
|
|
187
|
+
if (!column) {
|
|
188
|
+
return acc;
|
|
189
|
+
}
|
|
190
|
+
if (typeof column.footer === 'function') {
|
|
191
|
+
acc[columnKey] = column.footer;
|
|
192
|
+
} else if (
|
|
193
|
+
typeof column.footer === 'object' &&
|
|
194
|
+
typeof column.footer[footerKey] === 'function'
|
|
195
|
+
) {
|
|
196
|
+
acc[columnKey] = column.footer[footerKey];
|
|
197
|
+
}
|
|
198
|
+
return acc;
|
|
199
|
+
}, {} as Record<string, DataGridFooterFunction<R>>),
|
|
200
|
+
[columns, footers]
|
|
201
|
+
);
|
|
202
|
+
|
|
176
203
|
/** COPYING */
|
|
177
204
|
|
|
178
|
-
const { copyTable } = useDataGridCopy(
|
|
205
|
+
const { copyTable } = useDataGridCopy({
|
|
206
|
+
rows,
|
|
207
|
+
visibleColumns,
|
|
208
|
+
footerFunctions,
|
|
209
|
+
loadCopyRows,
|
|
210
|
+
});
|
|
179
211
|
|
|
180
212
|
const contextValue = useMemo<DataGridContextProps<R>>(
|
|
181
213
|
() => ({
|
|
@@ -204,28 +236,35 @@ export const useDataGrid = <R,>(
|
|
|
204
236
|
length,
|
|
205
237
|
rowKeyGetter,
|
|
206
238
|
gridTemplateColumns,
|
|
239
|
+
footers,
|
|
240
|
+
setFooters,
|
|
241
|
+
footerFunctions,
|
|
242
|
+
...override,
|
|
207
243
|
}),
|
|
208
244
|
[
|
|
209
|
-
columns,
|
|
210
|
-
copyTable,
|
|
211
|
-
editingCell,
|
|
212
|
-
filters,
|
|
213
|
-
index,
|
|
214
|
-
length,
|
|
215
|
-
onScroll,
|
|
216
245
|
props,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
246
|
+
columns,
|
|
247
|
+
visibleColumns,
|
|
248
|
+
sortedRows,
|
|
220
249
|
selectedRows,
|
|
250
|
+
selectedKeys,
|
|
251
|
+
sorts,
|
|
252
|
+
filters,
|
|
253
|
+
editingCell,
|
|
254
|
+
copyTable,
|
|
221
255
|
setColumnWidth,
|
|
222
|
-
setSettings,
|
|
223
256
|
settings,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
visibleColumns,
|
|
257
|
+
setSettings,
|
|
258
|
+
saveSettings,
|
|
227
259
|
visibleRows,
|
|
260
|
+
onScroll,
|
|
261
|
+
index,
|
|
262
|
+
length,
|
|
263
|
+
rowKeyGetter,
|
|
228
264
|
gridTemplateColumns,
|
|
265
|
+
footers,
|
|
266
|
+
footerFunctions,
|
|
267
|
+
override,
|
|
229
268
|
]
|
|
230
269
|
);
|
|
231
270
|
|
|
@@ -256,6 +295,8 @@ export const useDataGrid = <R,>(
|
|
|
256
295
|
index: 0,
|
|
257
296
|
length: 0,
|
|
258
297
|
gridTemplateColumns: '',
|
|
298
|
+
footers: {},
|
|
299
|
+
setFooters: () => {},
|
|
259
300
|
}),
|
|
260
301
|
[]
|
|
261
302
|
);
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
|
|
3
|
-
import { DataGridColumn,
|
|
3
|
+
import { DataGridColumn, DataGridContextProps } from '../types';
|
|
4
4
|
|
|
5
5
|
import { useCallback } from 'react';
|
|
6
6
|
|
|
7
|
-
export const useDataGridCopy = <R>(
|
|
8
|
-
rows
|
|
9
|
-
|
|
10
|
-
loadCopyRows
|
|
11
|
-
|
|
7
|
+
export const useDataGridCopy = <R>({
|
|
8
|
+
rows,
|
|
9
|
+
visibleColumns = [],
|
|
10
|
+
loadCopyRows,
|
|
11
|
+
footerFunctions,
|
|
12
|
+
}: Pick<
|
|
13
|
+
DataGridContextProps<R>,
|
|
14
|
+
'rows' | 'visibleColumns' | 'loadCopyRows' | 'footerFunctions'
|
|
15
|
+
>) => {
|
|
12
16
|
const generateHeadersHtml = useCallback(() => {
|
|
13
17
|
return `<tr>
|
|
14
|
-
${
|
|
18
|
+
${visibleColumns
|
|
15
19
|
.map(
|
|
16
|
-
(col) =>
|
|
20
|
+
([, col]) =>
|
|
17
21
|
`<th style="
|
|
18
22
|
text-align: left;
|
|
19
23
|
font-weight: bold;
|
|
@@ -24,29 +28,32 @@ export const useDataGridCopy = <R>(
|
|
|
24
28
|
)
|
|
25
29
|
.join('\n')}
|
|
26
30
|
</tr>`;
|
|
27
|
-
}, [
|
|
31
|
+
}, [visibleColumns]);
|
|
28
32
|
|
|
29
33
|
const generateFootersHtml = useCallback(
|
|
30
34
|
(rowsToCopy: R[]) => {
|
|
35
|
+
console.log('generate footers html');
|
|
31
36
|
return `<tr>
|
|
32
|
-
${
|
|
37
|
+
${visibleColumns
|
|
33
38
|
.map(
|
|
34
|
-
(
|
|
39
|
+
([colKey]) =>
|
|
35
40
|
`<td style="
|
|
36
41
|
font-weight: bold;
|
|
37
42
|
white-space: nowrap;
|
|
38
43
|
">
|
|
39
44
|
${
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
footerFunctions?.[colKey]?.(
|
|
46
|
+
rowsToCopy,
|
|
47
|
+
rowsToCopy,
|
|
48
|
+
[]
|
|
49
|
+
) ?? ''
|
|
43
50
|
}
|
|
44
51
|
</td>`
|
|
45
52
|
)
|
|
46
53
|
.join('\n')}
|
|
47
54
|
</tr>`;
|
|
48
55
|
},
|
|
49
|
-
[
|
|
56
|
+
[footerFunctions, visibleColumns]
|
|
50
57
|
);
|
|
51
58
|
|
|
52
59
|
const generateCellText = useCallback((col: DataGridColumn<R>, value: any) => {
|
|
@@ -76,8 +83,8 @@ export const useDataGridCopy = <R>(
|
|
|
76
83
|
.map(
|
|
77
84
|
(row) =>
|
|
78
85
|
`<tr>
|
|
79
|
-
${
|
|
80
|
-
.map((col) => {
|
|
86
|
+
${visibleColumns
|
|
87
|
+
.map(([, col]) => {
|
|
81
88
|
const value: any =
|
|
82
89
|
col.getter && row ? col.getter(row) : '';
|
|
83
90
|
return generateCellHtml(col, value);
|
|
@@ -90,24 +97,22 @@ export const useDataGridCopy = <R>(
|
|
|
90
97
|
</table>
|
|
91
98
|
`;
|
|
92
99
|
},
|
|
93
|
-
[
|
|
100
|
+
[visibleColumns, generateCellHtml, generateFootersHtml, generateHeadersHtml]
|
|
94
101
|
);
|
|
95
102
|
|
|
96
103
|
const generateHeadersText = useCallback(() => {
|
|
97
|
-
return
|
|
98
|
-
|
|
99
|
-
.join('\t');
|
|
100
|
-
}, [columns]);
|
|
104
|
+
return visibleColumns.map(([, col]) => col.name).join('\t');
|
|
105
|
+
}, [visibleColumns]);
|
|
101
106
|
|
|
102
107
|
const generateFootersText = useCallback(
|
|
103
108
|
(rowsToCopy: R[]) => {
|
|
104
|
-
return
|
|
105
|
-
.map(
|
|
106
|
-
|
|
109
|
+
return visibleColumns
|
|
110
|
+
.map(
|
|
111
|
+
([colKey]) => footerFunctions?.[colKey]?.(rowsToCopy, [], []) ?? ''
|
|
107
112
|
)
|
|
108
113
|
.join('\t');
|
|
109
114
|
},
|
|
110
|
-
[
|
|
115
|
+
[footerFunctions, visibleColumns]
|
|
111
116
|
);
|
|
112
117
|
|
|
113
118
|
const generateCopyText = useCallback(
|
|
@@ -115,8 +120,8 @@ export const useDataGridCopy = <R>(
|
|
|
115
120
|
return [
|
|
116
121
|
includeHeaders ? generateHeadersText() : '',
|
|
117
122
|
...(rowsToCopy || []).map((row) =>
|
|
118
|
-
|
|
119
|
-
.map((col) => {
|
|
123
|
+
visibleColumns
|
|
124
|
+
.map(([, col]) => {
|
|
120
125
|
const value: any = col.getter && row ? col.getter(row) : '';
|
|
121
126
|
return col.excelValue
|
|
122
127
|
? col.excelValue(value)
|
|
@@ -131,12 +136,12 @@ export const useDataGridCopy = <R>(
|
|
|
131
136
|
.filter((s) => s != null)
|
|
132
137
|
.join('\n');
|
|
133
138
|
},
|
|
134
|
-
[
|
|
139
|
+
[visibleColumns, generateFootersText, generateHeadersText]
|
|
135
140
|
);
|
|
136
141
|
|
|
137
142
|
const copyTable = useCallback(
|
|
138
143
|
async (includeHeaders = true, includeFooters = true) => {
|
|
139
|
-
const rowsToCopy = loadCopyRows
|
|
144
|
+
const rowsToCopy = await (loadCopyRows ?? (async () => rows))();
|
|
140
145
|
|
|
141
146
|
const copyHtml = generateCopyHtml(
|
|
142
147
|
rowsToCopy,
|