@addev-be/ui 0.14.1 → 0.14.2

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 (40) hide show
  1. package/assets/icons/floppy-disk.svg +1 -0
  2. package/package.json +2 -1
  3. package/src/Icons.tsx +2 -0
  4. package/src/components/data/DataGrid/DataGridCell.tsx +3 -3
  5. package/src/components/data/DataGrid/DataGridColumnsModal/helpers.ts +7 -12
  6. package/src/components/data/DataGrid/DataGridColumnsModal/hooks.tsx +2 -2
  7. package/src/components/data/DataGrid/DataGridColumnsModal/index.tsx +31 -30
  8. package/src/components/data/DataGrid/DataGridEditableCell/CheckboxEditableCell.tsx +38 -0
  9. package/src/components/data/DataGrid/DataGridEditableCell/DateEditableCell.tsx +39 -0
  10. package/src/components/data/DataGrid/DataGridEditableCell/NumberEditableCell.tsx +68 -0
  11. package/src/components/data/DataGrid/DataGridEditableCell/TextEditableCell.tsx +38 -0
  12. package/src/components/data/DataGrid/DataGridEditableCell/index.tsx +60 -0
  13. package/src/components/data/DataGrid/DataGridEditableCell/types.ts +14 -0
  14. package/src/components/data/DataGrid/DataGridFilterMenu/hooks.tsx +13 -10
  15. package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +27 -29
  16. package/src/components/data/DataGrid/DataGridFooter.tsx +3 -3
  17. package/src/components/data/DataGrid/DataGridHeader.tsx +52 -7
  18. package/src/components/data/DataGrid/DataGridHeaderCell.tsx +16 -2
  19. package/src/components/data/DataGrid/DataGridRowTemplate.tsx +23 -16
  20. package/src/components/data/DataGrid/helpers/columns.tsx +238 -236
  21. package/src/components/data/DataGrid/hooks/index.ts +6 -7
  22. package/src/components/data/DataGrid/hooks/useDataGrid.tsx +89 -16
  23. package/src/components/data/DataGrid/hooks/useDataGridChangedRows.ts +56 -0
  24. package/src/components/data/DataGrid/hooks/useDataGridCopy.ts +18 -19
  25. package/src/components/data/DataGrid/styles.ts +56 -1
  26. package/src/components/data/DataGrid/types.ts +69 -17
  27. package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +240 -216
  28. package/src/components/data/SqlRequestDataGrid/index.tsx +58 -43
  29. package/src/components/data/SqlRequestDataGrid/types.ts +21 -6
  30. package/src/components/data/SqlRequestForeignList/index.tsx +157 -0
  31. package/src/components/data/SqlRequestForeignList/styles.ts +38 -0
  32. package/src/components/data/SqlRequestGrid/filters/FiltersSidebar.tsx +8 -4
  33. package/src/components/data/SqlRequestGrid/index.tsx +24 -18
  34. package/src/components/data/SqlRequestGrid/types.ts +25 -3
  35. package/src/components/data/index.ts +2 -0
  36. package/src/helpers/numbers.ts +37 -0
  37. package/src/services/index.ts +1 -0
  38. package/src/services/updateSqlRequests.ts +34 -0
  39. package/src/components/data/DataGrid/DataGridEditableCell.tsx +0 -43
  40. package/src/components/data/SqlRequestDataGrid/index.ts +0 -1
@@ -23,6 +23,7 @@ import {
23
23
  XBarIcon,
24
24
  } from '../../../../Icons';
