@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.
Files changed (68) hide show
  1. package/assets/icons/arrow-down-1-9.svg +1 -0
  2. package/assets/icons/arrow-down-big-small.svg +1 -0
  3. package/assets/icons/arrow-up-9-1.svg +1 -0
  4. package/assets/icons/arrow-up-big-small.svg +1 -0
  5. package/assets/icons/chevron-down.svg +1 -0
  6. package/assets/icons/ellipsis.svg +1 -0
  7. package/assets/icons/sigma.svg +1 -0
  8. package/assets/icons/table-footer-slash.svg +5 -0
  9. package/assets/icons/table-footer.svg +4 -0
  10. package/assets/icons/table.svg +1 -0
  11. package/assets/icons/tally.svg +1 -0
  12. package/assets/icons/x-bar.svg +4 -0
  13. package/dist/Icons.d.ts +13 -1
  14. package/dist/Icons.js +25 -1
  15. package/dist/components/data/AdvancedRequestDataGrid/index.js +3 -3
  16. package/dist/components/data/DataGrid/DataGridColumnsModal/hooks.js +2 -1
  17. package/dist/components/data/DataGrid/DataGridFilterMenu/index.js +85 -7
  18. package/dist/components/data/DataGrid/DataGridFilterMenu/styles.d.ts +3 -9
  19. package/dist/components/data/DataGrid/DataGridFilterMenu/styles.js +10 -37
  20. package/dist/components/data/DataGrid/DataGridFooter.d.ts +1 -1
  21. package/dist/components/data/DataGrid/DataGridFooter.js +35 -12
  22. package/dist/components/data/DataGrid/DataGridHeader.js +1 -1
  23. package/dist/components/data/DataGrid/DataGridHeaderCell.js +6 -22
  24. package/dist/components/data/DataGrid/helpers/columns.d.ts +1 -1
  25. package/dist/components/data/DataGrid/helpers/columns.js +71 -16
  26. package/dist/components/data/DataGrid/hooks/useDataGrid.d.ts +1 -1
  27. package/dist/components/data/DataGrid/hooks/useDataGrid.js +60 -30
  28. package/dist/components/data/DataGrid/hooks/useDataGridCopy.d.ts +2 -2
  29. package/dist/components/data/DataGrid/hooks/useDataGridCopy.js +41 -39
  30. package/dist/components/data/DataGrid/index.d.ts +4 -2
  31. package/dist/components/data/DataGrid/index.js +22 -12
  32. package/dist/components/data/DataGrid/styles.d.ts +8 -4
  33. package/dist/components/data/DataGrid/styles.js +27 -17
  34. package/dist/components/data/DataGrid/types.d.ts +8 -1
  35. package/dist/components/data/SqlRequestDataGrid/helpers/columns.d.ts +1 -1
  36. package/dist/components/data/SqlRequestDataGrid/helpers/columns.js +24 -11
  37. package/dist/components/data/SqlRequestDataGrid/index.js +105 -33
  38. package/dist/components/ui/ContextMenu/index.d.ts +11 -0
  39. package/dist/components/ui/ContextMenu/index.js +58 -0
  40. package/dist/components/ui/ContextMenu/styles.d.ts +18 -0
  41. package/dist/components/ui/ContextMenu/styles.js +56 -0
  42. package/dist/services/advancedRequests.d.ts +1 -1
  43. package/dist/services/sqlRequests.d.ts +9 -4
  44. package/dist/services/sqlRequests.js +1 -0
  45. package/package.json +1 -1
  46. package/src/Icons.tsx +24 -0
  47. package/src/components/data/AdvancedRequestDataGrid/index.tsx +3 -5
  48. package/src/components/data/DataGrid/DataGridColumnsModal/hooks.tsx +2 -1
  49. package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +180 -22
  50. package/src/components/data/DataGrid/DataGridFilterMenu/styles.ts +13 -64
  51. package/src/components/data/DataGrid/DataGridFooter.tsx +20 -22
  52. package/src/components/data/DataGrid/DataGridHeader.tsx +5 -5
  53. package/src/components/data/DataGrid/DataGridHeaderCell.tsx +3 -38
  54. package/src/components/data/DataGrid/FilterValuesScroller.tsx +33 -27
  55. package/src/components/data/DataGrid/helpers/columns.tsx +103 -8
  56. package/src/components/data/DataGrid/helpers/filters.ts +29 -19
  57. package/src/components/data/DataGrid/hooks/useDataGrid.tsx +58 -17
  58. package/src/components/data/DataGrid/hooks/useDataGridCopy.ts +35 -30
  59. package/src/components/data/DataGrid/index.tsx +22 -14
  60. package/src/components/data/DataGrid/styles.ts +50 -9
  61. package/src/components/data/DataGrid/types.ts +24 -3
  62. package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +39 -3
  63. package/src/components/data/SqlRequestDataGrid/index.tsx +116 -21
  64. package/src/components/ui/ContextMenu/index.tsx +79 -0
  65. package/src/components/ui/ContextMenu/styles.ts +119 -0
  66. package/src/services/advancedRequests.ts +1 -1
  67. package/src/services/sqlRequests.ts +16 -5
  68. package/tsconfig.tsbuildinfo +1 -1