25
25
  import {
26
+ DataGridColumnWithFilter,
26
27
  DataGridContext,
27
28
  DataGridFilterType,
28
29
  DataGridFilterValue,
@@ -50,8 +51,7 @@ import { MenuContainer } from '../../../ui/ContextMenu/styles';
50
51
  import { useFilterModal } from './hooks';
51
52
 
52
53
  type FilterValuesProps<R> = {
53
- columnKey: string;
54
- columnIndex: number;
54
+ column: DataGridColumnWithFilter<R>;
55
55
  context: DataGridContext<R>;
56
56
  onClose?: () => void;
57
57
  contextMenu?: boolean;
@@ -87,24 +87,22 @@ const footerFunctionsIcons: Record<DataGridFooterPredefinedFunction, IconFC> = {
87
87
  };
88
88
 
89
89
  export const DataGridFilterMenu = <R,>({
90
- columnKey,
90
+ column,
91
91
  context,
92
92
  onClose,
93
93
  contextMenu = true,
94
94
  showTotalButton = true,
95
95
  }: FilterValuesProps<R>) => {
96
- const { openModal, modal } = useFilterModal({ columnKey, context, onClose });
96
+ const { openModal, modal } = useFilterModal({ column, context, onClose });
97
97
  const {
98
98
  filters = {},
99
99
  footers = {},
100
100
  rows,
101
- columns,
102
101
  setFilters,
103
102
  filterValuesLoader,
104
103
  setSorts,
105
104
  setFooters,
106
105
  } = useContext(context);
107
- const column = columns[columnKey] ?? {};
108
106
  const textFilterInputRef = useRef<HTMLInputElement>(null);
109
107
  const [textFilter, setTextFilter] = useState('');
110
108
 
@@ -114,12 +112,12 @@ export const DataGridFilterMenu = <R,>({
114
112
 
115
113
  useEffect(() => {
116
114
  if (filterValuesLoader) {
117
- filterValuesLoader(columnKey).then((values) => {
115
+ filterValuesLoader(column.key).then((values) => {
118
116
  setAvailableValues(() => values);
119
117
  });
120
118
  } else {
121
119
  const otherFilters = Object.entries(filters)
122
- .filter(([key]) => key !== columnKey)
120
+ .filter(([key]) => key !== column.key)
123
121
  .map(([, filter]) => filter);
124
122
  const availableRows = applyFilters(rows, otherFilters);
125
123
  const values = availableRows.map((row) => column.filter!.getter(row));
@@ -131,34 +129,34 @@ export const DataGridFilterMenu = <R,>({
131
129
  )
132
130
  );
133
131
  }
134
- }, [column.filter, columnKey, filterValuesLoader, filters, rows]);
132
+ }, [column.filter, column.key, filterValuesLoader, filters, rows]);
135
133
 
136
134
  const selectedValues = useMemo(
137
- () => filters?.[columnKey]?.values ?? [],
138
- [columnKey, filters]
135
+ () => filters?.[column.key]?.values ?? [],
136
+ [column.key, filters]
139
137
  );
140
138
 
141
139
  const clearFilter = useCallback(() => {
142
140
  const newFilters = { ...filters };
143
- delete newFilters[columnKey];
141
+ delete newFilters[column.key];
144
142
  setFilters(newFilters);
145
143
  onClose?.();
146
- }, [filters, columnKey, setFilters, onClose]);
144
+ }, [filters, column.key, setFilters, onClose]);
147
145
 
148
146
  const setValuesChecked = useCallback(
149
147
  (values: any[], checked?: boolean) => {
150
148
  setFilters((prevFilters) => {
151
149
  const newValues = checked
152
- ? [...(prevFilters[columnKey]?.values ?? []), ...values]
153
- : without(prevFilters[columnKey]?.values ?? [], ...values);
150
+ ? [...(prevFilters[column.key]?.values ?? []), ...values]
151
+ : without(prevFilters[column.key]?.values ?? [], ...values);
154
152
  const newFilters = {
155
153
  ...prevFilters,
156
154
  };
157
155
  if (newValues.length === 0) {
158
- delete newFilters[columnKey];
156
+ delete newFilters[column.key];
159
157
  } else {
160
- newFilters[columnKey] = {
161
- ...(prevFilters[columnKey] ?? column.filter),
158
+ newFilters[column.key] = {
159
+ ...(prevFilters[column.key] ?? column.filter),
162
160
  operator: 'inArray',
163
161
  values: newValues,
164
162
  };
@@ -166,7 +164,7 @@ export const DataGridFilterMenu = <R,>({
166
164
  return newFilters;
167
165
  });
168
166
  },
169
- [setFilters, columnKey, column.filter]
167
+ [setFilters, column.key, column.filter]
170
168
  );
171
169
 
172
170
  const toggleValues = useCallback(
@@ -228,40 +226,40 @@ export const DataGridFilterMenu = <R,>({
228
226
  ]);
229
227
 
230
228
  const onSortAscClicked = useCallback(() => {
231
- setSorts({ [columnKey]: 'asc' });
229
+ setSorts({ [column.key]: 'asc' });
232
230
  onClose?.();
233
- }, [columnKey, onClose, setSorts]);
231
+ }, [column.key, onClose, setSorts]);
234
232
  const onSortDescClicked = useCallback(() => {
235
- setSorts({ [columnKey]: 'desc' });
233
+ setSorts({ [column.key]: 'desc' });
236
234
  onClose?.();
237
- }, [columnKey, onClose, setSorts]);
235
+ }, [column.key, onClose, setSorts]);
238
236
 
239
- const hasFilters = filters[columnKey]?.values.length > 0;
237
+ const hasFilters = filters[column.key]?.values.length > 0;
240
238
  const [[sortAscText, SortAscIcon], [sortDescText, SortDescIcon]] = [
241
239
  sortAsc[column.filter?.type ?? 'text'],
242
240
  sortDesc[column.filter?.type ?? 'text'],
243
241
  ];
244
242
 
245
243
  const isFooterVisible =
246
- columnKey in footers && footers[columnKey] !== undefined;
244
+ column.key in footers && footers[column.key] !== undefined;
247
245
  const showFooter = useCallback(
248
246
  (key: string) => {
249
247
  setFooters((prevFooters) => ({
250
248
  ...prevFooters,
251
- [columnKey]: key,
249
+ [column.key]: key,
252
250
  }));
253
251
  onClose?.();
254
252
  },
255
- [columnKey, onClose, setFooters]
253
+ [column.key, onClose, setFooters]
256
254
  );
257
255
  const hideFooter = useCallback(() => {
258
256
  setFooters((prevFooters) => {
259
257
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
260
- const { [columnKey]: _, ...newFooters } = prevFooters;
258
+ const { [column.key]: _, ...newFooters } = prevFooters;
261
259
  return newFooters;
262
260
  });
263
261
  onClose?.();
264
- }, [columnKey, onClose, setFooters]);
262
+ }, [column.key, onClose, setFooters]);
265
263
 
266
264
  const content = (
267
265
  <>
@@ -31,13 +31,13 @@ export const DataGridFooter = <R,>({
31
31
  return (
32
32
  <styles.DataGridFooterRow $gridTemplateColumns={gridTemplateColumns}>
33
33
  {!!selectable && <styles.HeaderSelectionCell />}
34
- {visibleColumns.map(([key, col]) => (
34
+ {visibleColumns.map((col) => (
35
35
  <styles.DataGridHeaderCellContainer
36
- key={key}
36
+ key={col.key}
37
37
  style={{ width: (col.width ?? DEFAULT_COLUMN_WIDTH) + 'px' }}
38
38
  $headerColor={col.color ?? headerColor}
39
39
  >
40
- {footerFunctions?.[key]?.(rows, sortedRows, selectedRows)}
40
+ {footerFunctions?.[col.key]?.(rows, sortedRows, selectedRows)}
41
41
  </styles.DataGridHeaderCellContainer>
42
42
  ))}
43
43
  </styles.DataGridFooterRow>
@@ -7,6 +7,8 @@ import {
7
7
  ArrowsRotateIcon,
8
8
  CopyIcon,
9
9
  FilterSlashIcon,
10
+ FloppyDiskIcon,
11
+ PlusIcon,
10
12
  TableColumnsIcon,
11
13
  } from '../../../Icons';
12
14
  import { useCallback, useState } from 'react';
@@ -38,6 +40,13 @@ export const DataGridHeader = <R,>({
38
40
  rowKeyGetter,
39
41
  gridTemplateColumns,
40
42
  getAllIds,
43
+ editable,
44
+ onSaveClicked,
45
+ onAddClicked,
46
+ addedRows,
47
+ updatedRows,
48
+ addRow,
49
+ clearChangedRows,
41
50
  } = useDataGridContext(context);
42
51
  const [visibleFilter, setVisibleFilter] = useState<string | undefined>();
43
52
 
@@ -67,16 +76,52 @@ export const DataGridHeader = <R,>({
67
76
  copyTable().then(() => setIsLoadingVisible(false));
68
77
  }, [copyTable]);
69
78
 
79
+ const save = useCallback(async () => {
80
+ if (
81
+ Object.keys(addedRows).length + Object.keys(updatedRows).length > 0 &&
82
+ onSaveClicked
83
+ ) {
84
+ const savedIds = await onSaveClicked(addedRows, updatedRows);
85
+ clearChangedRows(savedIds);
86
+ }
87
+ }, [addedRows, clearChangedRows, onSaveClicked, updatedRows]);
88
+
89
+ const add = useCallback(async () => {
90
+ if (onAddClicked) {
91
+ const row = await onAddClicked();
92
+ const key = rowKeyGetter(row);
93
+ addRow(key, row);
94
+ }
95
+ }, [addRow, onAddClicked, rowKeyGetter]);
96
+
97
+ const onRefreshClicked = useCallback(() => {
98
+ refresh?.();
99
+ clearChangedRows();
100
+ setSelectedKeys([]);
101
+ }, [clearChangedRows, refresh, setSelectedKeys]);
102
+
70
103
  const toolsRow = (
71
104
  <styles.DataGridToolsRow>
72
105
  <styles.DataGridToolsRowButtonsContainer>
73
106
  <Loading visible={isLoadingVisible} />
74
- {refresh && (
75
- <Button size="small" onClick={refresh}>
107
+ {editable && onSaveClicked && (
108
+ <Button size="small" $color="primary" onClick={save}>
109
+ <FloppyDiskIcon />
110
+ Enregistrer
111
+ </Button>
112
+ )}
113
+ {editable && onAddClicked && (
114
+ <Button size="small" $color="success" onClick={add}>
115
+ <PlusIcon />
116
+ Ajouter
117
+ </Button>
118
+ )}
119
+ {
120
+ <Button size="small" onClick={onRefreshClicked}>
76
121
  <ArrowsRotateIcon />
77
122
  Rafraîchir
78
123
  </Button>
79
- )}
124
+ }
80
125
  <Button $color="emerald" size="small" onClick={runCopyTable}>
81
126
  <CopyIcon />
82
127
  Copier la table
@@ -111,14 +156,14 @@ export const DataGridHeader = <R,>({
111
156
  <IndeterminateCheckbox checked={checkboxStatus} readOnly />
112
157
  </styles.HeaderSelectionCell>
113
158
  )}
114
- {visibleColumns.map(([key, col], index) => (
159
+ {visibleColumns.map((col, index) => (
115
160
  <DataGridHeaderCell
116
- key={key}
117
- columnKey={key}
161
+ key={col.key}
162
+ columnKey={col.key}
118
163
  column={col}
119
164
  context={context}
120
165
  columnIndex={index}
121
- isFilterOpen={visibleFilter === key}
166
+ isFilterOpen={visibleFilter === col.key}
122
167
  onFilterButtonClicked={onFilterButtonClicked}
123
168
  />
124
169
  ))}
@@ -33,7 +33,12 @@ export const DataGridHeaderCell = <R,>({
33
33
 
34
34
  const [isFilterDropdownVisible, setIsFilterDropdownVisible] = useState(false);
35
35
  const filterDropdown = useMemo(() => {
36
- if (!isFilterDropdownVisible || !filterButtonRef.current || !columnKey) {
36
+ if (
37
+ !isFilterDropdownVisible ||
38
+ !filterButtonRef.current ||
39
+ !columnKey ||
40
+ !column.filter
41
+ ) {
37
42
  return null;
38
43
  }
39
44
  const filterButtonRect = getElementScreenRect(filterButtonRef.current);
@@ -48,6 +53,7 @@ export const DataGridHeaderCell = <R,>({
48
53
  $autoPositionX
49
54
  >
50
55
  <DataGridFilterMenu
56
+ column={column}
51
57
  columnKey={columnKey}
52
58
  columnIndex={columnIndex}
53
59
  context={context}
@@ -56,6 +62,7 @@ export const DataGridHeaderCell = <R,>({
56
62
  </Dropdown>
57
63
  );
58
64
  }, [
65
+ column,
59
66
  columnIndex,
60
67
  columnKey,
61
68
  context,
@@ -76,7 +83,14 @@ export const DataGridHeaderCell = <R,>({
76
83
  $isResizing={isResizing}
77
84
  >
78
85
  {filterDropdown}
79
- <span>{column.name}</span>
86
+
87
+ {typeof column.name === 'string' ? (
88
+ <span>{column.name}</span>
89
+ ) : (
90
+ <styles.DataGridHeaderTextContainer>
91
+ {column.name}
92
+ </styles.DataGridHeaderTextContainer>
93
+ )}
80
94
  {!!column.filter && (
81
95
  <IconButton
82
96
  size="small"
@@ -7,15 +7,20 @@ import { useContext } from 'react';
7
7
 
8
8
  export const DataGridRowTemplate = <R,>({
9
9
  item,
10
- index,
10
+ index: rowIndex,
11
11
  context,
12
12
  }: VirtualScrollerTemplateProps<R, DataGridRowTemplateProps<R>>) => {
13
- const { visibleColumns, rowKeyGetter, toggleSelection, ...props } =
14
- useContext(context);
13
+ const {
14
+ visibleColumns,
15
+ rowKeyGetter,
16
+ toggleSelection,
17
+ addedRows: editedRows,
18
+ ...props
19
+ } = useContext(context);
15
20
 
16
21
  if (!item) {
17
22
  return (
18
- <styles.DataGridRow key={`loading-row-${index}`}>
23
+ <styles.DataGridRow key={`loading-row-${rowIndex}`}>
19
24
  {!!props.selectable && (
20
25
  <styles.LoadingCell className="animate-pulse">
21
26
  <div />
@@ -24,7 +29,7 @@ export const DataGridRowTemplate = <R,>({
24
29
  {visibleColumns.map((_, colIndex) => (
25
30
  <styles.LoadingCell
26
31
  className="animate-pulse"
27
- key={`loading-${index}-${colIndex}`}
32
+ key={`loading-${rowIndex}-${colIndex}`}
28
33
  >
29
34
  <div />
30
35
  </styles.LoadingCell>
@@ -32,37 +37,39 @@ export const DataGridRowTemplate = <R,>({
32
37
  </styles.DataGridRow>
33
38
  );
34
39
  }
35
- const key = rowKeyGetter(item);
36
- const selected = props.selectedKeys.includes(key);
40
+ const rowKey = rowKeyGetter(item);
41
+ const selected = props.selectedKeys.includes(rowKey);
37
42
  const { className, style } = props.rowClassNameGetter?.(item) ?? {
38
43
  className: '',
39
44
  style: undefined,
40
45
  };
46
+ const isEdited = rowKey in editedRows;
47
+
41
48
  return (
42
- <styles.DataGridRow key={key}>
49
+ <styles.DataGridRow key={rowKey} $edited={isEdited}>
43
50
  {!!props.selectable && (
44
51
  <styles.SelectionCell
45
52
  key="__select_checkbox__"
46
- onClick={() => toggleSelection(key)}
53
+ onClick={() => toggleSelection(rowKey)}
47
54
  >
48
55
  <input
49
56
  type="checkbox"
50
- value={key as string}
57
+ value={rowKey as string}
51
58
  checked={selected}
52
59
  readOnly
53
60
  />
54
61
  </styles.SelectionCell>
55
62
  )}
56
- {visibleColumns.map(([key, col], index) => (
63
+ {visibleColumns.map((col, colIndex) => (
57
64
  <DataGridCell
58
- key={`loading-${index}-${index}`}
59
- {...(index === 0 ? { className, style } : {})}
65
+ key={`loading-${colIndex}-${colIndex}`}
66
+ {...(colIndex === 0 ? { className, style } : {})}
60
67
  row={item}
61
- rowIndex={index}
68
+ rowIndex={rowIndex}
62
69
  column={col}
63
- columnIndex={index}
70
+ columnIndex={colIndex}
64
71
  context={context}
65
- columnKey={key}
72
+ columnKey={col.key}
66
73
  color={col.color}
67
74
  />
68
75
  ))}