@@ -1,9 +1,10 @@
1
1
  import * as styles from './styles';
2
2
 
3
+ import { DataGridContextProps, DataGridProps } from './types';
4
+
3
5
  import { DataGridCell } from './DataGridCell';
4
6
  import { DataGridFooter } from './DataGridFooter';
5
7
  import { DataGridHeader } from './DataGridHeader';
6
- import { DataGridProps } from './types';
7
8
  import { VirtualScroller } from './VirtualScroller';
8
9
  import { useCallback } from 'react';
9
10
  import { useDataGrid } from './hooks';
@@ -11,13 +12,18 @@ import { useDataGrid } from './hooks';
11
12
  /* eslint-disable @typescript-eslint/no-explicit-any */
12
13
  /* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
13
14
 
14
- export const DataGrid = <R,>(props: DataGridProps<R>) => {
15
+ export const DataGrid = <R,>({
16
+ contextOverride,
17
+ ...props
18
+ }: DataGridProps<R> & {
19
+ contextOverride?: Partial<DataGridContextProps<R>>;
20
+ }) => {
15
21
  const {
16
22
  className,
17
23
  // onRowDoubleClick,
18
24
  onVisibleRowsChange,
19
25
  } = props;
20
- const [contextProps, DataGridContext] = useDataGrid(props);
26
+ const [contextProps, DataGridContext] = useDataGrid(props, contextOverride);
21
27
  const {
22
28
  selectedKeys,
23
29
  setSelectedKeys,
@@ -32,17 +38,15 @@ export const DataGrid = <R,>(props: DataGridProps<R>) => {
32
38
 
33
39
  const hasFooter = Object.values(columns).some((col) => col.footer);
34
40
 
35
- const setRowSelection = useCallback(
36
- (row: R, selected: boolean) => {
37
- const key = rowKeyGetter(row);
38
- if (selected) {
39
- if (!selectedKeys.includes(key))
40
- setSelectedKeys([...selectedKeys, key]);
41
- } else {
41
+ const toggleSelection = useCallback(
42
+ (key: string) => {
43
+ if (selectedKeys.includes(key)) {
42
44
  setSelectedKeys(selectedKeys.filter((p) => p !== key));
45
+ } else {
46
+ setSelectedKeys([...selectedKeys, key]);
43
47
  }
44
48
  },
45
- [rowKeyGetter, selectedKeys, setSelectedKeys]
49
+ [selectedKeys, setSelectedKeys]
46
50
  );
47
51
 
48
52
  const rowTemplate = useCallback(
@@ -74,12 +78,15 @@ export const DataGrid = <R,>(props: DataGridProps<R>) => {
74
78
  return (
75
79
  <styles.DataGridRow key={key}>
76
80
  {!!props.selectable && (
77
- <styles.SelectionCell key="__select_checkbox__">
81
+ <styles.SelectionCell
82
+ key="__select_checkbox__"
83
+ onClick={() => toggleSelection(key)}
84
+ >
78
85
  <input
79
86
  type="checkbox"
80
87
  value={key as string}
81
88
  checked={selectedKeys.includes(key)}
82
- onChange={(e) => setRowSelection(row, e.target.checked)}
89
+ readOnly
83
90
  />
84
91
  </styles.SelectionCell>
85
92
  )}
@@ -103,7 +110,7 @@ export const DataGrid = <R,>(props: DataGridProps<R>) => {
103
110
  props,
104
111
  rowKeyGetter,
105
112
  selectedKeys,
106
- setRowSelection,
113
+ toggleSelection,
107
114
  visibleColumns,
108
115
  ]
109
116
  );
@@ -116,6 +123,7 @@ export const DataGrid = <R,>(props: DataGridProps<R>) => {
116
123
  $headerRowHeight={headerRowHeight}
117
124
  $rowHeight={rowHeight}
118
125
  $rowsCount={contextProps.sortedRows.length}
126
+ $withFooter={hasFooter}
119
127
  className={className}
120
128
  >
121
129
  <DataGridHeader context={DataGridContext} />
@@ -5,6 +5,7 @@ import { ThemeColor } from '../../../providers/ThemeProvider/types';
5
5
  export const VIRTUAL_SCROLL_TOLERANCE = 20;
6
6
  export const TOOLBAR_HEIGHT = 40;
7
7
  export const DEFAULT_HEADER_ROW_HEIGHT = 40;
8
+ export const DEFAULT_FOOTER_ROW_HEIGHT = 40;
8
9
  export const DEFAULT_ROW_HEIGHT = 32;
9
10
  export const DEFAULT_FILTER_ROW_HEIGHT = 24;
10
11
 
@@ -175,6 +176,7 @@ export const DataGridContainer = styled.div<{
175
176
  $rowHeight?: number;
176
177
  $rowsCount: number;
177
178
  $showToolsHeader?: boolean;
179
+ $withFooter?: boolean;
178
180
  }>`
179
181
  display: grid;
180
182
  width: 100%;
@@ -182,8 +184,13 @@ export const DataGridContainer = styled.div<{
182
184
  background-color: var(--color-neutral-50);
183
185
  font-size: var(--text-base);
184
186
  overflow: scroll;
185
- grid-template-rows: ${({ $headerRowHeight = DEFAULT_HEADER_ROW_HEIGHT }) =>
186
- `${TOOLBAR_HEIGHT}px ${$headerRowHeight}px auto`};
187
+ grid-template-rows: ${({
188
+ $headerRowHeight = DEFAULT_HEADER_ROW_HEIGHT,
189
+ $withFooter = false,
190
+ }) =>
191
+ `${TOOLBAR_HEIGHT}px ${$headerRowHeight}px auto ${
192
+ $withFooter ? DEFAULT_FOOTER_ROW_HEIGHT + 'px' : ''
193
+ }`};
187
194
 
188
195
  ${DataGridToolsRow} {
189
196
  height: ${TOOLBAR_HEIGHT}px;
@@ -208,21 +215,18 @@ export const DataGridContainer = styled.div<{
208
215
  `;
209
216
  DataGridContainer.displayName = 'DataGridContainer';
210
217
 
211
- export const DataGridHeaderRow = styled.div.attrs<{
218
+ type DataGridHeaderOrFooterRowProps = {
212
219
  $headerRowHeight?: number;
213
220
  $headerColor?: ThemeColor;
214
221
  $gridTemplateColumns: string;
215
- }>(({ $gridTemplateColumns }) => ({
216
- style: {
217
- gridTemplateColumns: $gridTemplateColumns,
218
- },
219
- }))`
222
+ };
223
+
224
+ const dataGridHeaderOrFooterRowCss = css<DataGridHeaderOrFooterRowProps>`
220
225
  display: grid;
221
226
  grid-template-rows: ${({ $headerRowHeight = DEFAULT_HEADER_ROW_HEIGHT }) =>
222
227
  `${$headerRowHeight}px`};
223
228
  z-index: 10;
224
229
  position: sticky;
225
- top: ${TOOLBAR_HEIGHT}px;
226
230
  align-items: center;
227
231
 
228
232
  ${({ $headerColor }) =>
@@ -236,8 +240,31 @@ export const DataGridHeaderRow = styled.div.attrs<{
236
240
  color: var(--color-neutral-900);
237
241
  `}
238
242
  `;
243
+
244
+ export const DataGridHeaderRow = styled.div.attrs<DataGridHeaderOrFooterRowProps>(
245
+ ({ $gridTemplateColumns }) => ({
246
+ style: {
247
+ gridTemplateColumns: $gridTemplateColumns,
248
+ },
249
+ })
250
+ )`
251
+ ${dataGridHeaderOrFooterRowCss}
252
+ top: ${TOOLBAR_HEIGHT}px;
253
+ `;
239
254
  DataGridHeaderRow.displayName = 'DataGridHeaderRow';
240
255
 
256
+ export const DataGridFooterRow = styled.div.attrs<DataGridHeaderOrFooterRowProps>(
257
+ ({ $gridTemplateColumns }) => ({
258
+ style: {
259
+ gridTemplateColumns: $gridTemplateColumns,
260
+ },
261
+ })
262
+ )`
263
+ ${dataGridHeaderOrFooterRowCss}
264
+ bottom: 0;
265
+ `;
266
+ DataGridFooterRow.displayName = 'DataGridFooterRow';
267
+
241
268
  export const DataGridRow = styled.div`
242
269
  display: contents;
243
270
  `;
@@ -262,6 +289,7 @@ const selectionCellStyle = css`
262
289
  justify-content: center;
263
290
  width: var(--space-8);
264
291
  padding: 0 var(--space-1);
292
+ cursor: pointer;
265
293
 
266
294
  & > input[type='checkbox'] {
267
295
  height: var(--space-4);
@@ -324,3 +352,16 @@ export const FilterValuesScrollerContainer = styled.div.attrs({
324
352
  }
325
353
  }
326
354
  `;
355
+
356
+ export const FilterValueContainer = styled.div.attrs({
357
+ className: 'FilterValueContainer',
358
+ })`
359
+ position: absolute;
360
+ display: flex;
361
+ flex-direction: row;
362
+ align-items: center;
363
+ cursor: pointer;
364
+ &:hover {
365
+ background-color: var(--color-neutral-50);
366
+ }
367
+ `;
@@ -21,13 +21,28 @@ export type DataGridCellFC = FC<{
21
21
  style?: CSSProperties;
22
22
  }>;
23
23
 
24
+ export type DataGridFooterPredefinedFunction =
25
+ | 'average'
26
+ | 'avg'
27
+ | 'count'
28
+ | 'max'
29
+ | 'min'
30
+ | 'sum';
31
+ export type DataGridFooterFunction<R> = (
32
+ allRows: R[],
33
+ filteredRows: R[],
34
+ selectedRows: R[]
35
+ ) => ReactNode;
36
+
24
37
  export type DataGridColumn<R> = {
25
38
  component?: DataGridCellFC;
26
39
  editable?: boolean;
27
40
  excelFormatter?: (value: any) => string;
28
41
  excelValue?: (value: any) => string;
29
42
  filter?: DataGridFilter;
30
- footer?: (allRows: R[], filteredRows: R[], selectedRows: R[]) => ReactNode;
43
+ footer?:
44
+ | DataGridFooterFunction<R>
45
+ | Record<string, DataGridFooterFunction<R> | null>;
31
46
  getter?: (row: R) => string | number;
32
47
  name: string;
33
48
  order?: number;
@@ -71,6 +86,8 @@ export type DataGridProps<R> = {
71
86
  filter?: boolean;
72
87
  sort?: boolean;
73
88
  initialSorts?: Record<string, DataGridSort>;
89
+ initialFooters?: Record<string, string>;
90
+ onFootersChanged?: (footers: Record<string, string>) => void;
74
91
  filterValuesLoader?: (
75
92
  columnKey: string
76
93
  ) => Promise<(string | number | null)[]>;
@@ -94,6 +111,9 @@ export type DataGridContextProps<R> = DataGridProps<R> & {
94
111
  setSorts: (sorts: Record<string, DataGridSort>) => void;
95
112
  filters?: DataGridFilters;
96
113
  setFilters: Dispatch<SetStateAction<DataGridFilters>>;
114
+ footers?: Record<string, string>;
115
+ setFooters: Dispatch<SetStateAction<Record<string, string>>>;
116
+ footerFunctions?: Record<string, DataGridFooterFunction<R>>;
97
117
  visibleColumns: DataGridColumnKeyValuePair<R>[];
98
118
  copyTable: (
99
119
  includeHeaders?: boolean,
@@ -227,7 +247,8 @@ export type DataGridFilter<T extends string = DataGridFilterType> =
227
247
 
228
248
  export type DataGridFilterGroup = {
229
249
  name: string;
230
- values?: (string | number | null)[];
250
+ displayValue: DataGridFilterValue;
251
+ values?: DataGridFilterValue[];
231
252
  groups?: DataGridFilterGroup[];
232
253
  };
233
254
 
@@ -236,6 +257,6 @@ export type DataGridFilterValue = string | number | null;
236
257
  export type DataGridFilterCheckbox = {
237
258
  displayValue: ReactNode;
238
259
  title: string;
239
- value: DataGridFilterValue;
260
+ values: DataGridFilterValue[];
240
261
  level: number;
241
262
  };
@@ -22,6 +22,7 @@ export const sqlTextColumn = <R extends Record<string, any>>(
22
22
  sortGetter: (row) => row[key] ?? '',
23
23
  filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
24
24
  ...options,
25
+ footer: (rows) => `${rows[0][key]} éléments`,
25
26
  },
26
27
  });
27
28
 
@@ -54,6 +55,7 @@ export const sqlComposedColumn = <R extends Record<string, any>>(
54
55
  },
55
56
  filterField: fields[0],
56
57
  sortField: fields[0],
58
+ footer: (rows) => `${rows[0][key]} éléments`,
57
59
  ...options,
58
60
  },
59
61
  });
@@ -69,6 +71,7 @@ export const sqlMailColumn = <R extends Record<string, any>>(
69
71
  getter: (row) => row[key] ?? '',
70
72
  sortGetter: (row) => row[key] ?? '',
71
73
  filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
74
+ footer: (rows) => `${rows[0][key]} éléments`,
72
75
  ...options,
73
76
  },
74
77
  });
@@ -84,6 +87,7 @@ export const sqlPhoneColumn = <R extends Record<string, any>>(
84
87
  getter: (row) => row[key] ?? '',
85
88
  sortGetter: (row) => row[key] ?? '',
86
89
  filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
90
+ footer: (rows) => `${rows[0][key]} éléments`,
87
91
  ...options,
88
92
  },
89
93
  });
@@ -95,10 +99,12 @@ export const sqlDateColumn = <R extends Record<string, any>>(
95
99
  ): SqlRequestDataGridColumns<R> => ({
96
100
  [key]: {
97
101
  name: title,
102
+ type: 'date',
98
103
  render: (row) => formatDate(row[key]),
99
104
  getter: (row) => row[key] ?? '',
100
105
  sortGetter: (row) => row[key] ?? '',
101
106
  filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
107
+ footer: (rows) => `${rows[0][key]} éléments`,
102
108
  ...options,
103
109
  },
104
110
  });
@@ -114,6 +120,7 @@ export const sqlMonthColumn = <R extends Record<string, any>>(
114
120
  getter: (row) => row[key] ?? '',
115
121
  sortGetter: (row) => row[key] ?? '',
116
122
  filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
123
+ footer: (rows) => `${rows[0][key]} éléments`,
117
124
  ...options,
118
125
  },
119
126
  });
@@ -130,7 +137,18 @@ export const sqlNumberColumn = <R extends Record<string, any>>(
130
137
  excelFormatter: () => '#',
131
138
  getter: (row) => row[key] ?? '',
132
139
  sortGetter: (row) => row[key] ?? '',
133
- filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
140
+ filter: {
141
+ ...numberFilter(key),
142
+ getter: (value) => value[key] ?? 0,
143
+ renderer: (value) => formatNumber(value, decimals) ?? '',
144
+ },
145
+ footer: {
146
+ sum: null,
147
+ avg: null,
148
+ count: null,
149
+ max: null,
150
+ min: null,
151
+ },
134
152
  ...options,
135
153
  },
136
154
  });
@@ -143,11 +161,23 @@ export const sqlMoneyColumn = <R extends Record<string, any>>(
143
161
  ): SqlRequestDataGridColumns<R> => ({
144
162
  [key]: {
145
163
  name: title,
164
+ type: 'number',
146
165
  render: (row) => formatMoney(row[key], decimals) ?? '',
147
166
  excelFormatter: () => '#0.00',
148
167
  getter: (row) => row[key] ?? '',
149
168
  sortGetter: (row) => row[key] ?? '',
150
- filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
169
+ filter: {
170
+ ...numberFilter(key),
171
+ getter: (value) => value[key] ?? 0,
172
+ renderer: (value) => formatMoney(value, decimals) ?? '',
173
+ },
174
+ footer: {
175
+ sum: null,
176
+ avg: null,
177
+ count: null,
178
+ max: null,
179
+ min: null,
180
+ },
151
181
  ...options,
152
182
  },
153
183
  });
@@ -155,6 +185,7 @@ export const sqlMoneyColumn = <R extends Record<string, any>>(
155
185
  export const sqlPercentageColumn = <R extends Record<string, any>>(
156
186
  key: string,
157
187
  title: string,
188
+ decimals = 2,
158
189
  options?: Partial<SqlRequestDataGridColumn<R>>
159
190
  ): SqlRequestDataGridColumns<R> => ({
160
191
  [key]: {
@@ -163,7 +194,11 @@ export const sqlPercentageColumn = <R extends Record<string, any>>(
163
194
  excelFormatter: () => '#0.00',
164
195
  getter: (row) => row[key] ?? '',
165
196
  sortGetter: (row) => row[key] ?? '',
166
- filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
197
+ filter: {
198
+ ...numberFilter(key),
199
+ getter: (value) => value[key] ?? 0,
200
+ renderer: (value) => formatPercentage(value, decimals) ?? '',
201
+ },
167
202
  ...options,
168
203
  },
169
204
  });
@@ -184,6 +219,7 @@ export const sqlCheckboxColumn = <R extends Record<string, any>>(
184
219
  getter: (row) => row[key] ?? '',
185
220
  sortGetter: (row) => row[key] ?? '',
186
221
  filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
222
+ footer: (rows) => `${rows[0][key]} éléments`,
187
223
  ...options,
188
224
  },
189
225
  });
@@ -1,9 +1,15 @@
1
1
  import {
2
2
  ConditionDTO,
3
3
  OrderByDTO,
4
+ SqlRequestFooterFunction,
5
+ SqlRequestRow,
4
6
  useSqlRequestHandler,
5
7
  } from '../../../services/sqlRequests';
6
- import { DataGridFilters, DataGridSort } from '../DataGrid/types';
8
+ import {
9
+ DataGridFilters,
10
+ DataGridFooterFunction,
11
+ DataGridSort,
12
+ } from '../DataGrid/types';
7
13
  import _, { debounce } from 'lodash';
8
14
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
9
15
 
@@ -20,8 +26,10 @@ export const SqlRequestDataGrid = <R,>({
20
26
  const [rows, setRows] = useState<R[]>([]);
21
27
  const [start, setStart] = useState(0);
22
28
  const [length, setLength] = useState(50);
23
- const [total, setTotal] = useState(-1);
24
- const [sqlRequest, sqlIdRequest] = useSqlRequestHandler<R>(props.type);
29
+ const [count, setCount] = useState(-1);
30
+ const [sqlRequest, sqlIdRequest, sqlPartialRequest] = useSqlRequestHandler<R>(
31
+ props.type
32
+ );
25
33
 
26
34
  const [conditions, setConditions] = useState<Record<string, ConditionDTO>>(
27
35
  {}
@@ -30,6 +38,7 @@ export const SqlRequestDataGrid = <R,>({
30
38
  Object.entries(props.initialSorts ?? {}).map(
31
39
  ([columnKey, direction]): OrderByDTO => ({
32
40
  field: props.columns[columnKey].field?.fieldAlias ?? columnKey,
41
+ type: props.columns[columnKey].type ?? 'text',
33
42
  direction: direction.toUpperCase() as 'ASC' | 'DESC',
34
43
  })
35
44
  )
@@ -47,17 +56,24 @@ export const SqlRequestDataGrid = <R,>({
47
56
  ],
48
57
  [props.columns, props.hiddenColumns]
49
58
  );
59
+ const columnTypes = useMemo(
60
+ () =>
61
+ visibleColumnsKeys.map((key) =>
62
+ String(props.columns[key]?.type ?? 'text')
63
+ ),
64
+ [visibleColumnsKeys, props.columns]
65
+ );
50
66
 
51
67
  const refresh = useCallback(() => {
52
68
  setRows([]);
53
69
  setStart(0);
54
70
  setLength(50);
55
- setTotal(-1);
71
+ setCount(-1);
56
72
  }, []);
57
73
 
58
74
  const onFiltersChanged = useCallback((filters: DataGridFilters) => {
59
75
  const newConditions = convertSqlFiltersToConditions(filters);
60
- setTotal(-1);
76
+ setCount(-1);
61
77
  setConditions(newConditions);
62
78
  }, []);
63
79
 
@@ -85,22 +101,25 @@ export const SqlRequestDataGrid = <R,>({
85
101
  orderBy: OrderByDTO[] = [],
86
102
  start = 0,
87
103
  length = 100,
88
- getTotal = false
104
+ getCount = false
89
105
  ) => {
90
106
  sqlRequest({
91
107
  columns: columns.includes('Id') ? columns : [...columns, 'Id'],
92
108
  returnColumns: returnColumns.includes('Id')
93
109
  ? returnColumns
94
110
  : [...returnColumns, 'Id'],
111
+ columnTypes: columnTypes.includes('Id')
112
+ ? columnTypes
113
+ : [...columnTypes, 'Id'],
95
114
  conditions,
96
115
  orderBy,
97
116
  start,
98
117
  length,
99
- getTotal,
118
+ getCount,
100
119
  }).then((response) => {
101
- if (getTotal) {
102
- currentRows.current = Array(response.total).fill(null);
103
- if (getTotal) setTotal(response.total ?? 0);
120
+ if (getCount) {
121
+ currentRows.current = Array(response.count).fill(null);
122
+ if (getCount) setCount(response.count ?? 0);
104
123
  }
105
124
  const parsedRows = props.parser
106
125
  ? response.data.map(props.parser)
@@ -122,11 +141,10 @@ export const SqlRequestDataGrid = <R,>({
122
141
  return sqlRequest({
123
142
  columns: columnsKeys,
124
143
  returnColumns: [columnKey],
144
+ columnTypes: [props.columns[columnKey].type ?? 'text'],
125
145
  conditions: [
126
146
  ...(props.conditions ?? []),
127
- ...Object.values(
128
- _.pickBy(conditions, (condition, key) => key !== columnKey)
129
- ),
147
+ ...Object.values(_.pickBy(conditions, (_, key) => key !== columnKey)),
130
148
  ].filter((condition) => condition.field !== columnKey),
131
149
  orderBy: [
132
150
  {
@@ -135,10 +153,11 @@ export const SqlRequestDataGrid = <R,>({
135
153
  props.columns[columnKey].field?.fieldAlias ??
136
154
  props.columns[columnKey].field?.fieldName ??
137
155
  columnKey,
156
+ type: props.columns[columnKey].type ?? 'text',
138
157
  direction: 'ASC',
139
158
  },
140
159
  ],
141
- getTotal: false,
160
+ getCount: false,
142
161
  unique: true,
143
162
  }).then((response) =>
144
163
  response.data.map(
@@ -158,7 +177,7 @@ export const SqlRequestDataGrid = <R,>({
158
177
  orderBy,
159
178
  start,
160
179
  length,
161
- total < 0
180
+ count < 0
162
181
  ),
163
182
  [
164
183
  props.columns,
@@ -166,7 +185,7 @@ export const SqlRequestDataGrid = <R,>({
166
185
  orderBy,
167
186
  start,
168
187
  length,
169
- total,
188
+ count,
170
189
  props.conditions,
171
190
  columnsKeys,
172
191
  visibleColumnsKeys,
@@ -178,13 +197,14 @@ export const SqlRequestDataGrid = <R,>({
178
197
  sqlRequest({
179
198
  columns: columnsKeys,
180
199
  returnColumns: visibleColumnsKeys,
200
+ columnTypes,
181
201
  conditions: [
182
202
  ...(props.conditions ?? []),
183
203
  ...(Object.values(conditions) ?? []),
184
204
  ],
185
205
  orderBy,
186
206
  start: 0,
187
- length: total,
207
+ length: count,
188
208
  }).then((response) =>
189
209
  props.parser ? response.data.map(props.parser) : (response.data as R[])
190
210
  ),
@@ -192,28 +212,32 @@ export const SqlRequestDataGrid = <R,>({
192
212
  sqlRequest,
193
213
  columnsKeys,
194
214
  visibleColumnsKeys,
215
+ columnTypes,
195
216
  props.conditions,
196
217
  props.parser,
197
218
  conditions,
198
219
  orderBy,
199
- total,
220
+ count,
200
221
  ]
201
222
  );
202
223
 
203
224
  const loadAllIds = useCallback(
204
225
  () =>
205
226
  sqlIdRequest({
206
- columns: columnsKeys,
227
+ columns: columnsKeys.includes('Id')
228
+ ? columnsKeys
229
+ : [...columnsKeys, 'Id'],
207
230
  returnColumns: ['Id'],
231
+ columnTypes: ['text'],
208
232
  conditions: [
209
233
  ...(props.conditions ?? []),
210
234
  ...(Object.values(conditions) ?? []),
211
235
  ],
212
236
  orderBy,
213
237
  start: 0,
214
- length: total,
238
+ length: count,
215
239
  }).then((response) => response.data.map((row) => row['Id'])),
216
- [columnsKeys, conditions, orderBy, props.conditions, sqlIdRequest, total]
240
+ [columnsKeys, conditions, orderBy, props.conditions, sqlIdRequest, count]
217
241
  );
218
242
 
219
243
  const onVisibleRowsChanged = useCallback(
@@ -233,6 +257,76 @@ export const SqlRequestDataGrid = <R,>({
233
257
  [onSelectionChangeFromProps]
234
258
  );
235
259
 
260
+ /** FOOTERS */
261
+ const [footers, setFooters] = useState<Record<string, string>>(
262
+ props.initialFooters ?? {}
263
+ );
264
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
265
+ const [footerData, setFooterData] = useState<SqlRequestRow<any>>({});
266
+
267
+ const loadFooters = useCallback(() => {
268
+ if (Object.keys(footers).length === 0) {
269
+ setFooterData({});
270
+ } else {
271
+ sqlPartialRequest({
272
+ columns: columnsKeys.includes('Id')
273
+ ? columnsKeys
274
+ : [...columnsKeys, 'Id'],
275
+ returnColumns: [],
276
+ columnTypes: [],
277
+ totalColumns: footers as Record<string, SqlRequestFooterFunction>,
278
+ conditions: [
279
+ ...(props.conditions ?? []),
280
+ ...(Object.values(conditions) ?? []),
281
+ ],
282
+ orderBy,
283
+ }).then((response) => setFooterData(response.totals ?? {}));
284
+ }
285
+ }, [
286
+ columnsKeys,
287
+ conditions,
288
+ footers,
289
+ orderBy,
290
+ props.conditions,
291
+ sqlPartialRequest,
292
+ ]);
293
+
294
+ useEffect(() => {
295
+ loadFooters();
296
+ }, [loadFooters]);
297
+
298
+ const footerFunctions = useMemo(
299
+ () =>
300
+ !footerData
301
+ ? {}
302
+ : Object.entries(footers).reduce((acc, [columnKey, footerKey]) => {
303
+ const column = props.columns[columnKey];
304
+ const footerFunc =
305
+ typeof column?.footer === 'function'
306
+ ? column.footer
307
+ : column?.footer?.[footerKey];
308
+ const render = footerFunc
309
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
310
+ (data: any) => footerFunc([data], [], [])
311
+ : column?.render ?? _.identity;
312
+ if (!column) {
313
+ return acc;
314
+ }
315
+ acc[columnKey] = () => render(footerData, column);
316
+ return acc;
317
+ }, {} as Record<string, DataGridFooterFunction<R>>),
318
+ [footerData, footers, props.columns]
319
+ );
320
+
321
+ const contextOverride = useMemo(
322
+ () => ({
323
+ footers,
324
+ setFooters,
325
+ footerFunctions,
326
+ }),
327
+ [footers, setFooters, footerFunctions]
328
+ );
329
+
236
330
  return (
237
331
  <DataGrid
238
332
  onVisibleRowsChange={onVisibleRowsChanged}
@@ -246,6 +340,7 @@ export const SqlRequestDataGrid = <R,>({
246
340
  refresh={refresh}
247
341
  onSelectionChange={onSelectionChange}
248
342
  getAllIds={loadAllIds}
343
+ contextOverride={contextOverride}
249
344
  {...props}
250
345
  />
251
346
  );