@bsol-oss/react-datatable5 12.0.0-beta.7 → 12.0.0-beta.71
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 +192 -0
- package/dist/index.d.ts +282 -83
- package/dist/index.js +1637 -475
- package/dist/index.mjs +1645 -483
- package/dist/types/components/DataTable/DataTable.d.ts +3 -1
- package/dist/types/components/DataTable/DataTableServer.d.ts +6 -4
- package/dist/types/components/DataTable/DefaultTable.d.ts +6 -9
- package/dist/types/components/DataTable/context/DataTableContext.d.ts +21 -3
- package/dist/types/components/DataTable/context/useDataTableContext.d.ts +2 -2
- package/dist/types/components/DataTable/controls/ReloadButton.d.ts +1 -2
- package/dist/types/components/DataTable/controls/ResetFilteringButton.d.ts +1 -4
- package/dist/types/components/DataTable/controls/ResetSelectionButton.d.ts +1 -4
- package/dist/types/components/DataTable/controls/ResetSortingButton.d.ts +1 -4
- package/dist/types/components/DataTable/controls/TableControls.d.ts +10 -2
- package/dist/types/components/DataTable/display/TableBody.d.ts +1 -2
- package/dist/types/components/DataTable/display/TableCardContainer.d.ts +6 -3
- package/dist/types/components/DataTable/display/TableDataDisplay.d.ts +6 -1
- package/dist/types/components/DataTable/display/TableFooter.d.ts +1 -5
- package/dist/types/components/DataTable/display/TableHeader.d.ts +46 -8
- package/dist/types/components/DataTable/useDataTableServer.d.ts +55 -3
- package/dist/types/components/DatePicker/DatePicker.d.ts +23 -0
- package/dist/types/components/DatePicker/DateTimePicker.d.ts +11 -0
- package/dist/types/components/DatePicker/DurationPicker.d.ts +12 -0
- package/dist/types/components/DatePicker/IsoTimePicker.d.ts +16 -0
- package/dist/types/components/DatePicker/PickerDemo.d.ts +1 -0
- package/dist/types/components/DatePicker/UniversalPicker.d.ts +9 -0
- package/dist/types/components/DatePicker/index.d.ts +7 -0
- package/dist/types/components/Filter/TagFilter.d.ts +5 -1
- package/dist/types/components/Form/SchemaFormContext.d.ts +8 -1
- package/dist/types/components/Form/components/core/DefaultForm.d.ts +1 -0
- package/dist/types/components/Form/components/core/FormRoot.d.ts +9 -2
- package/dist/types/components/Form/components/fields/CustomInput.d.ts +8 -0
- package/dist/types/components/Form/components/fields/DatePicker.d.ts +2 -7
- package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +2 -0
- package/dist/types/components/Form/components/fields/EnumPicker.d.ts +2 -1
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +2 -5
- package/dist/types/components/Form/components/fields/StringInputField.d.ts +19 -5
- package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +12 -0
- package/dist/types/components/Form/components/fields/TimePicker.d.ts +7 -0
- package/dist/types/components/Form/components/fields/types.d.ts +6 -0
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +19 -1
- package/dist/types/components/Form/components/viewers/CustomViewer.d.ts +8 -0
- package/dist/types/components/Form/components/viewers/DateTimeViewer.d.ts +7 -0
- package/dist/types/components/Form/components/viewers/TextAreaViewer.d.ts +12 -0
- package/dist/types/components/Form/components/viewers/TimeViewer.d.ts +7 -0
- package/dist/types/components/Form/utils/translateWrapper.d.ts +6 -0
- package/dist/types/components/Form/utils/useFormI18n.d.ts +53 -0
- package/dist/types/components/Form/utils/validateData.d.ts +9 -0
- package/dist/types/components/Form/utils/validation.d.ts +104 -0
- package/dist/types/components/TextArea/TextArea.d.ts +22 -0
- package/dist/types/components/TimePicker/TimePicker.d.ts +21 -0
- package/dist/types/index.d.ts +18 -2
- package/package.json +9 -2
package/dist/index.mjs
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card,
|
|
2
|
+
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Group, InputElement, Tooltip as Tooltip$1, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Accordion, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Center, Heading } from '@chakra-ui/react';
|
|
3
3
|
import { AiOutlineColumnWidth } from 'react-icons/ai';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import React__default, { createContext, useContext, useState, useEffect, useRef } from 'react';
|
|
5
|
+
import React__default, { createContext, useContext, useState, useEffect, useRef, forwardRef } from 'react';
|
|
6
6
|
import { LuX, LuCheck, LuChevronRight, LuChevronDown } from 'react-icons/lu';
|
|
7
|
-
import { MdOutlineSort, MdFilterAlt, MdSearch,
|
|
8
|
-
import { FaUpDown, FaGripLinesVertical } from 'react-icons/fa6';
|
|
7
|
+
import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdOutlineChecklist, MdDateRange } from 'react-icons/md';
|
|
8
|
+
import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
|
|
9
9
|
import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
|
|
10
|
-
import { CgClose } from 'react-icons/cg';
|
|
10
|
+
import { CgClose, CgTrash } from 'react-icons/cg';
|
|
11
11
|
import Dayzed from '@bsol-oss/dayzed-react19';
|
|
12
12
|
import { HiMiniEllipsisHorizontal, HiChevronLeft, HiChevronRight } from 'react-icons/hi2';
|
|
13
|
-
import { IoMdEye, IoMdCheckbox } from 'react-icons/io';
|
|
13
|
+
import { IoMdEye, IoMdCheckbox, IoMdClock } from 'react-icons/io';
|
|
14
14
|
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
15
15
|
import { bind, bindAll } from 'bind-event-listener';
|
|
16
16
|
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
17
17
|
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
|
|
18
18
|
import rafSchd from 'raf-schd';
|
|
19
19
|
import invariant from 'tiny-invariant';
|
|
20
|
-
import { HiColorSwatch } from 'react-icons/hi';
|
|
20
|
+
import { HiColorSwatch, HiOutlineInformationCircle } from 'react-icons/hi';
|
|
21
21
|
import { flexRender, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel, createColumnHelper } from '@tanstack/react-table';
|
|
22
22
|
import { rankItem } from '@tanstack/match-sorter-utils';
|
|
23
|
-
import { BsExclamationCircleFill } from 'react-icons/bs';
|
|
23
|
+
import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
|
|
24
24
|
import { useDebounce } from '@uidotdev/usehooks';
|
|
25
25
|
import { useQueryClient, useQuery } from '@tanstack/react-query';
|
|
26
26
|
import { IoReload } from 'react-icons/io5';
|
|
@@ -28,7 +28,12 @@ import { GrAscend, GrDescend } from 'react-icons/gr';
|
|
|
28
28
|
import { useTranslation } from 'react-i18next';
|
|
29
29
|
import axios from 'axios';
|
|
30
30
|
import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
|
|
31
|
+
import Ajv from 'ajv';
|
|
32
|
+
import addFormats from 'ajv-formats';
|
|
33
|
+
import addErrors from 'ajv-errors';
|
|
31
34
|
import dayjs from 'dayjs';
|
|
35
|
+
import utc from 'dayjs/plugin/utc';
|
|
36
|
+
import timezone from 'dayjs/plugin/timezone';
|
|
32
37
|
import { TiDeleteOutline } from 'react-icons/ti';
|
|
33
38
|
|
|
34
39
|
const DataTableContext = createContext({
|
|
@@ -37,6 +42,56 @@ const DataTableContext = createContext({
|
|
|
37
42
|
setGlobalFilter: () => { },
|
|
38
43
|
type: "client",
|
|
39
44
|
translate: {},
|
|
45
|
+
data: [],
|
|
46
|
+
columns: [],
|
|
47
|
+
columnOrder: [],
|
|
48
|
+
columnFilters: [],
|
|
49
|
+
density: "sm",
|
|
50
|
+
sorting: [],
|
|
51
|
+
setPagination: function () {
|
|
52
|
+
throw new Error("Function not implemented.");
|
|
53
|
+
},
|
|
54
|
+
setSorting: function () {
|
|
55
|
+
throw new Error("Function not implemented.");
|
|
56
|
+
},
|
|
57
|
+
setColumnFilters: function () {
|
|
58
|
+
throw new Error("Function not implemented.");
|
|
59
|
+
},
|
|
60
|
+
setRowSelection: function () {
|
|
61
|
+
throw new Error("Function not implemented.");
|
|
62
|
+
},
|
|
63
|
+
setColumnOrder: function () {
|
|
64
|
+
throw new Error("Function not implemented.");
|
|
65
|
+
},
|
|
66
|
+
setDensity: function () {
|
|
67
|
+
throw new Error("Function not implemented.");
|
|
68
|
+
},
|
|
69
|
+
setColumnVisibility: function () {
|
|
70
|
+
throw new Error("Function not implemented.");
|
|
71
|
+
},
|
|
72
|
+
pagination: {
|
|
73
|
+
pageIndex: 0,
|
|
74
|
+
pageSize: 10,
|
|
75
|
+
},
|
|
76
|
+
rowSelection: {},
|
|
77
|
+
columnVisibility: {},
|
|
78
|
+
tableLabel: {
|
|
79
|
+
view: "View",
|
|
80
|
+
edit: "Edit",
|
|
81
|
+
filterButtonText: "Filter",
|
|
82
|
+
filterTitle: "Filter",
|
|
83
|
+
filterReset: "Reset",
|
|
84
|
+
filterClose: "Close",
|
|
85
|
+
reloadTooltip: "Reload",
|
|
86
|
+
reloadButtonText: "Reload",
|
|
87
|
+
resetSelection: "Reset Selection",
|
|
88
|
+
resetSorting: "Reset Sorting",
|
|
89
|
+
rowCountText: "Row Count",
|
|
90
|
+
hasErrorText: "Has Error",
|
|
91
|
+
globalFilterPlaceholder: "Search",
|
|
92
|
+
trueLabel: "True",
|
|
93
|
+
falseLabel: "False",
|
|
94
|
+
},
|
|
40
95
|
});
|
|
41
96
|
|
|
42
97
|
const useDataTableContext = () => {
|
|
@@ -92,11 +147,13 @@ const TableSorter = () => {
|
|
|
92
147
|
}) }))) }));
|
|
93
148
|
};
|
|
94
149
|
|
|
95
|
-
const ResetSortingButton = (
|
|
150
|
+
const ResetSortingButton = () => {
|
|
96
151
|
const { table } = useDataTableContext();
|
|
152
|
+
const { tableLabel } = useDataTableContext();
|
|
153
|
+
const { resetSorting } = tableLabel;
|
|
97
154
|
return (jsx(Button$1, { onClick: () => {
|
|
98
155
|
table.resetSorting();
|
|
99
|
-
}, children:
|
|
156
|
+
}, children: resetSorting }));
|
|
100
157
|
};
|
|
101
158
|
|
|
102
159
|
const EditSortingButton = ({ text, icon = jsx(MdOutlineSort, {}), title = "Edit Sorting", }) => {
|
|
@@ -124,7 +181,7 @@ const monthNamesFull = [
|
|
|
124
181
|
"November",
|
|
125
182
|
"December",
|
|
126
183
|
];
|
|
127
|
-
const weekdayNamesShort
|
|
184
|
+
const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
128
185
|
function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, selected = [], firstDayOfWeek = 0, }) {
|
|
129
186
|
const [hoveredDate, setHoveredDate] = useState();
|
|
130
187
|
const onMouseLeave = () => {
|
|
@@ -159,7 +216,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
159
216
|
offset: 12,
|
|
160
217
|
}), children: ">>" })] }), jsx(Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", gap: 4, children: calendars.map((calendar) => (jsxs(Grid, { gap: 4, children: [jsxs(Grid, { justifyContent: "center", children: [monthNamesFull[calendar.month], " ", calendar.year] }), jsx(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
161
218
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
162
|
-
return (jsx(Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort
|
|
219
|
+
return (jsx(Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
163
220
|
}) }), jsx(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: calendar.weeks.map((week, windex) => week.map((dateObj, index) => {
|
|
164
221
|
const key = `${calendar.month}${calendar.year}${windex}${index}`;
|
|
165
222
|
if (!dateObj) {
|
|
@@ -280,8 +337,17 @@ const Tag = React.forwardRef(function Tag(props, ref) {
|
|
|
280
337
|
return (jsxs(Tag$1.Root, { ref: ref, ...rest, children: [startElement && (jsx(Tag$1.StartElement, { children: startElement })), jsx(Tag$1.Label, { children: children }), endElement && (jsx(Tag$1.EndElement, { children: endElement })), closable && (jsx(Tag$1.EndElement, { children: jsx(Tag$1.CloseTrigger, { onClick: onClose }) }))] }));
|
|
281
338
|
});
|
|
282
339
|
|
|
283
|
-
const TagFilter = ({ availableTags, selectedTags, onTagChange, }) => {
|
|
340
|
+
const TagFilter = ({ availableTags, selectedTags, onTagChange, selectOne = false, }) => {
|
|
284
341
|
const toggleTag = (tag) => {
|
|
342
|
+
if (selectOne) {
|
|
343
|
+
if (selectedTags.includes(tag)) {
|
|
344
|
+
onTagChange([]);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
onTagChange([tag]);
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
285
351
|
if (selectedTags.includes(tag)) {
|
|
286
352
|
onTagChange(selectedTags.filter((t) => t !== tag));
|
|
287
353
|
}
|
|
@@ -289,10 +355,14 @@ const TagFilter = ({ availableTags, selectedTags, onTagChange, }) => {
|
|
|
289
355
|
onTagChange([...selectedTags, tag]);
|
|
290
356
|
}
|
|
291
357
|
};
|
|
292
|
-
return (jsx(Flex, { flexFlow: "wrap", p: "0.5rem", gap: "0.5rem", children: availableTags.map((tag) =>
|
|
358
|
+
return (jsx(Flex, { flexFlow: "wrap", p: "0.5rem", gap: "0.5rem", children: availableTags.map((tag) => {
|
|
359
|
+
const { label, value } = tag;
|
|
360
|
+
return (jsx(Tag, { variant: selectedTags.includes(value) ? "solid" : "outline", cursor: "pointer", closable: selectedTags.includes(value) ? true : undefined, onClick: () => toggleTag(value), children: label ?? value }));
|
|
361
|
+
}) }));
|
|
293
362
|
};
|
|
294
363
|
|
|
295
364
|
const Filter = ({ column }) => {
|
|
365
|
+
const { tableLabel } = useDataTableContext();
|
|
296
366
|
const { filterVariant } = column.columnDef.meta ?? {};
|
|
297
367
|
const displayName = column.columnDef.meta?.displayName ?? column.id;
|
|
298
368
|
const filterOptions = column.columnDef.meta?.filterOptions ?? [];
|
|
@@ -307,10 +377,14 @@ const Filter = ({ column }) => {
|
|
|
307
377
|
if (filterVariant === "select") {
|
|
308
378
|
return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(RadioGroup, { value: column.getFilterValue() ? String(column.getFilterValue()) : "", onValueChange: (details) => {
|
|
309
379
|
column.setFilterValue(details.value);
|
|
310
|
-
}, children:
|
|
380
|
+
}, children: jsxs(Flex, { flexFlow: "wrap", gap: "0.5rem", children: [filterOptions.length === 0 && jsx(Text, { children: "No filter options" }), filterOptions.length > 0 &&
|
|
381
|
+
filterOptions.map((item) => (jsx(Radio, { value: item.value, children: item.label }, item.value)))] }) })] }, column.id));
|
|
311
382
|
}
|
|
312
383
|
if (filterVariant === "tag") {
|
|
313
|
-
return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(TagFilter, { availableTags: filterOptions
|
|
384
|
+
return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(TagFilter, { availableTags: filterOptions.map((item) => ({
|
|
385
|
+
label: item.label,
|
|
386
|
+
value: item.value,
|
|
387
|
+
})), selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
|
|
314
388
|
if (tags.length === 0) {
|
|
315
389
|
return column.setFilterValue(undefined);
|
|
316
390
|
}
|
|
@@ -318,7 +392,11 @@ const Filter = ({ column }) => {
|
|
|
318
392
|
} })] }, column.id));
|
|
319
393
|
}
|
|
320
394
|
if (filterVariant === "boolean") {
|
|
321
|
-
|
|
395
|
+
const { trueLabel, falseLabel } = tableLabel;
|
|
396
|
+
return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(TagFilter, { availableTags: [
|
|
397
|
+
{ label: trueLabel, value: "true" },
|
|
398
|
+
{ label: falseLabel, value: "false" },
|
|
399
|
+
], selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
|
|
322
400
|
if (tags.length === 0) {
|
|
323
401
|
return column.setFilterValue(undefined);
|
|
324
402
|
}
|
|
@@ -373,17 +451,20 @@ const TableFilter = () => {
|
|
|
373
451
|
}) }));
|
|
374
452
|
};
|
|
375
453
|
|
|
376
|
-
const ResetFilteringButton = (
|
|
454
|
+
const ResetFilteringButton = () => {
|
|
377
455
|
const { table } = useDataTableContext();
|
|
456
|
+
const { tableLabel } = useDataTableContext();
|
|
457
|
+
const { filterReset } = tableLabel;
|
|
378
458
|
return (jsx(Button$1, { onClick: () => {
|
|
379
459
|
table.resetColumnFilters();
|
|
380
|
-
}, children:
|
|
460
|
+
}, children: filterReset }));
|
|
381
461
|
};
|
|
382
462
|
|
|
383
463
|
const FilterDialog = ({ icon = jsx(MdFilterAlt, {}), }) => {
|
|
384
464
|
const filterModal = useDisclosure();
|
|
385
|
-
const {
|
|
386
|
-
|
|
465
|
+
const { tableLabel } = useDataTableContext();
|
|
466
|
+
const { filterButtonText, filterTitle, filterClose } = tableLabel;
|
|
467
|
+
return (jsxs(DialogRoot, { size: ["full", "full", "md", "md"], open: filterModal.open, children: [jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: filterModal.onOpen, children: [icon, " ", filterButtonText] }) }), jsxs(DialogContent, { children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: filterTitle }) }), jsx(DialogBody, { display: "flex", flexFlow: "column", children: jsx(TableFilter, {}) }), jsxs(DialogFooter, { children: [jsx(ResetFilteringButton, {}), jsx(Button$1, { onClick: filterModal.onClose, variant: "subtle", children: filterClose })] }), jsx(DialogCloseTrigger, { onClick: filterModal.onClose })] })] }));
|
|
387
468
|
};
|
|
388
469
|
|
|
389
470
|
const MenuContent = React.forwardRef(function MenuContent(props, ref) {
|
|
@@ -502,11 +583,13 @@ const Pagination = () => {
|
|
|
502
583
|
}, children: jsxs(HStack, { children: [jsx(PaginationPrevTrigger, {}), jsx(PaginationItems, {}), jsx(PaginationNextTrigger, {})] }) }));
|
|
503
584
|
};
|
|
504
585
|
|
|
505
|
-
const ResetSelectionButton = (
|
|
586
|
+
const ResetSelectionButton = () => {
|
|
506
587
|
const { table } = useDataTableContext();
|
|
588
|
+
const { tableLabel } = useDataTableContext();
|
|
589
|
+
const { resetSelection } = tableLabel;
|
|
507
590
|
return (jsx(Button$1, { onClick: () => {
|
|
508
591
|
table.resetRowSelection();
|
|
509
|
-
}, children:
|
|
592
|
+
}, children: resetSelection }));
|
|
510
593
|
};
|
|
511
594
|
|
|
512
595
|
const RowCountText = () => {
|
|
@@ -2421,8 +2504,8 @@ CheckboxCard$1.Indicator;
|
|
|
2421
2504
|
function ColumnCard({ columnId }) {
|
|
2422
2505
|
const ref = useRef(null);
|
|
2423
2506
|
const [dragging, setDragging] = useState(false); // NEW
|
|
2424
|
-
const { table } = useDataTableContext();
|
|
2425
|
-
const displayName = columnId;
|
|
2507
|
+
const { table, translate } = useDataTableContext();
|
|
2508
|
+
const displayName = translate.t(columnId);
|
|
2426
2509
|
const column = table.getColumn(columnId);
|
|
2427
2510
|
invariant(column);
|
|
2428
2511
|
useEffect(() => {
|
|
@@ -2437,7 +2520,7 @@ function ColumnCard({ columnId }) {
|
|
|
2437
2520
|
onDrop: () => setDragging(false), // NEW
|
|
2438
2521
|
});
|
|
2439
2522
|
}, [columnId, table]);
|
|
2440
|
-
return (jsxs(Grid, { ref: ref, templateColumns: "auto 1fr", gap: "0.5rem", alignItems: "center", style: dragging ? { opacity: 0.4 } : {}, children: [jsx(Flex, { alignItems: "center", padding: "0", cursor: "grab", children: jsx(FaGripLinesVertical, { color: "
|
|
2523
|
+
return (jsxs(Grid, { ref: ref, templateColumns: "auto 1fr", gap: "0.5rem", alignItems: "center", style: dragging ? { opacity: 0.4 } : {}, children: [jsx(Flex, { alignItems: "center", padding: "0", cursor: "grab", children: jsx(FaGripLinesVertical, { color: "colorPalette.400" }) }), jsx(Flex, { justifyContent: "space-between", alignItems: "center", children: jsx(CheckboxCard, { variant: "surface", label: displayName, checked: column.getIsVisible(), onChange: column.getToggleVisibilityHandler() }) })] }));
|
|
2441
2524
|
}
|
|
2442
2525
|
function CardContainer({ location, children }) {
|
|
2443
2526
|
const ref = useRef(null);
|
|
@@ -2456,7 +2539,6 @@ function CardContainer({ location, children }) {
|
|
|
2456
2539
|
onDrop: () => setIsDraggedOver(false),
|
|
2457
2540
|
});
|
|
2458
2541
|
}, [location]);
|
|
2459
|
-
// const isDark = (location + location) % 2 === 1;
|
|
2460
2542
|
function getColor(isDraggedOver) {
|
|
2461
2543
|
if (isDraggedOver) {
|
|
2462
2544
|
return {
|
|
@@ -2466,7 +2548,6 @@ function CardContainer({ location, children }) {
|
|
|
2466
2548
|
},
|
|
2467
2549
|
};
|
|
2468
2550
|
}
|
|
2469
|
-
// return isDark ? "lightgrey" : "white";
|
|
2470
2551
|
return {
|
|
2471
2552
|
backgroundColor: undefined,
|
|
2472
2553
|
_dark: {
|
|
@@ -2517,8 +2598,9 @@ const TableViewer = () => {
|
|
|
2517
2598
|
|
|
2518
2599
|
const ViewDialog = ({ icon = jsx(IoMdEye, {}) }) => {
|
|
2519
2600
|
const viewModel = useDisclosure();
|
|
2520
|
-
const {
|
|
2521
|
-
|
|
2601
|
+
const { tableLabel } = useDataTableContext();
|
|
2602
|
+
const { view } = tableLabel;
|
|
2603
|
+
return (jsxs(DialogRoot, { children: [jsx(DialogBackdrop, {}), jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: viewModel.onOpen, children: [icon, " ", view] }) }), jsxs(DialogContent, { children: [jsx(DialogCloseTrigger, {}), jsx(DialogHeader, { children: jsx(DialogTitle, { children: view }) }), jsx(DialogBody, { children: jsx(TableViewer, {}) }), jsx(DialogFooter, {})] })] }));
|
|
2522
2604
|
};
|
|
2523
2605
|
|
|
2524
2606
|
const CardHeader = ({ row, imageColumnId = undefined, titleColumnId = undefined, tagColumnId = undefined, tagIcon = undefined, showTag = true, imageProps = {}, }) => {
|
|
@@ -2569,7 +2651,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = "", }) => {
|
|
|
2569
2651
|
return jsx(Fragment, { children: "null" });
|
|
2570
2652
|
}
|
|
2571
2653
|
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
|
|
2572
|
-
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "
|
|
2654
|
+
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "colorPalette.400", children: getColumn({ field }) }), typeof value === "object" ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsx(Text, { children: JSON.stringify(value) }))] }, field));
|
|
2573
2655
|
}) }));
|
|
2574
2656
|
};
|
|
2575
2657
|
|
|
@@ -2619,7 +2701,7 @@ const CellRenderer = ({ cell }) => {
|
|
|
2619
2701
|
paddingY: 2,
|
|
2620
2702
|
}, object: value })] }, cell.id));
|
|
2621
2703
|
}
|
|
2622
|
-
return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { color:
|
|
2704
|
+
return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { color: "colorPalette.400", children: getLabel({ columnId: cell.column.id }) }), jsx(Box, { wordBreak: "break-word", textOverflow: "ellipsis", overflow: "hidden", children: `${formatValue(cell.getValue())}` })] }, cell.id));
|
|
2623
2705
|
};
|
|
2624
2706
|
const DataDisplay = ({ variant = "" }) => {
|
|
2625
2707
|
const { table, translate } = useDataTableContext();
|
|
@@ -2741,7 +2823,23 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
|
|
|
2741
2823
|
*
|
|
2742
2824
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
2743
2825
|
*/
|
|
2744
|
-
function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, translate, children,
|
|
2826
|
+
function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, translate, children, tableLabel = {
|
|
2827
|
+
view: "View",
|
|
2828
|
+
edit: "Edit",
|
|
2829
|
+
filterButtonText: "Filter",
|
|
2830
|
+
filterTitle: "Filter",
|
|
2831
|
+
filterReset: "Reset",
|
|
2832
|
+
filterClose: "Close",
|
|
2833
|
+
reloadTooltip: "Reload",
|
|
2834
|
+
reloadButtonText: "Reload",
|
|
2835
|
+
resetSelection: "Reset Selection",
|
|
2836
|
+
resetSorting: "Reset Sorting",
|
|
2837
|
+
rowCountText: "Row Count",
|
|
2838
|
+
hasErrorText: "Has Error",
|
|
2839
|
+
globalFilterPlaceholder: "Search",
|
|
2840
|
+
trueLabel: "True",
|
|
2841
|
+
falseLabel: "False",
|
|
2842
|
+
}, }) {
|
|
2745
2843
|
const table = useReactTable({
|
|
2746
2844
|
_features: [DensityFeature],
|
|
2747
2845
|
data: data,
|
|
@@ -2794,7 +2892,7 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
2794
2892
|
setGlobalFilter,
|
|
2795
2893
|
type: "client",
|
|
2796
2894
|
translate,
|
|
2797
|
-
columns,
|
|
2895
|
+
columns: columns,
|
|
2798
2896
|
sorting,
|
|
2799
2897
|
setSorting,
|
|
2800
2898
|
columnFilters,
|
|
@@ -2809,6 +2907,8 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
2809
2907
|
setDensity,
|
|
2810
2908
|
columnVisibility,
|
|
2811
2909
|
setColumnVisibility,
|
|
2910
|
+
data,
|
|
2911
|
+
tableLabel,
|
|
2812
2912
|
}, children: children }));
|
|
2813
2913
|
}
|
|
2814
2914
|
|
|
@@ -2823,10 +2923,26 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
2823
2923
|
*
|
|
2824
2924
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
2825
2925
|
*/
|
|
2826
|
-
function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url, translate, children,
|
|
2926
|
+
function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url, translate, children, tableLabel = {
|
|
2927
|
+
view: "View",
|
|
2928
|
+
edit: "Edit",
|
|
2929
|
+
filterButtonText: "Filter",
|
|
2930
|
+
filterTitle: "Filter",
|
|
2931
|
+
filterReset: "Reset",
|
|
2932
|
+
filterClose: "Close",
|
|
2933
|
+
reloadTooltip: "Reload",
|
|
2934
|
+
reloadButtonText: "Reload",
|
|
2935
|
+
resetSelection: "Reset Selection",
|
|
2936
|
+
resetSorting: "Reset Sorting",
|
|
2937
|
+
rowCountText: "Row Count",
|
|
2938
|
+
hasErrorText: "Has Error",
|
|
2939
|
+
globalFilterPlaceholder: "Search",
|
|
2940
|
+
trueLabel: "True",
|
|
2941
|
+
falseLabel: "False",
|
|
2942
|
+
}, }) {
|
|
2827
2943
|
const table = useReactTable({
|
|
2828
2944
|
_features: [DensityFeature],
|
|
2829
|
-
data: query.data?.data ?? [],
|
|
2945
|
+
data: (query.data?.data ?? []),
|
|
2830
2946
|
rowCount: query.data?.count ?? 0,
|
|
2831
2947
|
columns: columns,
|
|
2832
2948
|
getCoreRowModel: getCoreRowModel(),
|
|
@@ -2872,12 +2988,12 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
2872
2988
|
// for tanstack-table ts bug end
|
|
2873
2989
|
});
|
|
2874
2990
|
return (jsx(DataTableContext.Provider, { value: {
|
|
2875
|
-
table:
|
|
2991
|
+
table: table,
|
|
2876
2992
|
globalFilter,
|
|
2877
2993
|
setGlobalFilter,
|
|
2878
2994
|
type: "server",
|
|
2879
2995
|
translate,
|
|
2880
|
-
columns,
|
|
2996
|
+
columns: columns,
|
|
2881
2997
|
sorting,
|
|
2882
2998
|
setSorting,
|
|
2883
2999
|
columnFilters,
|
|
@@ -2892,98 +3008,11 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
2892
3008
|
setDensity,
|
|
2893
3009
|
columnVisibility,
|
|
2894
3010
|
setColumnVisibility,
|
|
3011
|
+
data: query.data?.data ?? [],
|
|
3012
|
+
tableLabel,
|
|
2895
3013
|
}, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
2896
3014
|
}
|
|
2897
3015
|
|
|
2898
|
-
const Checkbox = React.forwardRef(function Checkbox(props, ref) {
|
|
2899
|
-
const { icon, children, inputProps, rootRef, ...rest } = props;
|
|
2900
|
-
return (jsxs(Checkbox$1.Root, { ref: rootRef, ...rest, children: [jsx(Checkbox$1.HiddenInput, { ref: ref, ...inputProps }), jsx(Checkbox$1.Control, { children: icon || jsx(Checkbox$1.Indicator, {}) }), children != null && (jsx(Checkbox$1.Label, { children: children }))] }));
|
|
2901
|
-
});
|
|
2902
|
-
|
|
2903
|
-
const TableBody = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, showSelector = false, alwaysShowSelector = true, canResize = true, }) => {
|
|
2904
|
-
"use no memo";
|
|
2905
|
-
const { table } = useDataTableContext();
|
|
2906
|
-
const SELECTION_BOX_WIDTH = 20;
|
|
2907
|
-
const [hoveredRow, setHoveredRow] = useState(-1);
|
|
2908
|
-
const handleRowHover = (index) => {
|
|
2909
|
-
setHoveredRow(index);
|
|
2910
|
-
};
|
|
2911
|
-
const getTdProps = (cell) => {
|
|
2912
|
-
const tdProps = cell.column.getIsPinned()
|
|
2913
|
-
? {
|
|
2914
|
-
left: showSelector
|
|
2915
|
-
? `${cell.column.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
2916
|
-
: `${cell.column.getStart("left")}px`,
|
|
2917
|
-
background: pinnedBgColor.light,
|
|
2918
|
-
position: "sticky",
|
|
2919
|
-
zIndex: -1,
|
|
2920
|
-
_dark: {
|
|
2921
|
-
backgroundColor: pinnedBgColor.dark,
|
|
2922
|
-
},
|
|
2923
|
-
}
|
|
2924
|
-
: {};
|
|
2925
|
-
return tdProps;
|
|
2926
|
-
};
|
|
2927
|
-
const getTrProps = ({ hoveredRow, index, }) => {
|
|
2928
|
-
if (hoveredRow === -1) {
|
|
2929
|
-
return {};
|
|
2930
|
-
}
|
|
2931
|
-
if (hoveredRow === index) {
|
|
2932
|
-
return {
|
|
2933
|
-
opacity: "1",
|
|
2934
|
-
};
|
|
2935
|
-
}
|
|
2936
|
-
return {
|
|
2937
|
-
opacity: "0.8",
|
|
2938
|
-
};
|
|
2939
|
-
};
|
|
2940
|
-
return (jsx(Table$1.Body, { children: table.getRowModel().rows.map((row, index) => {
|
|
2941
|
-
return (jsxs(Table$1.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow, alwaysShowSelector: alwaysShowSelector })), row.getVisibleCells().map((cell, index) => {
|
|
2942
|
-
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
|
|
2943
|
-
// styling resize and pinning start
|
|
2944
|
-
flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`, backgroundColor: "white", ...getTdProps(cell), _dark: {
|
|
2945
|
-
backgroundColor: "gray.950",
|
|
2946
|
-
}, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
2947
|
-
})] }, `chakra-table-row-${row.id}`));
|
|
2948
|
-
}) }));
|
|
2949
|
-
};
|
|
2950
|
-
const TableRowSelector = ({ index, row, hoveredRow, pinnedBgColor = { light: "gray.50", dark: "gray.700" }, alwaysShowSelector = true, }) => {
|
|
2951
|
-
const { table } = useDataTableContext();
|
|
2952
|
-
const SELECTION_BOX_WIDTH = 20;
|
|
2953
|
-
const isCheckBoxVisible = (current_index, current_row) => {
|
|
2954
|
-
if (alwaysShowSelector) {
|
|
2955
|
-
return true;
|
|
2956
|
-
}
|
|
2957
|
-
if (current_row.getIsSelected()) {
|
|
2958
|
-
return true;
|
|
2959
|
-
}
|
|
2960
|
-
if (hoveredRow == current_index) {
|
|
2961
|
-
return true;
|
|
2962
|
-
}
|
|
2963
|
-
return false;
|
|
2964
|
-
};
|
|
2965
|
-
return (jsxs(Table$1.Cell, { padding: `${table.getDensityValue()}px`, ...(table.getIsSomeColumnsPinned("left")
|
|
2966
|
-
? {
|
|
2967
|
-
left: `0px`,
|
|
2968
|
-
backgroundColor: pinnedBgColor.light,
|
|
2969
|
-
position: "sticky",
|
|
2970
|
-
zIndex: 1,
|
|
2971
|
-
_dark: { backgroundColor: pinnedBgColor.dark },
|
|
2972
|
-
}
|
|
2973
|
-
: {}),
|
|
2974
|
-
// styling resize and pinning end
|
|
2975
|
-
display: "grid", children: [!isCheckBoxVisible(index, row) && (jsx(Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` })), isCheckBoxVisible(index, row) && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: row.getIsSelected(),
|
|
2976
|
-
disabled: !row.getCanSelect(),
|
|
2977
|
-
onChange: row.getToggleSelectedHandler() }) }))] }));
|
|
2978
|
-
};
|
|
2979
|
-
|
|
2980
|
-
const Tooltip = React.forwardRef(function Tooltip(props, ref) {
|
|
2981
|
-
const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
|
|
2982
|
-
if (disabled)
|
|
2983
|
-
return children;
|
|
2984
|
-
return (jsxs(Tooltip$1.Root, { ...rest, children: [jsx(Tooltip$1.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Tooltip$1.Positioner, { children: jsxs(Tooltip$1.Content, { ref: ref, ...contentProps, children: [showArrow && (jsx(Tooltip$1.Arrow, { children: jsx(Tooltip$1.ArrowTip, {}) })), content] }) }) })] }));
|
|
2985
|
-
});
|
|
2986
|
-
|
|
2987
3016
|
const InputGroup = React.forwardRef(function InputGroup(props, ref) {
|
|
2988
3017
|
const { startElement, startElementProps, endElement, endElementProps, children, startOffset = "6px", endOffset = "6px", ...rest } = props;
|
|
2989
3018
|
return (jsxs(Group, { ref: ref, ...rest, children: [startElement && (jsx(InputElement, { pointerEvents: "none", ...startElementProps, children: startElement })), React.cloneElement(children, {
|
|
@@ -2997,7 +3026,8 @@ const InputGroup = React.forwardRef(function InputGroup(props, ref) {
|
|
|
2997
3026
|
});
|
|
2998
3027
|
|
|
2999
3028
|
const GlobalFilter = () => {
|
|
3000
|
-
const { table } = useDataTableContext();
|
|
3029
|
+
const { table, tableLabel } = useDataTableContext();
|
|
3030
|
+
const { globalFilterPlaceholder } = tableLabel;
|
|
3001
3031
|
const [searchTerm, setSearchTerm] = useState("");
|
|
3002
3032
|
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
3003
3033
|
useEffect(() => {
|
|
@@ -3006,42 +3036,31 @@ const GlobalFilter = () => {
|
|
|
3006
3036
|
};
|
|
3007
3037
|
searchHN();
|
|
3008
3038
|
}, [debouncedSearchTerm]);
|
|
3009
|
-
return (jsx(Fragment, { children: jsx(InputGroup, { flex: "1", startElement: jsx(MdSearch, {}), children: jsx(Input, { placeholder:
|
|
3039
|
+
return (jsx(Fragment, { children: jsx(InputGroup, { flex: "1", startElement: jsx(MdSearch, {}), children: jsx(Input, { placeholder: globalFilterPlaceholder, variant: "outline", onChange: (e) => {
|
|
3010
3040
|
setSearchTerm(e.target.value);
|
|
3011
3041
|
} }) }) }));
|
|
3012
3042
|
};
|
|
3013
3043
|
|
|
3014
|
-
const
|
|
3044
|
+
const Tooltip = React.forwardRef(function Tooltip(props, ref) {
|
|
3045
|
+
const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
|
|
3046
|
+
if (disabled)
|
|
3047
|
+
return children;
|
|
3048
|
+
return (jsxs(Tooltip$1.Root, { ...rest, children: [jsx(Tooltip$1.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Tooltip$1.Positioner, { children: jsxs(Tooltip$1.Content, { ref: ref, ...contentProps, children: [showArrow && (jsx(Tooltip$1.Arrow, { children: jsx(Tooltip$1.ArrowTip, {}) })), content] }) }) })] }));
|
|
3049
|
+
});
|
|
3050
|
+
|
|
3051
|
+
const ReloadButton = ({ variant = "icon", }) => {
|
|
3015
3052
|
const { url } = useDataTableServerContext();
|
|
3016
3053
|
const queryClient = useQueryClient();
|
|
3054
|
+
const { tableLabel } = useDataTableContext();
|
|
3055
|
+
const { reloadTooltip, reloadButtonText } = tableLabel;
|
|
3017
3056
|
if (variant === "icon") {
|
|
3018
|
-
return (jsx(Tooltip, { showArrow: true, content:
|
|
3057
|
+
return (jsx(Tooltip, { showArrow: true, content: reloadTooltip, children: jsx(Button, { variant: "ghost", onClick: () => {
|
|
3019
3058
|
queryClient.invalidateQueries({ queryKey: [url] });
|
|
3020
3059
|
}, "aria-label": "refresh", children: jsx(IoReload, {}) }) }));
|
|
3021
3060
|
}
|
|
3022
3061
|
return (jsxs(Button, { variant: "ghost", onClick: () => {
|
|
3023
3062
|
queryClient.invalidateQueries({ queryKey: [url] });
|
|
3024
|
-
}, children: [jsx(IoReload, {}), " ",
|
|
3025
|
-
};
|
|
3026
|
-
|
|
3027
|
-
const FilterOptions = ({ column }) => {
|
|
3028
|
-
const { table } = useDataTableContext();
|
|
3029
|
-
const tableColumn = table.getColumn(column);
|
|
3030
|
-
const options = tableColumn?.columnDef.meta?.filterOptions ?? [];
|
|
3031
|
-
return (jsx(Fragment, { children: options.map((option) => {
|
|
3032
|
-
const selected = table.getColumn(column)?.getFilterValue() === option;
|
|
3033
|
-
return (jsxs(Button$1, { size: "sm", onClick: () => {
|
|
3034
|
-
if (selected) {
|
|
3035
|
-
table.setColumnFilters((state) => {
|
|
3036
|
-
return state.filter((filter) => {
|
|
3037
|
-
return filter.id !== column;
|
|
3038
|
-
});
|
|
3039
|
-
});
|
|
3040
|
-
return;
|
|
3041
|
-
}
|
|
3042
|
-
table.getColumn(column)?.setFilterValue(option);
|
|
3043
|
-
}, variant: selected ? "solid" : "outline", display: "flex", gap: "0.25rem", children: [option, selected && jsx(MdClose, {})] }, option));
|
|
3044
|
-
}) }));
|
|
3063
|
+
}, children: [jsx(IoReload, {}), " ", reloadButtonText] }));
|
|
3045
3064
|
};
|
|
3046
3065
|
|
|
3047
3066
|
const TableFilterTags = () => {
|
|
@@ -3055,16 +3074,99 @@ const TableFilterTags = () => {
|
|
|
3055
3074
|
}) }));
|
|
3056
3075
|
};
|
|
3057
3076
|
|
|
3058
|
-
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true,
|
|
3059
|
-
const {
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3077
|
+
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsx(Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
|
|
3078
|
+
const { tableLabel, table } = useDataTableContext();
|
|
3079
|
+
const { rowCountText, hasErrorText } = tableLabel;
|
|
3080
|
+
return (jsxs(Grid, { templateRows: "auto 1fr", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", gap: "0.5rem", ...gridProps, children: [jsxs(Flex, { flexFlow: "column", gap: 2, children: [jsxs(Flex, { justifyContent: "space-between", children: [jsx(Box, { children: showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }) }), jsxs(Flex, { gap: "0.5rem", alignItems: "center", justifySelf: "end", children: [loading && jsx(Spinner, { size: "sm" }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: "red.400" }) })), showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsx(Flex, { flexFlow: "column", gap: "0.5rem", children: filterTagsOptions.map((option) => {
|
|
3081
|
+
const { column, options } = option;
|
|
3082
|
+
const tableColumn = table.getColumn(column);
|
|
3083
|
+
return (jsxs(Flex, { alignItems: "center", flexFlow: "wrap", gap: "0.5rem", children: [tableColumn?.columnDef.meta?.displayName && (jsx(Text, { children: tableColumn?.columnDef.meta?.displayName })), jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
|
|
3084
|
+
if (tags.length === 0) {
|
|
3085
|
+
return tableColumn?.setFilterValue(undefined);
|
|
3086
|
+
}
|
|
3087
|
+
tableColumn?.setFilterValue(tags);
|
|
3088
|
+
} })] }, column));
|
|
3089
|
+
}) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, { overflow: "auto", bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Flex, { justifyContent: "space-between", children: [jsxs(Flex, { gap: "1rem", alignItems: "center", children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && (jsxs(Flex, { children: [jsx(Text, { paddingRight: "0.5rem", children: rowCountText }), jsx(RowCountText, {})] }))] }), jsx(Box, { justifySelf: "end", children: showPagination && jsx(Pagination, {}) })] }))] }));
|
|
3090
|
+
};
|
|
3091
|
+
|
|
3092
|
+
const EmptyState = React.forwardRef(function EmptyState(props, ref) {
|
|
3093
|
+
const { title, description, icon, children, ...rest } = props;
|
|
3094
|
+
return (jsx(EmptyState$2.Root, { ref: ref, ...rest, children: jsxs(EmptyState$2.Content, { children: [icon && (jsx(EmptyState$2.Indicator, { children: icon })), description ? (jsxs(VStack, { textAlign: "center", children: [jsx(EmptyState$2.Title, { children: title }), jsx(EmptyState$2.Description, { children: description })] })) : (jsx(EmptyState$2.Title, { children: title })), children] }) }));
|
|
3095
|
+
});
|
|
3096
|
+
|
|
3097
|
+
const EmptyResult = (jsx(EmptyState, { icon: jsx(HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxs(List.Root, { variant: "marker", children: [jsx(List.Item, { children: "Try removing filters" }), jsx(List.Item, { children: "Try different keywords" })] }) }));
|
|
3098
|
+
const Table = ({ children, emptyComponent = EmptyResult, canResize = true, ...props }) => {
|
|
3099
|
+
const { table } = useDataTableContext();
|
|
3100
|
+
if (table.getRowModel().rows.length <= 0) {
|
|
3101
|
+
return emptyComponent;
|
|
3102
|
+
}
|
|
3103
|
+
return (jsx(Table$1.Root, { stickyHeader: true, variant: "outline", width: canResize ? table.getCenterTotalSize() : undefined, display: "grid", alignContent: "start", overflowY: "auto", bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, ...props, children: children }));
|
|
3104
|
+
};
|
|
3105
|
+
|
|
3106
|
+
const Checkbox = React.forwardRef(function Checkbox(props, ref) {
|
|
3107
|
+
const { icon, children, inputProps, rootRef, ...rest } = props;
|
|
3108
|
+
return (jsxs(Checkbox$1.Root, { ref: rootRef, ...rest, children: [jsx(Checkbox$1.HiddenInput, { ref: ref, ...inputProps }), jsx(Checkbox$1.Control, { children: icon || jsx(Checkbox$1.Indicator, {}) }), children != null && (jsx(Checkbox$1.Label, { children: children }))] }));
|
|
3109
|
+
});
|
|
3110
|
+
|
|
3111
|
+
const TableBody = ({ showSelector = false, canResize = true, }) => {
|
|
3112
|
+
"use no memo";
|
|
3113
|
+
const { table } = useDataTableContext();
|
|
3114
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
3115
|
+
const [hoveredRow, setHoveredRow] = useState(-1);
|
|
3116
|
+
const handleRowHover = (index) => {
|
|
3117
|
+
setHoveredRow(index);
|
|
3118
|
+
};
|
|
3119
|
+
const getTdProps = (cell) => {
|
|
3120
|
+
const tdProps = cell.column.getIsPinned()
|
|
3121
|
+
? {
|
|
3122
|
+
left: showSelector
|
|
3123
|
+
? `${cell.column.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3124
|
+
: `${cell.column.getStart("left")}px`,
|
|
3125
|
+
position: "relative",
|
|
3126
|
+
}
|
|
3127
|
+
: {};
|
|
3128
|
+
return tdProps;
|
|
3129
|
+
};
|
|
3130
|
+
const getTrProps = ({ hoveredRow, index, }) => {
|
|
3131
|
+
if (hoveredRow === -1) {
|
|
3132
|
+
return {};
|
|
3133
|
+
}
|
|
3134
|
+
if (hoveredRow === index) {
|
|
3135
|
+
return {
|
|
3136
|
+
opacity: "1",
|
|
3137
|
+
};
|
|
3138
|
+
}
|
|
3139
|
+
return {
|
|
3140
|
+
opacity: "0.8",
|
|
3141
|
+
};
|
|
3142
|
+
};
|
|
3143
|
+
return (jsx(Table$1.Body, { children: table.getRowModel().rows.map((row, index) => {
|
|
3144
|
+
return (jsxs(Table$1.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow })), row.getVisibleCells().map((cell, index) => {
|
|
3145
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
|
|
3146
|
+
// styling resize and pinning start
|
|
3147
|
+
flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`,
|
|
3148
|
+
// this is to avoid the cell from being too wide
|
|
3149
|
+
minWidth: `0`, color: {
|
|
3150
|
+
base: "colorPalette.900",
|
|
3151
|
+
_dark: "colorPalette.100",
|
|
3152
|
+
},
|
|
3153
|
+
bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, ...getTdProps(cell), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
3154
|
+
})] }, `chakra-table-row-${row.id}`));
|
|
3155
|
+
}) }));
|
|
3156
|
+
};
|
|
3157
|
+
const TableRowSelector = ({ row, }) => {
|
|
3158
|
+
const { table } = useDataTableContext();
|
|
3159
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
3160
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
|
|
3161
|
+
base: "colorPalette.900",
|
|
3162
|
+
_dark: "colorPalette.100",
|
|
3163
|
+
},
|
|
3164
|
+
bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: row.getIsSelected(),
|
|
3165
|
+
disabled: !row.getCanSelect(),
|
|
3166
|
+
onCheckedChange: row.getToggleSelectedHandler() }) }));
|
|
3065
3167
|
};
|
|
3066
3168
|
|
|
3067
|
-
const TableFooter = ({
|
|
3169
|
+
const TableFooter = ({ showSelector = false, alwaysShowSelector = true, }) => {
|
|
3068
3170
|
const table = useDataTableContext().table;
|
|
3069
3171
|
const SELECTION_BOX_WIDTH = 20;
|
|
3070
3172
|
const [hoveredCheckBox, setHoveredCheckBox] = useState(false);
|
|
@@ -3083,65 +3185,62 @@ const TableFooter = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, s
|
|
|
3083
3185
|
}
|
|
3084
3186
|
return false;
|
|
3085
3187
|
};
|
|
3086
|
-
|
|
3087
|
-
const thProps = header.column.getIsPinned()
|
|
3088
|
-
? {
|
|
3089
|
-
left: showSelector
|
|
3090
|
-
? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3091
|
-
: `${header.getStart("left") + table.getDensityValue() * 2}px`,
|
|
3092
|
-
background: pinnedBgColor.light,
|
|
3093
|
-
position: "sticky",
|
|
3094
|
-
zIndex: 1,
|
|
3095
|
-
_dark: {
|
|
3096
|
-
backgroundColor: pinnedBgColor.dark,
|
|
3097
|
-
},
|
|
3098
|
-
}
|
|
3099
|
-
: {};
|
|
3100
|
-
return thProps;
|
|
3101
|
-
};
|
|
3102
|
-
return (jsx(Table$1.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxs(Table$1.Row, { display: "flex", children: [showSelector && (jsxs(Table$1.Header
|
|
3103
|
-
// styling resize and pinning start
|
|
3104
|
-
, {
|
|
3105
|
-
// styling resize and pinning start
|
|
3106
|
-
padding: `${table.getDensityValue()}px`, ...(table.getIsSomeColumnsPinned("left")
|
|
3107
|
-
? {
|
|
3108
|
-
left: `0px`,
|
|
3109
|
-
backgroundColor: pinnedBgColor.light,
|
|
3110
|
-
position: "sticky",
|
|
3111
|
-
zIndex: 1,
|
|
3112
|
-
_dark: { backgroundColor: pinnedBgColor.dark },
|
|
3113
|
-
}
|
|
3114
|
-
: {}),
|
|
3115
|
-
// styling resize and pinning end
|
|
3116
|
-
onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
|
|
3188
|
+
return (jsx(Table$1.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxs(Table$1.Row, { display: "flex", children: [showSelector && (jsxs(Table$1.Header, { padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
|
|
3117
3189
|
// indeterminate: table.getIsSomeRowsSelected(),
|
|
3118
3190
|
onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsx(Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }))] })), footerGroup.headers.map((header) => (jsx(Table$1.Cell, { padding: "0", columnSpan: `${header.colSpan}`,
|
|
3119
3191
|
// styling resize and pinning start
|
|
3120
|
-
maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid",
|
|
3192
|
+
maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid", children: jsx(MenuRoot$1, { children: jsx(MenuTrigger$1, { asChild: true, children: jsx(Box, { padding: `${table.getDensityValue()}px`, display: "flex", alignItems: "center", justifyContent: "start", borderRadius: "0rem", children: jsxs(Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
|
|
3121
3193
|
? null
|
|
3122
|
-
: flexRender(header.column.columnDef.footer, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && (
|
|
3123
|
-
// <UpDownIcon />
|
|
3124
|
-
jsx(Fragment, {})), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
|
|
3194
|
+
: flexRender(header.column.columnDef.footer, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && jsx(Fragment, {}), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
|
|
3125
3195
|
};
|
|
3126
3196
|
|
|
3127
|
-
|
|
3197
|
+
// Default text values
|
|
3198
|
+
const DEFAULT_HEADER_TEXTS = {
|
|
3199
|
+
pinColumn: "Pin Column",
|
|
3200
|
+
cancelPin: "Cancel Pin",
|
|
3201
|
+
sortAscending: "Sort Ascending",
|
|
3202
|
+
sortDescending: "Sort Descending",
|
|
3203
|
+
clearSorting: "Clear Sorting",
|
|
3204
|
+
};
|
|
3205
|
+
/**
|
|
3206
|
+
* TableHeader component with configurable text strings.
|
|
3207
|
+
*
|
|
3208
|
+
* @example
|
|
3209
|
+
* // Using default texts
|
|
3210
|
+
* <TableHeader />
|
|
3211
|
+
*
|
|
3212
|
+
* @example
|
|
3213
|
+
* // Customizing default texts for all columns
|
|
3214
|
+
* <TableHeader
|
|
3215
|
+
* defaultTexts={{
|
|
3216
|
+
* pinColumn: "Pin This Column",
|
|
3217
|
+
* sortAscending: "Sort A-Z"
|
|
3218
|
+
* }}
|
|
3219
|
+
* />
|
|
3220
|
+
*
|
|
3221
|
+
* @example
|
|
3222
|
+
* // Customizing texts per column via meta
|
|
3223
|
+
* const columns = [
|
|
3224
|
+
* columnHelper.accessor("name", {
|
|
3225
|
+
* header: "Name",
|
|
3226
|
+
* meta: {
|
|
3227
|
+
* headerTexts: {
|
|
3228
|
+
* pinColumn: "Pin Name Column",
|
|
3229
|
+
* sortAscending: "Sort Names A-Z"
|
|
3230
|
+
* }
|
|
3231
|
+
* }
|
|
3232
|
+
* })
|
|
3233
|
+
* ];
|
|
3234
|
+
*/
|
|
3235
|
+
const TableHeader = ({ canResize = true, showSelector = false, isSticky = true, tableHeaderProps = {}, tableRowProps = {}, defaultTexts = {}, }) => {
|
|
3128
3236
|
const { table } = useDataTableContext();
|
|
3129
3237
|
const SELECTION_BOX_WIDTH = 20;
|
|
3130
|
-
|
|
3131
|
-
const
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
return true;
|
|
3137
|
-
}
|
|
3138
|
-
if (table.getIsAllRowsSelected()) {
|
|
3139
|
-
return true;
|
|
3140
|
-
}
|
|
3141
|
-
if (hoveredCheckBox) {
|
|
3142
|
-
return true;
|
|
3143
|
-
}
|
|
3144
|
-
return false;
|
|
3238
|
+
// Merge default texts with provided defaults
|
|
3239
|
+
const mergedDefaultTexts = { ...DEFAULT_HEADER_TEXTS, ...defaultTexts };
|
|
3240
|
+
// Helper function to get text for a specific header
|
|
3241
|
+
const getHeaderText = (header, key) => {
|
|
3242
|
+
const columnMeta = header.column.columnDef.meta;
|
|
3243
|
+
return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
|
|
3145
3244
|
};
|
|
3146
3245
|
const getThProps = (header) => {
|
|
3147
3246
|
const thProps = header.column.getIsPinned()
|
|
@@ -3149,12 +3248,8 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
|
|
|
3149
3248
|
left: showSelector
|
|
3150
3249
|
? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3151
3250
|
: `${header.getStart("left")}px`,
|
|
3152
|
-
background: pinnedBgColor.light,
|
|
3153
3251
|
position: "sticky",
|
|
3154
3252
|
zIndex: 100 + 1,
|
|
3155
|
-
_dark: {
|
|
3156
|
-
backgroundColor: pinnedBgColor.dark,
|
|
3157
|
-
},
|
|
3158
3253
|
}
|
|
3159
3254
|
: {};
|
|
3160
3255
|
return thProps;
|
|
@@ -3163,21 +3258,13 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
|
|
|
3163
3258
|
position: "sticky",
|
|
3164
3259
|
top: 0,
|
|
3165
3260
|
};
|
|
3166
|
-
return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}), ...
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
zIndex: 1,
|
|
3174
|
-
_dark: { backgroundColor: pinnedBgColor.dark },
|
|
3175
|
-
}
|
|
3176
|
-
: {}),
|
|
3177
|
-
// styling resize and pinning end
|
|
3178
|
-
padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
|
|
3179
|
-
// indeterminate: table.getIsSomeRowsSelected(),
|
|
3180
|
-
onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsx(Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }))] })), headerGroup.headers.map((header) => {
|
|
3261
|
+
return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}), bgColor: "transparent", ...tableHeaderProps, children: table.getHeaderGroups().map((headerGroup) => (jsxs(Table$1.Row, { display: "flex", bgColor: "transparent", ...tableRowProps, children: [showSelector && (jsx(Table$1.ColumnHeader, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
|
|
3262
|
+
base: "colorPalette.900",
|
|
3263
|
+
_dark: "colorPalette.100",
|
|
3264
|
+
},
|
|
3265
|
+
bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: table.getIsAllRowsSelected(),
|
|
3266
|
+
// indeterminate: table.getIsSomeRowsSelected(),
|
|
3267
|
+
onChange: table.getToggleAllRowsSelectedHandler() }) })), headerGroup.headers.map((header) => {
|
|
3181
3268
|
const resizeProps = {
|
|
3182
3269
|
onMouseDown: header.getResizeHandler(),
|
|
3183
3270
|
onTouchStart: header.getResizeHandler(),
|
|
@@ -3185,18 +3272,32 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
|
|
|
3185
3272
|
};
|
|
3186
3273
|
return (jsxs(Table$1.ColumnHeader, { padding: 0, columnSpan: `${header.colSpan}`,
|
|
3187
3274
|
// styling resize and pinning start
|
|
3188
|
-
flex: `${canResize ? "0" : "1"} 0 ${header.column.getSize()}px`, display: "grid", gridTemplateColumns: "1fr auto", zIndex: 1500 + header.index,
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3275
|
+
flex: `${canResize ? "0" : "1"} 0 ${header.column.getSize()}px`, display: "grid", gridTemplateColumns: "1fr auto", zIndex: 1500 + header.index, color: {
|
|
3276
|
+
base: "colorPalette.800",
|
|
3277
|
+
_dark: "colorPalette.200",
|
|
3278
|
+
},
|
|
3279
|
+
bg: { base: "colorPalette.100", _dark: "colorPalette.900" }, ...getThProps(header), children: [jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Flex, { padding: `${table.getDensityValue()}px`, alignItems: "center", justifyContent: "start", borderRadius: "0rem", overflow: "auto", color: {
|
|
3280
|
+
base: "colorPalette.800",
|
|
3281
|
+
_dark: "colorPalette.200",
|
|
3282
|
+
_hover: {
|
|
3283
|
+
base: "colorPalette.700",
|
|
3284
|
+
_dark: "colorPalette.300",
|
|
3285
|
+
},
|
|
3286
|
+
},
|
|
3287
|
+
bg: {
|
|
3288
|
+
base: "colorPalette.100",
|
|
3289
|
+
_dark: "colorPalette.900",
|
|
3290
|
+
_hover: {
|
|
3291
|
+
base: "colorPalette.200",
|
|
3292
|
+
_dark: "colorPalette.800",
|
|
3192
3293
|
},
|
|
3193
3294
|
}, children: jsxs(Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
|
|
3194
3295
|
? null
|
|
3195
3296
|
: flexRender(header.column.columnDef.header, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && jsx(Fragment, {}), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) }), jsx(Box, { children: header.column.getIsFiltered() && jsx(MdFilterListAlt, {}) })] }) }) }), jsxs(MenuContent, { children: [!header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "pin-column", children: jsxs(Button, { variant: "ghost", onClick: () => {
|
|
3196
3297
|
header.column.pin("left");
|
|
3197
|
-
}, children: [jsx(MdPushPin, {}),
|
|
3298
|
+
}, children: [jsx(MdPushPin, {}), getHeaderText(header, "pinColumn")] }) })), header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxs(Button, { variant: "ghost", onClick: () => {
|
|
3198
3299
|
header.column.pin(false);
|
|
3199
|
-
}, children: [jsx(MdCancel, {}),
|
|
3300
|
+
}, children: [jsx(MdCancel, {}), getHeaderText(header, "cancelPin")] }) })), header.column.getCanSort() && (jsxs(Fragment, { children: [jsx(MenuItem, { asChild: true, value: "sort-ascend", children: jsxs(Button, { variant: "ghost", onClick: () => {
|
|
3200
3301
|
table.setSorting((state) => {
|
|
3201
3302
|
return [
|
|
3202
3303
|
...state.filter((column) => {
|
|
@@ -3205,7 +3306,7 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
|
|
|
3205
3306
|
{ id: header.id, desc: false },
|
|
3206
3307
|
];
|
|
3207
3308
|
});
|
|
3208
|
-
}, children: [jsx(GrAscend, {}),
|
|
3309
|
+
}, children: [jsx(GrAscend, {}), getHeaderText(header, "sortAscending")] }) }), jsx(MenuItem, { asChild: true, value: "sort-descend", children: jsxs(Button, { variant: "ghost", onClick: () => {
|
|
3209
3310
|
table.setSorting((state) => {
|
|
3210
3311
|
return [
|
|
3211
3312
|
...state.filter((column) => {
|
|
@@ -3214,42 +3315,30 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
|
|
|
3214
3315
|
{ id: header.id, desc: true },
|
|
3215
3316
|
];
|
|
3216
3317
|
});
|
|
3217
|
-
}, children: [jsx(GrDescend, {}),
|
|
3318
|
+
}, children: [jsx(GrDescend, {}), getHeaderText(header, "sortDescending")] }) }), header.column.getIsSorted() && (jsx(MenuItem, { asChild: true, value: "clear-sorting", children: jsxs(Button, { variant: "ghost", onClick: () => {
|
|
3218
3319
|
header.column.clearSorting();
|
|
3219
|
-
}, children: [jsx(MdClear, {}),
|
|
3320
|
+
}, children: [jsx(MdClear, {}), getHeaderText(header, "clearSorting")] }) }))] }))] })] }), canResize && (jsx(Box, { borderRight: "0.2rem solid", borderRightColor: header.column.getIsResizing()
|
|
3321
|
+
? "colorPalette.700"
|
|
3322
|
+
: "transparent", position: "relative", right: "0.1rem", width: "2px", height: "100%", userSelect: "none", style: { touchAction: "none" }, _hover: {
|
|
3220
3323
|
borderRightColor: header.column.getIsResizing()
|
|
3221
|
-
? "
|
|
3222
|
-
: "
|
|
3324
|
+
? "colorPalette.700"
|
|
3325
|
+
: "colorPalette.400",
|
|
3223
3326
|
}, ...resizeProps }))] }, `chakra-table-header-${header.id}`));
|
|
3224
3327
|
})] }, `chakra-table-headergroup-${headerGroup.id}`))) }));
|
|
3225
3328
|
};
|
|
3226
3329
|
|
|
3227
|
-
const
|
|
3228
|
-
const { title, description, icon, children, ...rest } = props;
|
|
3229
|
-
return (jsx(EmptyState$2.Root, { ref: ref, ...rest, children: jsxs(EmptyState$2.Content, { children: [icon && (jsx(EmptyState$2.Indicator, { children: icon })), description ? (jsxs(VStack, { textAlign: "center", children: [jsx(EmptyState$2.Title, { children: title }), jsx(EmptyState$2.Description, { children: description })] })) : (jsx(EmptyState$2.Title, { children: title })), children] }) }));
|
|
3230
|
-
});
|
|
3231
|
-
|
|
3232
|
-
const EmptyResult = (jsx(EmptyState, { icon: jsx(HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxs(List.Root, { variant: "marker", children: [jsx(List.Item, { children: "Try removing filters" }), jsx(List.Item, { children: "Try different keywords" })] }) }));
|
|
3233
|
-
const Table = ({ children, emptyComponent = EmptyResult, canResize = true, ...props }) => {
|
|
3234
|
-
const { table } = useDataTableContext();
|
|
3235
|
-
if (table.getRowModel().rows.length <= 0) {
|
|
3236
|
-
return emptyComponent;
|
|
3237
|
-
}
|
|
3238
|
-
return (jsx(Table$1.Root, { stickyHeader: true, variant: "outline", width: canResize ? table.getCenterTotalSize() : undefined, display: "grid", alignContent: "start", overflowY: "auto", ...props, children: children }));
|
|
3239
|
-
};
|
|
3240
|
-
|
|
3241
|
-
const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, controlProps = {}, tableFooterProps = {}, variant = "", }) => {
|
|
3330
|
+
const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = "", }) => {
|
|
3242
3331
|
if (variant === "greedy") {
|
|
3243
3332
|
return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { canResize: false, ...{ ...tableProps }, children: [jsx(TableHeader, { canResize: false, ...tableHeaderProps }), jsx(TableBody, { canResize: false, ...tableBodyProps }), showFooter && (jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
|
|
3244
3333
|
}
|
|
3245
3334
|
return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { ...tableProps, children: [jsx(TableHeader, { ...tableHeaderProps }), jsx(TableBody, { ...tableBodyProps }), showFooter && jsx(TableFooter, { ...tableFooterProps })] }) }));
|
|
3246
3335
|
};
|
|
3247
3336
|
|
|
3248
|
-
const TableCardContainer = ({ children, variant = "", ...props }) => {
|
|
3337
|
+
const TableCardContainer = ({ children, variant = "", gap = "1rem", gridTemplateColumns = "repeat(auto-fit, minmax(20rem, 1fr))", direction = "row", ...props }) => {
|
|
3249
3338
|
if (variant === "carousel") {
|
|
3250
|
-
return (jsx(Flex, { overflow: "
|
|
3339
|
+
return (jsx(Flex, { overflow: "auto", gap: gap, direction: direction, ...props, children: children }));
|
|
3251
3340
|
}
|
|
3252
|
-
return (jsx(Grid, { gridTemplateColumns:
|
|
3341
|
+
return (jsx(Grid, { gridTemplateColumns: gridTemplateColumns, gap: gap, ...props, children: children }));
|
|
3253
3342
|
};
|
|
3254
3343
|
|
|
3255
3344
|
const DefaultCardTitle = () => {
|
|
@@ -3278,8 +3367,8 @@ const TableComponent = ({ render = () => {
|
|
|
3278
3367
|
};
|
|
3279
3368
|
|
|
3280
3369
|
const TableLoadingComponent = ({ render, }) => {
|
|
3281
|
-
const {
|
|
3282
|
-
return jsx(Fragment, { children: render(
|
|
3370
|
+
const { query } = useDataTableServerContext();
|
|
3371
|
+
return jsx(Fragment, { children: render(query.isLoading) });
|
|
3283
3372
|
};
|
|
3284
3373
|
|
|
3285
3374
|
const SelectAllRowsToggle = ({ selectAllIcon = jsx(MdOutlineChecklist, {}), clearAllIcon = jsx(MdClear, {}), selectAllText = "", clearAllText = "", }) => {
|
|
@@ -3365,50 +3454,43 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3365
3454
|
};
|
|
3366
3455
|
};
|
|
3367
3456
|
|
|
3368
|
-
const useDataTableServer = (
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
pagination
|
|
3457
|
+
const useDataTableServer = (props) => {
|
|
3458
|
+
const { url, default: defaultProps, keyPrefix, placeholderData, queryFn: customQueryFn, } = props;
|
|
3459
|
+
const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
|
|
3460
|
+
const [sorting, setSorting] = useState(defaultSorting || []);
|
|
3461
|
+
const [columnFilters, setColumnFilters] = useState(defaultColumnFilters || []); // can set initial column filter state here
|
|
3462
|
+
const [pagination, setPagination] = useState(defaultPagination || {
|
|
3374
3463
|
pageIndex: 0, //initial page index
|
|
3375
|
-
pageSize: 10, //
|
|
3376
|
-
}
|
|
3377
|
-
rowSelection
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
}, keyPrefix, }) => {
|
|
3384
|
-
const [sorting, setSorting] = useState(defaultSorting);
|
|
3385
|
-
const [columnFilters, setColumnFilters] = useState(defaultColumnFilters); // can set initial column filter state here
|
|
3386
|
-
const [pagination, setPagination] = useState(defaultPagination);
|
|
3387
|
-
const [rowSelection, setRowSelection] = useState(defaultRowSelection);
|
|
3388
|
-
const [columnOrder, setColumnOrder] = useState(defaultColumnOrder);
|
|
3389
|
-
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter);
|
|
3390
|
-
const [density, setDensity] = useState(defaultDensity);
|
|
3391
|
-
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility);
|
|
3464
|
+
pageSize: 10, //default page size
|
|
3465
|
+
});
|
|
3466
|
+
const [rowSelection, setRowSelection] = useState(defaultRowSelection || {});
|
|
3467
|
+
const [columnOrder, setColumnOrder] = useState(defaultColumnOrder || []);
|
|
3468
|
+
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter || "");
|
|
3469
|
+
const [density, setDensity] = useState(defaultDensity || "sm");
|
|
3470
|
+
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility || {});
|
|
3471
|
+
const { pageSize, pageIndex } = pagination;
|
|
3392
3472
|
const params = {
|
|
3393
|
-
offset:
|
|
3394
|
-
limit:
|
|
3473
|
+
offset: pageIndex * pageSize,
|
|
3474
|
+
limit: pageSize,
|
|
3395
3475
|
sorting,
|
|
3396
3476
|
where: columnFilters,
|
|
3397
3477
|
searching: globalFilter,
|
|
3398
3478
|
};
|
|
3479
|
+
const defaultQueryFn = async () => {
|
|
3480
|
+
if (!url) {
|
|
3481
|
+
throw new Error("url is required");
|
|
3482
|
+
}
|
|
3483
|
+
const response = await axios.get(url, {
|
|
3484
|
+
params,
|
|
3485
|
+
});
|
|
3486
|
+
return response.data;
|
|
3487
|
+
};
|
|
3399
3488
|
const query = useQuery({
|
|
3400
3489
|
queryKey: [url, JSON.stringify(params)],
|
|
3401
|
-
queryFn:
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
})
|
|
3406
|
-
.then((res) => res.data);
|
|
3407
|
-
},
|
|
3408
|
-
placeholderData: {
|
|
3409
|
-
count: 0,
|
|
3410
|
-
data: [],
|
|
3411
|
-
},
|
|
3490
|
+
queryFn: customQueryFn !== undefined
|
|
3491
|
+
? () => customQueryFn(params)
|
|
3492
|
+
: defaultQueryFn,
|
|
3493
|
+
placeholderData,
|
|
3412
3494
|
});
|
|
3413
3495
|
const translate = useTranslation("", { keyPrefix });
|
|
3414
3496
|
return {
|
|
@@ -3498,7 +3580,71 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
|
|
|
3498
3580
|
return columns;
|
|
3499
3581
|
};
|
|
3500
3582
|
|
|
3501
|
-
const
|
|
3583
|
+
const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
3584
|
+
const { columns, translate, data } = useDataTableContext();
|
|
3585
|
+
const columnsMap = Object.fromEntries(columns.map((def) => {
|
|
3586
|
+
const { accessorKey, id } = def;
|
|
3587
|
+
if (accessorKey) {
|
|
3588
|
+
return [accessorKey, def];
|
|
3589
|
+
}
|
|
3590
|
+
return [id, def];
|
|
3591
|
+
}));
|
|
3592
|
+
const columnHeaders = Object.keys(columnsMap);
|
|
3593
|
+
const totalWidths = columns
|
|
3594
|
+
.map(({ size }) => {
|
|
3595
|
+
if (!!size === false) {
|
|
3596
|
+
return 0;
|
|
3597
|
+
}
|
|
3598
|
+
if (typeof size === "number") {
|
|
3599
|
+
return size;
|
|
3600
|
+
}
|
|
3601
|
+
return 0;
|
|
3602
|
+
})
|
|
3603
|
+
.reduce((previous, current) => previous + current, 0);
|
|
3604
|
+
const columnWidths = columns
|
|
3605
|
+
.map(({ size }) => {
|
|
3606
|
+
if (!!size === false) {
|
|
3607
|
+
return "1fr";
|
|
3608
|
+
}
|
|
3609
|
+
return `minmax(${size}px, ${(size / totalWidths) * 100}%)`;
|
|
3610
|
+
})
|
|
3611
|
+
.join(" ");
|
|
3612
|
+
console.log({ columnWidths }, "hadfg");
|
|
3613
|
+
const cellProps = {
|
|
3614
|
+
flex: "1 0 0%",
|
|
3615
|
+
overflow: "auto",
|
|
3616
|
+
paddingX: "2",
|
|
3617
|
+
py: "1",
|
|
3618
|
+
color: { base: "colorPalette.900", _dark: "colorPalette.100" },
|
|
3619
|
+
bgColor: { base: "colorPalette.50", _dark: "colorPalette.950" },
|
|
3620
|
+
borderBottomColor: { base: "colorPalette.200", _dark: "colorPalette.800" },
|
|
3621
|
+
borderBottomWidth: "1px",
|
|
3622
|
+
...{ colorPalette },
|
|
3623
|
+
};
|
|
3624
|
+
if (data.length <= 0) {
|
|
3625
|
+
return jsx(Fragment, { children: emptyComponent });
|
|
3626
|
+
}
|
|
3627
|
+
return (jsxs(Grid, { templateColumns: `${columnWidths}`, overflow: "auto", borderWidth: "1px", color: { base: "colorPalette.900", _dark: "colorPalette.100" }, borderColor: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: [jsx(Grid, { templateColumns: `${columnWidths}`, column: `1/span ${columns.length}`, bg: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: columnHeaders.map((header) => {
|
|
3628
|
+
return (jsx(Box, { flex: "1 0 0%", paddingX: "2", py: "1", overflow: "auto", textOverflow: "ellipsis", children: translate.t(`column_header.${header}`) }));
|
|
3629
|
+
}) }), data.map((record) => {
|
|
3630
|
+
return (jsx(Fragment, { children: columnHeaders.map((header) => {
|
|
3631
|
+
const { cell } = columnsMap[header];
|
|
3632
|
+
const value = record[header];
|
|
3633
|
+
if (!!record === false) {
|
|
3634
|
+
return (jsx(Box, { ...cellProps, children: translate.t(`column_cell.placeholder`) }));
|
|
3635
|
+
}
|
|
3636
|
+
if (cell) {
|
|
3637
|
+
return (jsx(Box, { ...cellProps, children: cell({ row: { original: record } }) }));
|
|
3638
|
+
}
|
|
3639
|
+
if (typeof value === "object") {
|
|
3640
|
+
return (jsx(Box, { ...cellProps, children: jsx(RecordDisplay, { object: value }) }));
|
|
3641
|
+
}
|
|
3642
|
+
return jsx(Box, { ...cellProps, children: value });
|
|
3643
|
+
}) }));
|
|
3644
|
+
})] }));
|
|
3645
|
+
};
|
|
3646
|
+
|
|
3647
|
+
const AccordionItemTrigger = React.forwardRef(function AccordionItemTrigger(props, ref) {
|
|
3502
3648
|
const { children, indicatorPlacement = "end", ...rest } = props;
|
|
3503
3649
|
return (jsxs(Accordion.ItemTrigger, { ...rest, ref: ref, children: [indicatorPlacement === "start" && (jsx(Accordion.ItemIndicator, { rotate: { base: "-90deg", _open: "0deg" }, children: jsx(LuChevronDown, {}) })), jsx(HStack, { gap: "4", flex: "1", textAlign: "start", width: "full", children: children }), indicatorPlacement === "end" && (jsx(Accordion.ItemIndicator, { children: jsx(LuChevronDown, {}) }))] }));
|
|
3504
3650
|
});
|
|
@@ -3519,6 +3665,12 @@ const SchemaFormContext = createContext({
|
|
|
3519
3665
|
onSubmit: async () => { },
|
|
3520
3666
|
rowNumber: 0,
|
|
3521
3667
|
requestOptions: {},
|
|
3668
|
+
timezone: 'Asia/Hong_Kong',
|
|
3669
|
+
displayConfig: {
|
|
3670
|
+
showSubmitButton: true,
|
|
3671
|
+
showResetButton: true,
|
|
3672
|
+
showTitle: true,
|
|
3673
|
+
},
|
|
3522
3674
|
});
|
|
3523
3675
|
|
|
3524
3676
|
const useSchemaContext = () => {
|
|
@@ -3529,6 +3681,24 @@ const clearEmptyString = (object) => {
|
|
|
3529
3681
|
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
3530
3682
|
};
|
|
3531
3683
|
|
|
3684
|
+
const validateData = (data, schema) => {
|
|
3685
|
+
const ajv = new Ajv({
|
|
3686
|
+
strict: false,
|
|
3687
|
+
allErrors: true,
|
|
3688
|
+
});
|
|
3689
|
+
addFormats(ajv);
|
|
3690
|
+
addErrors(ajv);
|
|
3691
|
+
const validate = ajv.compile(schema);
|
|
3692
|
+
const validationResult = validate(data);
|
|
3693
|
+
const errors = validate.errors;
|
|
3694
|
+
console.log(errors, data);
|
|
3695
|
+
return {
|
|
3696
|
+
isValid: validationResult,
|
|
3697
|
+
validate,
|
|
3698
|
+
errors,
|
|
3699
|
+
};
|
|
3700
|
+
};
|
|
3701
|
+
|
|
3532
3702
|
const idPickerSanityCheck = (column, foreign_key) => {
|
|
3533
3703
|
if (!!foreign_key == false) {
|
|
3534
3704
|
throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
|
|
@@ -3544,7 +3714,11 @@ const idPickerSanityCheck = (column, foreign_key) => {
|
|
|
3544
3714
|
throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
|
|
3545
3715
|
}
|
|
3546
3716
|
};
|
|
3547
|
-
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { },
|
|
3717
|
+
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, displayConfig = {
|
|
3718
|
+
showSubmitButton: true,
|
|
3719
|
+
showResetButton: true,
|
|
3720
|
+
showTitle: true,
|
|
3721
|
+
}, }) => {
|
|
3548
3722
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
3549
3723
|
const [isError, setIsError] = useState(false);
|
|
3550
3724
|
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
@@ -3577,11 +3751,13 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3577
3751
|
error,
|
|
3578
3752
|
setError,
|
|
3579
3753
|
getUpdatedData,
|
|
3754
|
+
customErrorRenderer,
|
|
3755
|
+
displayConfig,
|
|
3580
3756
|
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
3581
3757
|
};
|
|
3582
3758
|
|
|
3583
3759
|
function removeIndex(str) {
|
|
3584
|
-
return str.replace(/\.\d+\./g,
|
|
3760
|
+
return str.replace(/\.\d+\./g, ".");
|
|
3585
3761
|
}
|
|
3586
3762
|
|
|
3587
3763
|
const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
@@ -3593,13 +3769,17 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
3593
3769
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3594
3770
|
const { formState: { errors }, setValue, watch, } = useFormContext();
|
|
3595
3771
|
const fields = (watch(colLabel) ?? []);
|
|
3596
|
-
return (jsxs(
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3772
|
+
return (jsxs(Flex, { gridRow, gridColumn, flexFlow: "column", gap: 2, children: [jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Flex, { flexFlow: "column", gap: 2, children: fields.map((field, index) => (jsxs(Grid, { gridTemplateColumns: '1fr auto', gap: 2, bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
|
|
3773
|
+
base: "colorPalette.200",
|
|
3774
|
+
_dark: "colorPalette.800",
|
|
3775
|
+
}, children: [jsx(Grid, { gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsx(SchemaRenderer, { column: `${index}`,
|
|
3776
|
+
prefix: `${colLabel}.`,
|
|
3777
|
+
// @ts-expect-error find suitable types
|
|
3778
|
+
schema: { showLabel: false, ...(items ?? {}) } }) }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { variant: "ghost", onClick: () => {
|
|
3779
|
+
setValue(colLabel, fields.filter((_, curIndex) => {
|
|
3780
|
+
return curIndex !== index;
|
|
3781
|
+
}));
|
|
3782
|
+
}, children: jsx(Icon, { children: jsx(CgTrash, {}) }) }) })] }, `${colLabel}.${index}`))) }), jsx(Flex, { children: jsx(Button$1, { onClick: () => {
|
|
3603
3783
|
if (type === "number") {
|
|
3604
3784
|
setValue(colLabel, [...fields, 0]);
|
|
3605
3785
|
return;
|
|
@@ -3613,7 +3793,7 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
3613
3793
|
return;
|
|
3614
3794
|
}
|
|
3615
3795
|
setValue(colLabel, [...fields, {}]);
|
|
3616
|
-
}, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
3796
|
+
}, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
3617
3797
|
};
|
|
3618
3798
|
|
|
3619
3799
|
const Field = React.forwardRef(function Field(props, ref) {
|
|
@@ -3624,37 +3804,36 @@ const Field = React.forwardRef(function Field(props, ref) {
|
|
|
3624
3804
|
const BooleanPicker = ({ schema, column, prefix }) => {
|
|
3625
3805
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
3626
3806
|
const { translate } = useSchemaContext();
|
|
3627
|
-
const { required, gridColumn, gridRow } = schema;
|
|
3807
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
3628
3808
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3629
3809
|
const colLabel = `${prefix}${column}`;
|
|
3630
3810
|
const value = watch(colLabel);
|
|
3631
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
3811
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
3632
3812
|
gridRow, children: [jsx(CheckboxCard, { checked: value, variant: "surface", onChange: () => {
|
|
3633
3813
|
setValue(colLabel, !value);
|
|
3634
|
-
} }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
3814
|
+
} }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
3815
|
+
};
|
|
3816
|
+
|
|
3817
|
+
const CustomInput = ({ column, schema, prefix }) => {
|
|
3818
|
+
const formContext = useFormContext();
|
|
3819
|
+
const { inputRender } = schema;
|
|
3820
|
+
return (inputRender &&
|
|
3821
|
+
inputRender({
|
|
3822
|
+
column,
|
|
3823
|
+
schema,
|
|
3824
|
+
prefix,
|
|
3825
|
+
formContext,
|
|
3826
|
+
}));
|
|
3635
3827
|
};
|
|
3636
3828
|
|
|
3637
|
-
const monthNamesShort = [
|
|
3638
|
-
"Jan",
|
|
3639
|
-
"Feb",
|
|
3640
|
-
"Mar",
|
|
3641
|
-
"Apr",
|
|
3642
|
-
"May",
|
|
3643
|
-
"Jun",
|
|
3644
|
-
"Jul",
|
|
3645
|
-
"Aug",
|
|
3646
|
-
"Sep",
|
|
3647
|
-
"Oct",
|
|
3648
|
-
"Nov",
|
|
3649
|
-
"Dec",
|
|
3650
|
-
];
|
|
3651
|
-
const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
3652
3829
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
3830
|
+
const { labels } = useContext(DatePickerContext);
|
|
3831
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
3653
3832
|
if (calendars.length) {
|
|
3654
3833
|
return (jsxs(Grid, { children: [jsxs(Grid, { templateColumns: "repeat(4, auto)", justifyContent: "center", children: [jsx(Button$1, { variant: "ghost", ...getBackProps({
|
|
3655
3834
|
calendars,
|
|
3656
3835
|
offset: 12,
|
|
3657
|
-
}), children: "<<" }), jsx(Button$1, { variant: "ghost", ...getBackProps({ calendars }), children:
|
|
3836
|
+
}), children: "<<" }), jsx(Button$1, { variant: "ghost", ...getBackProps({ calendars }), children: backButtonLabel }), jsx(Button$1, { variant: "ghost", ...getForwardProps({ calendars }), children: forwardButtonLabel }), jsx(Button$1, { variant: "ghost", ...getForwardProps({
|
|
3658
3837
|
calendars,
|
|
3659
3838
|
offset: 12,
|
|
3660
3839
|
}), children: ">>" })] }), jsx(Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", children: calendars.map((calendar) => (jsxs(Grid, { gap: 4, children: [jsxs(Grid, { justifyContent: "center", children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsxs(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [[0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
@@ -3697,9 +3876,52 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
3697
3876
|
}
|
|
3698
3877
|
return null;
|
|
3699
3878
|
};
|
|
3879
|
+
const DatePickerContext = createContext({
|
|
3880
|
+
labels: {
|
|
3881
|
+
monthNamesShort: [
|
|
3882
|
+
"Jan",
|
|
3883
|
+
"Feb",
|
|
3884
|
+
"Mar",
|
|
3885
|
+
"Apr",
|
|
3886
|
+
"May",
|
|
3887
|
+
"Jun",
|
|
3888
|
+
"Jul",
|
|
3889
|
+
"Aug",
|
|
3890
|
+
"Sep",
|
|
3891
|
+
"Oct",
|
|
3892
|
+
"Nov",
|
|
3893
|
+
"Dec",
|
|
3894
|
+
],
|
|
3895
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
3896
|
+
backButtonLabel: "Back",
|
|
3897
|
+
forwardButtonLabel: "Next",
|
|
3898
|
+
},
|
|
3899
|
+
});
|
|
3700
3900
|
let DatePicker$1 = class DatePicker extends React__default.Component {
|
|
3701
3901
|
render() {
|
|
3702
|
-
|
|
3902
|
+
const { labels = {
|
|
3903
|
+
monthNamesShort: [
|
|
3904
|
+
"Jan",
|
|
3905
|
+
"Feb",
|
|
3906
|
+
"Mar",
|
|
3907
|
+
"Apr",
|
|
3908
|
+
"May",
|
|
3909
|
+
"Jun",
|
|
3910
|
+
"Jul",
|
|
3911
|
+
"Aug",
|
|
3912
|
+
"Sep",
|
|
3913
|
+
"Oct",
|
|
3914
|
+
"Nov",
|
|
3915
|
+
"Dec",
|
|
3916
|
+
],
|
|
3917
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
3918
|
+
backButtonLabel: "Back",
|
|
3919
|
+
forwardButtonLabel: "Next",
|
|
3920
|
+
}, } = this.props;
|
|
3921
|
+
return (jsx(DatePickerContext.Provider, { value: { labels }, children: jsx(Dayzed, { onDateSelected: this.props.onDateSelected, selected: this.props.selected, firstDayOfWeek: this.props.firstDayOfWeek, showOutsideDays: this.props.showOutsideDays, date: this.props.date, minDate: this.props.minDate, maxDate: this.props.maxDate, monthsToDisplay: this.props.monthsToDisplay, render:
|
|
3922
|
+
// @ts-expect-error - Dayzed types need to be fixed
|
|
3923
|
+
(dayzedData) => (jsx(Calendar, { ...dayzedData,
|
|
3924
|
+
firstDayOfWeek: this.props.firstDayOfWeek })) }) }));
|
|
3703
3925
|
}
|
|
3704
3926
|
};
|
|
3705
3927
|
|
|
@@ -3721,28 +3943,144 @@ const PopoverRoot = Popover.Root;
|
|
|
3721
3943
|
const PopoverBody = Popover.Body;
|
|
3722
3944
|
const PopoverTrigger = Popover.Trigger;
|
|
3723
3945
|
|
|
3946
|
+
/**
|
|
3947
|
+
* Custom hook to simplify i18n translation for form fields.
|
|
3948
|
+
* Automatically handles colLabel construction and removeIndex logic.
|
|
3949
|
+
*
|
|
3950
|
+
* @param column - The column name
|
|
3951
|
+
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
3952
|
+
* @returns Object with translation helper functions
|
|
3953
|
+
*
|
|
3954
|
+
* @example
|
|
3955
|
+
* ```tsx
|
|
3956
|
+
* const formI18n = useFormI18n(column, prefix);
|
|
3957
|
+
*
|
|
3958
|
+
* // Get field label
|
|
3959
|
+
* <Field label={formI18n.label()} />
|
|
3960
|
+
*
|
|
3961
|
+
* // Get error message
|
|
3962
|
+
* <Text>{formI18n.required()}</Text>
|
|
3963
|
+
*
|
|
3964
|
+
* // Get custom translation key
|
|
3965
|
+
* <Text>{formI18n.t('add_more')}</Text>
|
|
3966
|
+
*
|
|
3967
|
+
* // Access the raw colLabel
|
|
3968
|
+
* const colLabel = formI18n.colLabel;
|
|
3969
|
+
* ```
|
|
3970
|
+
*/
|
|
3971
|
+
const useFormI18n = (column, prefix = "") => {
|
|
3972
|
+
const { translate } = useSchemaContext();
|
|
3973
|
+
const colLabel = `${prefix}${column}`;
|
|
3974
|
+
return {
|
|
3975
|
+
/**
|
|
3976
|
+
* The constructed column label (prefix + column)
|
|
3977
|
+
*/
|
|
3978
|
+
colLabel,
|
|
3979
|
+
/**
|
|
3980
|
+
* Get the field label translation
|
|
3981
|
+
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
3982
|
+
*/
|
|
3983
|
+
label: (options) => {
|
|
3984
|
+
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
3985
|
+
},
|
|
3986
|
+
/**
|
|
3987
|
+
* Get the required error message translation
|
|
3988
|
+
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
|
|
3989
|
+
*/
|
|
3990
|
+
required: (options) => {
|
|
3991
|
+
return translate.t(removeIndex(`${colLabel}.field_required`), options);
|
|
3992
|
+
},
|
|
3993
|
+
/**
|
|
3994
|
+
* Get a translation for any custom key relative to the field
|
|
3995
|
+
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
3996
|
+
*
|
|
3997
|
+
* @param key - The translation key suffix (e.g., 'add_more', 'total', etc.)
|
|
3998
|
+
* @param options - Optional translation options (e.g., defaultValue, interpolation variables)
|
|
3999
|
+
*/
|
|
4000
|
+
t: (key, options) => {
|
|
4001
|
+
return translate.t(removeIndex(`${colLabel}.${key}`), options);
|
|
4002
|
+
},
|
|
4003
|
+
/**
|
|
4004
|
+
* Access to the original translate object for edge cases
|
|
4005
|
+
*/
|
|
4006
|
+
translate,
|
|
4007
|
+
};
|
|
4008
|
+
};
|
|
4009
|
+
|
|
4010
|
+
dayjs.extend(utc);
|
|
4011
|
+
dayjs.extend(timezone);
|
|
3724
4012
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
3725
4013
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
3726
|
-
const {
|
|
3727
|
-
const
|
|
4014
|
+
const { timezone } = useSchemaContext();
|
|
4015
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4016
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD", } = schema;
|
|
3728
4017
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3729
|
-
const colLabel =
|
|
4018
|
+
const colLabel = formI18n.colLabel;
|
|
3730
4019
|
const [open, setOpen] = useState(false);
|
|
3731
4020
|
const selectedDate = watch(colLabel);
|
|
3732
|
-
const
|
|
3733
|
-
|
|
3734
|
-
|
|
4021
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
4022
|
+
useEffect(() => {
|
|
4023
|
+
try {
|
|
4024
|
+
if (selectedDate) {
|
|
4025
|
+
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
4026
|
+
// For example, parse as UTC:
|
|
4027
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
4028
|
+
if (!parsedDate.isValid())
|
|
4029
|
+
return;
|
|
4030
|
+
// Format according to dateFormat from schema
|
|
4031
|
+
const formatted = parsedDate.format(dateFormat);
|
|
4032
|
+
// Update the form value only if different to avoid loops
|
|
4033
|
+
if (formatted !== selectedDate) {
|
|
4034
|
+
setValue(colLabel, formatted, {
|
|
4035
|
+
shouldValidate: true,
|
|
4036
|
+
shouldDirty: true,
|
|
4037
|
+
});
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
catch (e) {
|
|
4042
|
+
console.error(e);
|
|
4043
|
+
}
|
|
4044
|
+
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4045
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
|
|
4046
|
+
gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
3735
4047
|
setOpen(true);
|
|
3736
|
-
}, children: selectedDate !== undefined ? `${
|
|
3737
|
-
|
|
3738
|
-
, {
|
|
3739
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3740
|
-
selected: new Date(selectedDate),
|
|
3741
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3742
|
-
onDateSelected: ({ date }) => {
|
|
3743
|
-
setValue(colLabel, dayjs(date).format("YYYY-MM-DD"));
|
|
4048
|
+
}, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4049
|
+
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
3744
4050
|
setOpen(false);
|
|
3745
|
-
}
|
|
4051
|
+
}, labels: {
|
|
4052
|
+
monthNamesShort: [
|
|
4053
|
+
formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
4054
|
+
formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
4055
|
+
formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
4056
|
+
formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
4057
|
+
formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
4058
|
+
formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
4059
|
+
formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
4060
|
+
formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
4061
|
+
formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
4062
|
+
formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
4063
|
+
formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
4064
|
+
formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
4065
|
+
],
|
|
4066
|
+
weekdayNamesShort: [
|
|
4067
|
+
formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
4068
|
+
formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
4069
|
+
formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
4070
|
+
formI18n.translate.t(`common.weekday_4`, {
|
|
4071
|
+
defaultValue: "Wed",
|
|
4072
|
+
}),
|
|
4073
|
+
formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
4074
|
+
formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
4075
|
+
formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
4076
|
+
],
|
|
4077
|
+
backButtonLabel: formI18n.translate.t(`common.back_button`, {
|
|
4078
|
+
defaultValue: "Back",
|
|
4079
|
+
}),
|
|
4080
|
+
forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
|
|
4081
|
+
defaultValue: "Forward",
|
|
4082
|
+
}),
|
|
4083
|
+
} })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
|
|
3746
4084
|
};
|
|
3747
4085
|
|
|
3748
4086
|
function filterArray(array, searchTerm) {
|
|
@@ -3755,12 +4093,12 @@ function filterArray(array, searchTerm) {
|
|
|
3755
4093
|
});
|
|
3756
4094
|
}
|
|
3757
4095
|
|
|
3758
|
-
const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
4096
|
+
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
3759
4097
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
3760
4098
|
const { translate } = useSchemaContext();
|
|
3761
|
-
const { required } = schema;
|
|
4099
|
+
const { required, variant } = schema;
|
|
3762
4100
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3763
|
-
const { gridColumn, gridRow, renderDisplay } = schema;
|
|
4101
|
+
const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
|
|
3764
4102
|
const [searchText, setSearchText] = useState();
|
|
3765
4103
|
const [limit, setLimit] = useState(10);
|
|
3766
4104
|
const [openSearchResult, setOpenSearchResult] = useState();
|
|
@@ -3775,28 +4113,61 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
3775
4113
|
setSearchText(event.target.value);
|
|
3776
4114
|
setLimit(10);
|
|
3777
4115
|
};
|
|
3778
|
-
|
|
4116
|
+
if (variant === "radio") {
|
|
4117
|
+
return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4118
|
+
gridRow, children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? "").map((item) => {
|
|
4119
|
+
return (jsxs(RadioGroup$1.Item, { onClick: () => {
|
|
4120
|
+
if (!isMultiple) {
|
|
4121
|
+
setOpenSearchResult(false);
|
|
4122
|
+
setValue(colLabel, item);
|
|
4123
|
+
return;
|
|
4124
|
+
}
|
|
4125
|
+
const newSet = new Set([...(watchEnums ?? []), item]);
|
|
4126
|
+
setValue(colLabel, [...newSet]);
|
|
4127
|
+
}, value: item, children: [jsx(RadioGroup$1.ItemHiddenInput, {}), jsx(RadioGroup$1.ItemIndicator, {}), jsx(RadioGroup$1.ItemText, { children: !!renderDisplay === true
|
|
4128
|
+
? renderDisplay(item)
|
|
4129
|
+
: translate.t(removeIndex(`${colLabel}.${item}`)) })] }, `${colLabel}-${item}`));
|
|
4130
|
+
}) }) }) }));
|
|
4131
|
+
}
|
|
4132
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
3779
4133
|
gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchEnums.map((enumValue) => {
|
|
3780
4134
|
const item = enumValue;
|
|
3781
|
-
if (item ===
|
|
3782
|
-
return jsx(Fragment, {
|
|
4135
|
+
if (!!item === false) {
|
|
4136
|
+
return jsx(Fragment, {});
|
|
3783
4137
|
}
|
|
3784
|
-
return (jsx(Tag, { closable: true, onClick: () => {
|
|
3785
|
-
// setSelectedEnums((state) => state.filter((id) => id != item));
|
|
4138
|
+
return (jsx(Tag, { size: "lg", closable: true, onClick: () => {
|
|
3786
4139
|
setValue(column, watchEnums.filter((id) => id != item));
|
|
3787
4140
|
}, children: !!renderDisplay === true
|
|
3788
4141
|
? renderDisplay(item)
|
|
3789
|
-
: translate.t(removeIndex(`${colLabel}.${item}`)) }));
|
|
3790
|
-
}), jsx(Tag, { cursor: "pointer", onClick: () => {
|
|
4142
|
+
: translate.t(removeIndex(`${colLabel}.${item}`)) }, item));
|
|
4143
|
+
}), jsx(Tag, { size: "lg", cursor: "pointer", onClick: () => {
|
|
3791
4144
|
setOpenSearchResult(true);
|
|
3792
|
-
}, children: translate.t(removeIndex(`${colLabel}.
|
|
4145
|
+
}, children: translate.t(removeIndex(`${colLabel}.add_more`)) }, `${colLabel}-add-more-tag`)] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
|
|
3793
4146
|
setOpenSearchResult(true);
|
|
3794
|
-
}, children: watchEnum ===
|
|
4147
|
+
}, justifyContent: "start", children: !!watchEnum === false
|
|
3795
4148
|
? ""
|
|
3796
|
-
: translate.t(removeIndex(`${colLabel}.${watchEnum}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(`${
|
|
4149
|
+
: translate.t(removeIndex(`${colLabel}.${watchEnum ?? "null"}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { portalled: false, children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
|
|
3797
4150
|
onSearchChange(event);
|
|
3798
4151
|
setOpenSearchResult(true);
|
|
3799
|
-
}, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), jsx(Text, { children: `${translate.t(`${
|
|
4152
|
+
}, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), showTotalAndLimit && (jsx(Text, { children: `${translate.t(removeIndex(`${colLabel}.total`))}: ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` })), jsxs(Grid, { overflow: "auto", maxHeight: "20rem", children: [jsx(Flex, { flexFlow: "column wrap", children: dataList
|
|
4153
|
+
.filter((item) => {
|
|
4154
|
+
const searchTerm = (searchText || "").toLowerCase();
|
|
4155
|
+
if (!searchTerm)
|
|
4156
|
+
return true;
|
|
4157
|
+
// Check if the original enum value contains the search text
|
|
4158
|
+
const enumValueMatch = item
|
|
4159
|
+
.toLowerCase()
|
|
4160
|
+
.includes(searchTerm);
|
|
4161
|
+
// Check if the display value (translation) contains the search text
|
|
4162
|
+
const displayValue = !!renderDisplay === true
|
|
4163
|
+
? renderDisplay(item)
|
|
4164
|
+
: translate.t(removeIndex(`${colLabel}.${item}`));
|
|
4165
|
+
// Convert to string and check if it includes the search term
|
|
4166
|
+
const displayValueString = String(displayValue).toLowerCase();
|
|
4167
|
+
const displayValueMatch = displayValueString.includes(searchTerm);
|
|
4168
|
+
return enumValueMatch || displayValueMatch;
|
|
4169
|
+
})
|
|
4170
|
+
.map((item) => {
|
|
3800
4171
|
const selected = isMultiple
|
|
3801
4172
|
? watchEnums.some((enumValue) => item === enumValue)
|
|
3802
4173
|
: watchEnum == item;
|
|
@@ -3808,10 +4179,10 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
3808
4179
|
}
|
|
3809
4180
|
const newSet = new Set([...(watchEnums ?? []), item]);
|
|
3810
4181
|
setValue(colLabel, [...newSet]);
|
|
3811
|
-
}, ...(selected ? { color: "
|
|
4182
|
+
}, ...(selected ? { color: "colorPalette.400/50" } : {}), children: !!renderDisplay === true
|
|
3812
4183
|
? renderDisplay(item)
|
|
3813
4184
|
: translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
|
|
3814
|
-
}) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: translate.t(removeIndex(`${colLabel}.
|
|
4185
|
+
}) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
3815
4186
|
};
|
|
3816
4187
|
|
|
3817
4188
|
function isEnteringWindow(_ref) {
|
|
@@ -4163,17 +4534,17 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
|
|
|
4163
4534
|
const filesArray = [...event.target.files];
|
|
4164
4535
|
onDrop({ files: filesArray });
|
|
4165
4536
|
};
|
|
4166
|
-
return (jsxs(Grid, { ...getColor(isDraggedOver), ref: ref, cursor: "pointer", onClick: handleClick, borderStyle: "dashed", borderColor: "
|
|
4537
|
+
return (jsxs(Grid, { ...getColor(isDraggedOver), ref: ref, cursor: "pointer", onClick: handleClick, borderStyle: "dashed", borderColor: "colorPalette.400", alignContent: "center", justifyContent: "center", borderWidth: 1, borderRadius: 4, ...gridProps, children: [children, !!children === false && (jsxs(Fragment, { children: [jsx(Flex, { children: placeholder }), jsx(Input, { type: "file", multiple: true, style: { display: "none" }, ref: fileInput, onChange: handleChange })] }))] }));
|
|
4167
4538
|
};
|
|
4168
4539
|
|
|
4169
4540
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
4170
4541
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
4171
4542
|
const { translate } = useSchemaContext();
|
|
4172
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4543
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
|
|
4173
4544
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4174
4545
|
const currentFiles = (watch(column) ?? []);
|
|
4175
4546
|
const colLabel = `${prefix}${column}`;
|
|
4176
|
-
return (jsxs(Field, { label: `${translate.t(`${colLabel}.
|
|
4547
|
+
return (jsxs(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: [jsx(FileDropzone, { onDrop: ({ files }) => {
|
|
4177
4548
|
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
4178
4549
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
4179
4550
|
}, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
|
|
@@ -4181,10 +4552,19 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
4181
4552
|
setValue(column, currentFiles.filter(({ name }) => {
|
|
4182
4553
|
return name !== file.name;
|
|
4183
4554
|
}));
|
|
4184
|
-
}, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
|
|
4185
|
-
}) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
4555
|
+
}, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
|
|
4556
|
+
}) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4186
4557
|
};
|
|
4187
4558
|
|
|
4559
|
+
const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
|
|
4560
|
+
const { showArrow, children, portalled = true, content, portalRef, ...rest } = props;
|
|
4561
|
+
return (jsxs(Popover.Root, { ...rest, positioning: { ...rest.positioning, gutter: 4 }, children: [jsx(Popover.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Popover.Positioner, { children: jsxs(Popover.Content, { width: "auto", px: "2", py: "1", textStyle: "xs", rounded: "sm", ref: ref, children: [showArrow && (jsx(Popover.Arrow, { children: jsx(Popover.ArrowTip, {}) })), content] }) }) })] }));
|
|
4562
|
+
});
|
|
4563
|
+
const InfoTip = React.forwardRef(function InfoTip(props, ref) {
|
|
4564
|
+
const { children, ...rest } = props;
|
|
4565
|
+
return (jsx(ToggleTip, { content: children, ...rest, ref: ref, children: jsx(IconButton, { variant: "ghost", "aria-label": "info", size: "2xs", colorPalette: "colorPalette", children: jsx(HiOutlineInformationCircle, {}) }) }));
|
|
4566
|
+
});
|
|
4567
|
+
|
|
4188
4568
|
const getTableData = async ({ serverUrl, in_table, searching = "", where = [], limit = 10, offset = 0, }) => {
|
|
4189
4569
|
if (serverUrl === undefined || serverUrl.length == 0) {
|
|
4190
4570
|
throw new Error("The serverUrl is missing");
|
|
@@ -4215,25 +4595,40 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
|
|
|
4215
4595
|
|
|
4216
4596
|
const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
4217
4597
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4218
|
-
const { serverUrl, idMap, setIdMap,
|
|
4219
|
-
const
|
|
4598
|
+
const { serverUrl, idMap, setIdMap, schema: parentSchema, } = useSchemaContext();
|
|
4599
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4600
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
|
|
4220
4601
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4221
|
-
const { table, column: column_ref, display_column, } = foreign_key;
|
|
4222
|
-
const [searchText, setSearchText] = useState();
|
|
4602
|
+
const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
|
|
4603
|
+
const [searchText, setSearchText] = useState("");
|
|
4223
4604
|
const [limit, setLimit] = useState(10);
|
|
4224
4605
|
const [openSearchResult, setOpenSearchResult] = useState();
|
|
4225
4606
|
const [page, setPage] = useState(0);
|
|
4226
4607
|
const ref = useRef(null);
|
|
4227
|
-
const colLabel =
|
|
4608
|
+
const colLabel = formI18n.colLabel;
|
|
4609
|
+
const watchId = watch(colLabel);
|
|
4610
|
+
const watchIds = isMultiple ? (watch(colLabel) ?? []) : [];
|
|
4611
|
+
// Query for search results
|
|
4228
4612
|
const query = useQuery({
|
|
4229
4613
|
queryKey: [`idpicker`, { column, searchText, limit, page }],
|
|
4230
4614
|
queryFn: async () => {
|
|
4615
|
+
if (customQueryFn) {
|
|
4616
|
+
const { data, idMap } = await customQueryFn({
|
|
4617
|
+
searching: searchText ?? "",
|
|
4618
|
+
limit: limit,
|
|
4619
|
+
offset: page * limit,
|
|
4620
|
+
});
|
|
4621
|
+
setIdMap((state) => {
|
|
4622
|
+
return { ...state, ...idMap };
|
|
4623
|
+
});
|
|
4624
|
+
return data;
|
|
4625
|
+
}
|
|
4231
4626
|
const data = await getTableData({
|
|
4232
4627
|
serverUrl,
|
|
4233
4628
|
searching: searchText ?? "",
|
|
4234
4629
|
in_table: table,
|
|
4235
4630
|
limit: limit,
|
|
4236
|
-
offset: page *
|
|
4631
|
+
offset: page * limit,
|
|
4237
4632
|
});
|
|
4238
4633
|
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
4239
4634
|
return [
|
|
@@ -4248,27 +4643,38 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4248
4643
|
});
|
|
4249
4644
|
return data;
|
|
4250
4645
|
},
|
|
4251
|
-
enabled:
|
|
4646
|
+
enabled: openSearchResult === true,
|
|
4252
4647
|
staleTime: 300000,
|
|
4253
4648
|
});
|
|
4254
|
-
|
|
4255
|
-
const
|
|
4256
|
-
const count = data?.count ?? 0;
|
|
4257
|
-
const isDirty = (searchText?.length ?? 0) > 0;
|
|
4258
|
-
const watchId = watch(colLabel);
|
|
4259
|
-
const watchIds = (watch(colLabel) ?? []);
|
|
4260
|
-
useQuery({
|
|
4649
|
+
// Query for currently selected items (to display them properly)
|
|
4650
|
+
const queryDefault = useQuery({
|
|
4261
4651
|
queryKey: [
|
|
4262
|
-
`idpicker`,
|
|
4263
|
-
{ form: parentSchema.title, column,
|
|
4652
|
+
`idpicker-default`,
|
|
4653
|
+
{ form: parentSchema.title, column, id: isMultiple ? watchIds : watchId },
|
|
4264
4654
|
],
|
|
4265
4655
|
queryFn: async () => {
|
|
4656
|
+
if (customQueryFn) {
|
|
4657
|
+
const { data, idMap } = await customQueryFn({
|
|
4658
|
+
searching: watchIds.join(","),
|
|
4659
|
+
limit: isMultiple ? watchIds.length : 1,
|
|
4660
|
+
offset: 0,
|
|
4661
|
+
});
|
|
4662
|
+
setIdMap((state) => {
|
|
4663
|
+
return { ...state, ...idMap };
|
|
4664
|
+
});
|
|
4665
|
+
return data;
|
|
4666
|
+
}
|
|
4667
|
+
if (!watchId && (!watchIds || watchIds.length === 0)) {
|
|
4668
|
+
return { data: [] };
|
|
4669
|
+
}
|
|
4670
|
+
const searchValue = isMultiple ? watchIds.join(",") : watchId;
|
|
4266
4671
|
const data = await getTableData({
|
|
4267
4672
|
serverUrl,
|
|
4268
|
-
searching:
|
|
4673
|
+
searching: searchValue,
|
|
4269
4674
|
in_table: table,
|
|
4270
|
-
|
|
4271
|
-
|
|
4675
|
+
where: [{ id: column_ref, value: isMultiple ? watchIds : watchId }],
|
|
4676
|
+
limit: isMultiple ? watchIds.length : 1,
|
|
4677
|
+
offset: 0,
|
|
4272
4678
|
});
|
|
4273
4679
|
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
4274
4680
|
return [
|
|
@@ -4283,12 +4689,45 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4283
4689
|
});
|
|
4284
4690
|
return data;
|
|
4285
4691
|
},
|
|
4692
|
+
enabled: isMultiple
|
|
4693
|
+
? Array.isArray(watchIds) && watchIds.length > 0
|
|
4694
|
+
: !!watchId,
|
|
4286
4695
|
});
|
|
4696
|
+
// Effect to load selected values when component mounts
|
|
4697
|
+
useEffect(() => {
|
|
4698
|
+
if (isMultiple ? watchIds.length > 0 : !!watchId) {
|
|
4699
|
+
queryDefault.refetch();
|
|
4700
|
+
}
|
|
4701
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4702
|
+
}, []);
|
|
4703
|
+
// Effect to trigger initial data fetch when popover opens
|
|
4704
|
+
useEffect(() => {
|
|
4705
|
+
if (openSearchResult) {
|
|
4706
|
+
// Reset search text when opening the popover
|
|
4707
|
+
setSearchText("");
|
|
4708
|
+
// Reset page to first page
|
|
4709
|
+
setPage(0);
|
|
4710
|
+
// Fetch initial data
|
|
4711
|
+
query.refetch();
|
|
4712
|
+
}
|
|
4713
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4714
|
+
}, [openSearchResult]);
|
|
4287
4715
|
const onSearchChange = async (event) => {
|
|
4288
4716
|
setSearchText(event.target.value);
|
|
4289
4717
|
setPage(0);
|
|
4290
|
-
|
|
4718
|
+
query.refetch();
|
|
4719
|
+
};
|
|
4720
|
+
const handleLimitChange = (event) => {
|
|
4721
|
+
const newLimit = Number(event.target.value);
|
|
4722
|
+
setLimit(newLimit);
|
|
4723
|
+
// Reset to first page when changing limit
|
|
4724
|
+
setPage(0);
|
|
4725
|
+
// Trigger a new search with the updated limit
|
|
4726
|
+
query.refetch();
|
|
4291
4727
|
};
|
|
4728
|
+
const { isLoading, isFetching, data, isPending, isError } = query;
|
|
4729
|
+
const dataList = data?.data ?? [];
|
|
4730
|
+
const count = data?.count ?? 0;
|
|
4292
4731
|
const getPickedValue = () => {
|
|
4293
4732
|
if (Object.keys(idMap).length <= 0) {
|
|
4294
4733
|
return "";
|
|
@@ -4297,52 +4736,67 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4297
4736
|
if (record === undefined) {
|
|
4298
4737
|
return "";
|
|
4299
4738
|
}
|
|
4739
|
+
if (!!renderDisplay === true) {
|
|
4740
|
+
return renderDisplay(record);
|
|
4741
|
+
}
|
|
4300
4742
|
return record[display_column];
|
|
4301
4743
|
};
|
|
4302
|
-
return (jsxs(Field, { label:
|
|
4744
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
|
|
4303
4745
|
gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchIds.map((id) => {
|
|
4304
4746
|
const item = idMap[id];
|
|
4305
4747
|
if (item === undefined) {
|
|
4306
|
-
return (jsx(Text, { children:
|
|
4748
|
+
return (jsx(Text, { children: formI18n.t('undefined') }, id));
|
|
4307
4749
|
}
|
|
4308
4750
|
return (jsx(Tag, { closable: true, onClick: () => {
|
|
4309
|
-
setValue(
|
|
4751
|
+
setValue(colLabel, watchIds.filter((itemId) => itemId !== item[column_ref]));
|
|
4310
4752
|
}, children: !!renderDisplay === true
|
|
4311
4753
|
? renderDisplay(item)
|
|
4312
4754
|
: item[display_column] }, id));
|
|
4313
4755
|
}), jsx(Tag, { cursor: "pointer", onClick: () => {
|
|
4314
4756
|
setOpenSearchResult(true);
|
|
4315
|
-
}, children:
|
|
4757
|
+
}, children: formI18n.t('add_more') })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
|
|
4316
4758
|
setOpenSearchResult(true);
|
|
4317
|
-
}, children: getPickedValue() })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder:
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4759
|
+
}, justifyContent: "start", children: queryDefault.isLoading ? jsx(Spinner, { size: "sm" }) : getPickedValue() })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { portalled: false, children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: formI18n.t('type_to_search'), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsx(PopoverTitle, {}), openSearchResult && (jsxs(Fragment, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, {}), isError && (jsx(Icon, { color: "red.400", children: jsx(BiError, {}) })), jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxs(Flex, { alignItems: "center", gap: "2", children: [jsx(InfoTip, { children: `${formI18n.t('total')} ${count}, ${formI18n.t('showing')} ${limit} ${formI18n.t('per_page', { defaultValue: 'per page' })}` }), jsxs(Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxs(Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/", " ", count > 0
|
|
4760
|
+
? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}`
|
|
4761
|
+
: "0"] })] })] }), jsx(Box, { children: jsxs("select", { value: limit, onChange: handleLimitChange, style: {
|
|
4762
|
+
padding: "4px 8px",
|
|
4763
|
+
borderRadius: "4px",
|
|
4764
|
+
border: "1px solid #ccc",
|
|
4765
|
+
fontSize: "14px",
|
|
4766
|
+
}, children: [jsx("option", { value: "5", children: "5" }), jsx("option", { value: "10", children: "10" }), jsx("option", { value: "20", children: "20" }), jsx("option", { value: "30", children: "30" })] }) })] }), jsx(Grid, { overflowY: "auto", children: dataList.length > 0 ? (jsx(Flex, { flexFlow: "column wrap", gap: 1, children: dataList.map((item) => {
|
|
4767
|
+
const selected = isMultiple
|
|
4768
|
+
? watchIds.some((id) => item[column_ref] === id)
|
|
4769
|
+
: watchId === item[column_ref];
|
|
4770
|
+
return (jsx(Box, { cursor: "pointer", onClick: () => {
|
|
4771
|
+
if (!isMultiple) {
|
|
4772
|
+
setOpenSearchResult(false);
|
|
4773
|
+
setValue(colLabel, item[column_ref]);
|
|
4774
|
+
return;
|
|
4775
|
+
}
|
|
4776
|
+
// For multiple selection, don't add if already selected
|
|
4777
|
+
if (selected)
|
|
4778
|
+
return;
|
|
4779
|
+
const newSet = new Set([
|
|
4780
|
+
...(watchIds ?? []),
|
|
4781
|
+
item[column_ref],
|
|
4782
|
+
]);
|
|
4783
|
+
setValue(colLabel, [...newSet]);
|
|
4784
|
+
}, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
|
|
4785
|
+
? {
|
|
4786
|
+
color: "colorPalette.400/50",
|
|
4787
|
+
fontWeight: "bold",
|
|
4788
|
+
}
|
|
4789
|
+
: {}), children: !!renderDisplay === true
|
|
4790
|
+
? renderDisplay(item)
|
|
4791
|
+
: item[display_column] }, item[column_ref]));
|
|
4792
|
+
}) })) : (jsx(Text, { children: searchText
|
|
4793
|
+
? formI18n.t('empty_search_result')
|
|
4794
|
+
: formI18n.t('initial_results') })) }), jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
|
|
4341
4795
|
};
|
|
4342
4796
|
|
|
4343
4797
|
const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
|
|
4344
4798
|
const { children, ...rest } = props;
|
|
4345
|
-
return (
|
|
4799
|
+
return (jsx(NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: children }));
|
|
4346
4800
|
});
|
|
4347
4801
|
const NumberInputField$1 = NumberInput.Input;
|
|
4348
4802
|
NumberInput.Scrubber;
|
|
@@ -4351,17 +4805,17 @@ NumberInput.Label;
|
|
|
4351
4805
|
const NumberInputField = ({ schema, column, prefix, }) => {
|
|
4352
4806
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
4353
4807
|
const { translate } = useSchemaContext();
|
|
4354
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4808
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4355
4809
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4356
4810
|
const colLabel = `${prefix}${column}`;
|
|
4357
4811
|
const value = watch(`${colLabel}`);
|
|
4358
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
4812
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(NumberInputRoot, { children: jsx(NumberInputField$1, { required: isRequired, value: value, onChange: (event) => {
|
|
4359
4813
|
setValue(`${colLabel}`, Number(event.target.value));
|
|
4360
|
-
} }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
4814
|
+
} }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4361
4815
|
};
|
|
4362
4816
|
|
|
4363
4817
|
const ObjectInput = ({ schema, column, prefix }) => {
|
|
4364
|
-
const { properties,
|
|
4818
|
+
const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
|
|
4365
4819
|
const { translate } = useSchemaContext();
|
|
4366
4820
|
const colLabel = `${prefix}${column}`;
|
|
4367
4821
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
@@ -4369,25 +4823,28 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
4369
4823
|
if (properties === undefined) {
|
|
4370
4824
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
4371
4825
|
}
|
|
4372
|
-
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label",
|
|
4826
|
+
return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(Grid, { bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
|
|
4827
|
+
base: "colorPalette.200",
|
|
4828
|
+
_dark: "colorPalette.800",
|
|
4829
|
+
}, gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
|
|
4373
4830
|
return (
|
|
4374
4831
|
// @ts-expect-error find suitable types
|
|
4375
4832
|
jsx(ColumnRenderer, { column: `${key}`,
|
|
4376
4833
|
prefix: `${prefix}${column}.`,
|
|
4377
4834
|
properties }, `form-${colLabel}-${key}`));
|
|
4378
|
-
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
4835
|
+
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4379
4836
|
};
|
|
4380
4837
|
|
|
4381
4838
|
const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
4382
4839
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
4383
4840
|
const { translate } = useSchemaContext();
|
|
4384
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4841
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4385
4842
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4386
4843
|
const entries = Object.entries(getValues(column) ?? {});
|
|
4387
4844
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
4388
4845
|
const [newKey, setNewKey] = useState();
|
|
4389
4846
|
const [newValue, setNewValue] = useState();
|
|
4390
|
-
return (jsxs(Field, { label: `${translate.t(`${column}.
|
|
4847
|
+
return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
|
|
4391
4848
|
return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
4392
4849
|
const filtered = entries.filter(([target]) => {
|
|
4393
4850
|
return target !== key;
|
|
@@ -4427,16 +4884,16 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
|
4427
4884
|
setShowNewEntries(true);
|
|
4428
4885
|
setNewKey(undefined);
|
|
4429
4886
|
setNewValue(undefined);
|
|
4430
|
-
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.
|
|
4887
|
+
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
4431
4888
|
};
|
|
4432
4889
|
|
|
4433
4890
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
4434
4891
|
const { register, formState: { errors }, } = useFormContext();
|
|
4435
4892
|
const { translate } = useSchemaContext();
|
|
4436
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4893
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4437
4894
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4438
4895
|
const colLabel = `${prefix}${column}`;
|
|
4439
|
-
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
4896
|
+
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
|
|
4440
4897
|
};
|
|
4441
4898
|
|
|
4442
4899
|
const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
|
|
@@ -4534,9 +4991,574 @@ const TagPicker = ({ column, schema, prefix }) => {
|
|
|
4534
4991
|
}), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
|
|
4535
4992
|
};
|
|
4536
4993
|
|
|
4994
|
+
const Textarea = forwardRef(({ value, defaultValue, placeholder, onChange, onFocus, onBlur, disabled = false, readOnly = false, className, rows = 4, maxLength, autoFocus = false, invalid = false, required = false, label, helperText, errorText, ...props }, ref) => {
|
|
4995
|
+
const contentEditableRef = useRef(null);
|
|
4996
|
+
const isControlled = value !== undefined;
|
|
4997
|
+
// Handle input changes
|
|
4998
|
+
const handleInput = (e) => {
|
|
4999
|
+
const text = e.currentTarget.textContent || "";
|
|
5000
|
+
// Check maxLength if specified
|
|
5001
|
+
if (maxLength && text.length > maxLength) {
|
|
5002
|
+
e.currentTarget.textContent = text.slice(0, maxLength);
|
|
5003
|
+
// Move cursor to end
|
|
5004
|
+
const selection = window.getSelection();
|
|
5005
|
+
if (selection) {
|
|
5006
|
+
selection.selectAllChildren(e.currentTarget);
|
|
5007
|
+
selection.collapseToEnd();
|
|
5008
|
+
}
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
5011
|
+
onChange?.(text);
|
|
5012
|
+
};
|
|
5013
|
+
// Handle paste events to strip formatting and respect maxLength
|
|
5014
|
+
const handlePaste = (e) => {
|
|
5015
|
+
e.preventDefault();
|
|
5016
|
+
const text = e.clipboardData.getData('text/plain');
|
|
5017
|
+
const currentText = e.currentTarget.textContent || "";
|
|
5018
|
+
let pasteText = text;
|
|
5019
|
+
if (maxLength) {
|
|
5020
|
+
const remainingLength = maxLength - currentText.length;
|
|
5021
|
+
pasteText = text.slice(0, remainingLength);
|
|
5022
|
+
}
|
|
5023
|
+
document.execCommand('insertText', false, pasteText);
|
|
5024
|
+
};
|
|
5025
|
+
// Set initial content
|
|
5026
|
+
useEffect(() => {
|
|
5027
|
+
if (contentEditableRef.current && !isControlled) {
|
|
5028
|
+
const initialValue = defaultValue || "";
|
|
5029
|
+
if (contentEditableRef.current.textContent !== initialValue) {
|
|
5030
|
+
contentEditableRef.current.textContent = initialValue;
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5033
|
+
}, [defaultValue, isControlled]);
|
|
5034
|
+
// Update content when value changes (controlled mode)
|
|
5035
|
+
useEffect(() => {
|
|
5036
|
+
if (contentEditableRef.current && isControlled && value !== undefined) {
|
|
5037
|
+
if (contentEditableRef.current.textContent !== value) {
|
|
5038
|
+
contentEditableRef.current.textContent = value;
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
}, [value, isControlled]);
|
|
5042
|
+
// Auto focus
|
|
5043
|
+
useEffect(() => {
|
|
5044
|
+
if (autoFocus && contentEditableRef.current) {
|
|
5045
|
+
contentEditableRef.current.focus();
|
|
5046
|
+
}
|
|
5047
|
+
}, [autoFocus]);
|
|
5048
|
+
// Forward ref
|
|
5049
|
+
useEffect(() => {
|
|
5050
|
+
if (typeof ref === 'function') {
|
|
5051
|
+
ref(contentEditableRef.current);
|
|
5052
|
+
}
|
|
5053
|
+
else if (ref) {
|
|
5054
|
+
ref.current = contentEditableRef.current;
|
|
5055
|
+
}
|
|
5056
|
+
}, [ref]);
|
|
5057
|
+
const textareaElement = (jsx(Box, { ref: contentEditableRef, contentEditable: !disabled && !readOnly, onInput: handleInput, onPaste: handlePaste, onFocus: onFocus, onBlur: onBlur, className: className, minHeight: `${rows * 1.5}em`, padding: "2", border: "1px solid", borderColor: invalid ? "red.500" : "gray.200", borderRadius: "md", outline: "none", _focus: {
|
|
5058
|
+
borderColor: invalid ? "red.500" : "blue.500",
|
|
5059
|
+
boxShadow: `0 0 0 1px ${invalid ? "red.500" : "blue.500"}`,
|
|
5060
|
+
}, _disabled: {
|
|
5061
|
+
opacity: 0.6,
|
|
5062
|
+
cursor: "not-allowed",
|
|
5063
|
+
bg: "gray.50",
|
|
5064
|
+
}, _empty: {
|
|
5065
|
+
_before: {
|
|
5066
|
+
content: placeholder ? `"${placeholder}"` : undefined,
|
|
5067
|
+
color: "gray.400",
|
|
5068
|
+
pointerEvents: "none",
|
|
5069
|
+
}
|
|
5070
|
+
}, whiteSpace: "pre-wrap", overflowWrap: "break-word", overflow: "auto", maxHeight: `${rows * 4}em`, suppressContentEditableWarning: true, ...props }));
|
|
5071
|
+
// If we have additional field props, wrap in Field component
|
|
5072
|
+
if (label || helperText || errorText || required) {
|
|
5073
|
+
return (jsxs(Field$1.Root, { invalid: invalid, required: required, children: [label && (jsxs(Field$1.Label, { children: [label, required && jsx(Field$1.RequiredIndicator, {})] })), textareaElement, helperText && jsx(Field$1.HelperText, { children: helperText }), errorText && jsx(Field$1.ErrorText, { children: errorText })] }));
|
|
5074
|
+
}
|
|
5075
|
+
return textareaElement;
|
|
5076
|
+
});
|
|
5077
|
+
Textarea.displayName = "Textarea";
|
|
5078
|
+
|
|
5079
|
+
const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
5080
|
+
const { register, formState: { errors }, } = useFormContext();
|
|
5081
|
+
const { translate } = useSchemaContext();
|
|
5082
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
5083
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5084
|
+
const colLabel = `${prefix}${column}`;
|
|
5085
|
+
const form = useFormContext();
|
|
5086
|
+
const { setValue, watch } = form;
|
|
5087
|
+
const watchValue = watch(colLabel);
|
|
5088
|
+
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", children: [jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
|
|
5089
|
+
};
|
|
5090
|
+
|
|
5091
|
+
function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
|
|
5092
|
+
am: "am",
|
|
5093
|
+
pm: "pm",
|
|
5094
|
+
}, onChange = (_newValue) => { }, timezone = "Asia/Hong_Kong", }) {
|
|
5095
|
+
const handleClear = () => {
|
|
5096
|
+
setHour(null);
|
|
5097
|
+
setMinute(null);
|
|
5098
|
+
setMeridiem(null);
|
|
5099
|
+
setInputValue("");
|
|
5100
|
+
setShowInput(false);
|
|
5101
|
+
onChange({ hour: null, minute: null, meridiem: null });
|
|
5102
|
+
};
|
|
5103
|
+
const getTimeString = (hour, minute, meridiem) => {
|
|
5104
|
+
if (hour === null || minute === null || meridiem === null) {
|
|
5105
|
+
return "";
|
|
5106
|
+
}
|
|
5107
|
+
// if the hour is 24, set the hour to 0
|
|
5108
|
+
if (hour === 24) {
|
|
5109
|
+
return dayjs().tz(timezone).hour(0).minute(minute).format("HH:mmZ");
|
|
5110
|
+
}
|
|
5111
|
+
// use dayjs to format the time at current timezone
|
|
5112
|
+
// if meridiem is pm, add 12 hours
|
|
5113
|
+
let newHour = hour;
|
|
5114
|
+
if (meridiem === "pm" && hour !== 12) {
|
|
5115
|
+
newHour = hour + 12;
|
|
5116
|
+
}
|
|
5117
|
+
// if the hour is 12, set the meridiem to am, and set the hour to 0
|
|
5118
|
+
else if (meridiem === "am" && hour === 12) {
|
|
5119
|
+
newHour = 0;
|
|
5120
|
+
}
|
|
5121
|
+
return dayjs().tz(timezone).hour(newHour).minute(minute).format("HH:mmZ");
|
|
5122
|
+
};
|
|
5123
|
+
const stringTime = getTimeString(hour, minute, meridiem);
|
|
5124
|
+
const [inputValue, setInputValue] = useState("");
|
|
5125
|
+
const [showInput, setShowInput] = useState(false);
|
|
5126
|
+
const handleBlur = (text) => {
|
|
5127
|
+
// ignore all non-numeric characters
|
|
5128
|
+
if (!text) {
|
|
5129
|
+
return;
|
|
5130
|
+
}
|
|
5131
|
+
const value = text.replace(/[^0-9apm]/g, "");
|
|
5132
|
+
if (value === "") {
|
|
5133
|
+
handleClear();
|
|
5134
|
+
return;
|
|
5135
|
+
}
|
|
5136
|
+
// if the value is a valid time, parse it and set the hour, minute, and meridiem
|
|
5137
|
+
// if the value is not a valid time, set the stringTime to the value
|
|
5138
|
+
// first two characters are the hour
|
|
5139
|
+
// next two characters are the minute
|
|
5140
|
+
// final two characters are the meridiem
|
|
5141
|
+
const hour = parseInt(value.slice(0, 2));
|
|
5142
|
+
const minute = parseInt(value.slice(2, 4));
|
|
5143
|
+
const meridiem = value.slice(4, 6);
|
|
5144
|
+
// validate the hour and minute
|
|
5145
|
+
if (isNaN(hour) || isNaN(minute)) {
|
|
5146
|
+
setInputValue("");
|
|
5147
|
+
return;
|
|
5148
|
+
}
|
|
5149
|
+
// if the hour is larger than 24, set the hour to 24
|
|
5150
|
+
if (hour > 24) {
|
|
5151
|
+
setInputValue("");
|
|
5152
|
+
return;
|
|
5153
|
+
}
|
|
5154
|
+
let newHour = hour;
|
|
5155
|
+
let newMinute = minute;
|
|
5156
|
+
let newMeridiem = meridiem;
|
|
5157
|
+
// if the hour is 24, set the meridiem to am, and set the hour to 0
|
|
5158
|
+
if (hour === 24) {
|
|
5159
|
+
newMeridiem = "am";
|
|
5160
|
+
newHour = 0;
|
|
5161
|
+
}
|
|
5162
|
+
// if the hour is greater than 12, set the meridiem to pm, and subtract 12 from the hour
|
|
5163
|
+
else if (hour > 12) {
|
|
5164
|
+
newMeridiem = "pm";
|
|
5165
|
+
newHour = hour - 12;
|
|
5166
|
+
}
|
|
5167
|
+
// if the hour is 12, set the meridiem to pm, and set the hour to 12
|
|
5168
|
+
else if (hour === 12) {
|
|
5169
|
+
newMeridiem = "pm";
|
|
5170
|
+
newHour = 12;
|
|
5171
|
+
}
|
|
5172
|
+
// if the hour is 0, set the meridiem to am, and set the hour to 12
|
|
5173
|
+
else if (hour === 0) {
|
|
5174
|
+
newMeridiem = "am";
|
|
5175
|
+
newHour = 12;
|
|
5176
|
+
}
|
|
5177
|
+
else {
|
|
5178
|
+
newMeridiem = meridiem ?? "am";
|
|
5179
|
+
newHour = hour;
|
|
5180
|
+
}
|
|
5181
|
+
if (minute > 59) {
|
|
5182
|
+
newMinute = 0;
|
|
5183
|
+
}
|
|
5184
|
+
else {
|
|
5185
|
+
newMinute = minute;
|
|
5186
|
+
}
|
|
5187
|
+
onChange({
|
|
5188
|
+
hour: newHour,
|
|
5189
|
+
minute: newMinute,
|
|
5190
|
+
meridiem: newMeridiem,
|
|
5191
|
+
});
|
|
5192
|
+
setShowInput(false);
|
|
5193
|
+
};
|
|
5194
|
+
const handleKeyDown = (e) => {
|
|
5195
|
+
if (e.key === "Enter") {
|
|
5196
|
+
handleBlur(e.currentTarget.value);
|
|
5197
|
+
}
|
|
5198
|
+
};
|
|
5199
|
+
const inputRef = useRef(null);
|
|
5200
|
+
return (jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "200px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsx(Input, { onKeyDown: handleKeyDown, onChange: (e) => {
|
|
5201
|
+
setInputValue(e.currentTarget.value);
|
|
5202
|
+
}, onBlur: (e) => {
|
|
5203
|
+
handleBlur(e.currentTarget.value);
|
|
5204
|
+
}, onFocus: (e) => {
|
|
5205
|
+
e.currentTarget.select();
|
|
5206
|
+
}, value: inputValue, display: showInput ? undefined : "none", ref: inputRef }), jsxs(Button$1, { onClick: () => {
|
|
5207
|
+
setShowInput(true);
|
|
5208
|
+
setInputValue(dayjs(`1970-01-01T${getTimeString(hour, minute, meridiem)}`, "hh:mmZ").format("HH:mm"));
|
|
5209
|
+
inputRef.current?.focus();
|
|
5210
|
+
}, display: showInput ? "none" : "flex", alignItems: "center", justifyContent: "start", variant: "outline", gap: 2, children: [jsx(Icon, { size: "sm", children: jsx(BsClock, {}) }), jsx(Text, { fontSize: "sm", children: stringTime
|
|
5211
|
+
? dayjs(`1970-01-01T${stringTime}`, "hh:mmZ").format("hh:mm a")
|
|
5212
|
+
: "" })] }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }));
|
|
5213
|
+
}
|
|
5214
|
+
|
|
5215
|
+
dayjs.extend(timezone);
|
|
5216
|
+
const TimePicker = ({ column, schema, prefix }) => {
|
|
5217
|
+
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
5218
|
+
const { translate, timezone } = useSchemaContext();
|
|
5219
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
|
|
5220
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5221
|
+
const colLabel = `${prefix}${column}`;
|
|
5222
|
+
const [open, setOpen] = useState(false);
|
|
5223
|
+
const value = watch(colLabel);
|
|
5224
|
+
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
5225
|
+
? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
|
|
5226
|
+
: "";
|
|
5227
|
+
// Parse the initial time parts from the time string (HH:mm:ssZ)
|
|
5228
|
+
const parseTime = (time) => {
|
|
5229
|
+
if (!time)
|
|
5230
|
+
return { hour: 12, minute: 0, meridiem: "am" };
|
|
5231
|
+
const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
|
|
5232
|
+
if (!parsed.isValid()) {
|
|
5233
|
+
return { hour: 12, minute: 0, meridiem: "am" };
|
|
5234
|
+
}
|
|
5235
|
+
let hour = parsed.hour();
|
|
5236
|
+
const minute = parsed.minute();
|
|
5237
|
+
const meridiem = hour >= 12 ? "pm" : "am";
|
|
5238
|
+
if (hour === 0)
|
|
5239
|
+
hour = 12;
|
|
5240
|
+
else if (hour > 12)
|
|
5241
|
+
hour -= 12;
|
|
5242
|
+
return { hour, minute, meridiem };
|
|
5243
|
+
};
|
|
5244
|
+
const initialTime = parseTime(value);
|
|
5245
|
+
const [hour, setHour] = useState(initialTime.hour);
|
|
5246
|
+
const [minute, setMinute] = useState(initialTime.minute);
|
|
5247
|
+
const [meridiem, setMeridiem] = useState(initialTime.meridiem);
|
|
5248
|
+
useEffect(() => {
|
|
5249
|
+
const { hour, minute, meridiem } = parseTime(value);
|
|
5250
|
+
setHour(hour);
|
|
5251
|
+
setMinute(minute);
|
|
5252
|
+
setMeridiem(meridiem);
|
|
5253
|
+
}, [value]);
|
|
5254
|
+
const getTimeString = (hour, minute, meridiem) => {
|
|
5255
|
+
if (hour === null || minute === null || meridiem === null)
|
|
5256
|
+
return null;
|
|
5257
|
+
let newHour = hour;
|
|
5258
|
+
if (meridiem === "pm" && hour !== 12) {
|
|
5259
|
+
newHour = hour + 12;
|
|
5260
|
+
}
|
|
5261
|
+
return dayjs().tz(timezone).hour(newHour).minute(minute).second(0).format(timeFormat);
|
|
5262
|
+
};
|
|
5263
|
+
// Handle changes to time parts
|
|
5264
|
+
const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
|
|
5265
|
+
setHour(newHour);
|
|
5266
|
+
setMinute(newMinute);
|
|
5267
|
+
setMeridiem(newMeridiem);
|
|
5268
|
+
const timeString = getTimeString(newHour, newMinute, newMeridiem);
|
|
5269
|
+
setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
|
|
5270
|
+
};
|
|
5271
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5272
|
+
gridRow, children: [jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
5273
|
+
setOpen(true);
|
|
5274
|
+
}, justifyContent: "start", children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ""] }) }), jsx(Popover.Positioner, { children: jsx(Popover.Content, { children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
|
|
5275
|
+
am: translate.t(`common.am`, { defaultValue: "AM" }),
|
|
5276
|
+
pm: translate.t(`common.pm`, { defaultValue: "PM" }),
|
|
5277
|
+
} }) }) }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
5278
|
+
};
|
|
5279
|
+
|
|
5280
|
+
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
|
|
5281
|
+
// Refs for focus management
|
|
5282
|
+
const hourInputRef = useRef(null);
|
|
5283
|
+
const minuteInputRef = useRef(null);
|
|
5284
|
+
const secondInputRef = useRef(null);
|
|
5285
|
+
// Centralized handler for key events, value changes, and focus management
|
|
5286
|
+
const handleKeyDown = (e, field) => {
|
|
5287
|
+
const input = e.target;
|
|
5288
|
+
const value = input.value;
|
|
5289
|
+
// Handle navigation between fields
|
|
5290
|
+
if (e.key === "Tab") {
|
|
5291
|
+
return;
|
|
5292
|
+
}
|
|
5293
|
+
if (e.key === ":" && field === "hour") {
|
|
5294
|
+
e.preventDefault();
|
|
5295
|
+
minuteInputRef.current?.focus();
|
|
5296
|
+
return;
|
|
5297
|
+
}
|
|
5298
|
+
if (e.key === ":" && field === "minute") {
|
|
5299
|
+
e.preventDefault();
|
|
5300
|
+
secondInputRef.current?.focus();
|
|
5301
|
+
return;
|
|
5302
|
+
}
|
|
5303
|
+
if (e.key === "Backspace" && value === "") {
|
|
5304
|
+
e.preventDefault();
|
|
5305
|
+
if (field === "minute") {
|
|
5306
|
+
hourInputRef.current?.focus();
|
|
5307
|
+
}
|
|
5308
|
+
else if (field === "second") {
|
|
5309
|
+
minuteInputRef.current?.focus();
|
|
5310
|
+
}
|
|
5311
|
+
return;
|
|
5312
|
+
}
|
|
5313
|
+
// Handle number inputs
|
|
5314
|
+
if (field === "hour") {
|
|
5315
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5316
|
+
const newValue = value + e.key;
|
|
5317
|
+
const numValue = parseInt(newValue, 10);
|
|
5318
|
+
if (numValue > 23) {
|
|
5319
|
+
const digitValue = parseInt(e.key, 10);
|
|
5320
|
+
setHour(digitValue);
|
|
5321
|
+
onChange({ hour: digitValue, minute, second });
|
|
5322
|
+
return;
|
|
5323
|
+
}
|
|
5324
|
+
if (numValue >= 0 && numValue <= 23) {
|
|
5325
|
+
setHour(numValue);
|
|
5326
|
+
onChange({ hour: numValue, minute, second });
|
|
5327
|
+
e.preventDefault();
|
|
5328
|
+
minuteInputRef.current?.focus();
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5331
|
+
}
|
|
5332
|
+
else if (field === "minute") {
|
|
5333
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5334
|
+
const newValue = value + e.key;
|
|
5335
|
+
const numValue = parseInt(newValue, 10);
|
|
5336
|
+
if (numValue > 59) {
|
|
5337
|
+
const digitValue = parseInt(e.key, 10);
|
|
5338
|
+
setMinute(digitValue);
|
|
5339
|
+
onChange({ hour, minute: digitValue, second });
|
|
5340
|
+
return;
|
|
5341
|
+
}
|
|
5342
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5343
|
+
setMinute(numValue);
|
|
5344
|
+
onChange({ hour, minute: numValue, second });
|
|
5345
|
+
e.preventDefault();
|
|
5346
|
+
secondInputRef.current?.focus();
|
|
5347
|
+
}
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
else if (field === "second") {
|
|
5351
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5352
|
+
const newValue = value + e.key;
|
|
5353
|
+
const numValue = parseInt(newValue, 10);
|
|
5354
|
+
if (numValue > 59) {
|
|
5355
|
+
const digitValue = parseInt(e.key, 10);
|
|
5356
|
+
setSecond(digitValue);
|
|
5357
|
+
onChange({ hour, minute, second: digitValue });
|
|
5358
|
+
return;
|
|
5359
|
+
}
|
|
5360
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5361
|
+
setSecond(numValue);
|
|
5362
|
+
onChange({ hour, minute, second: numValue });
|
|
5363
|
+
}
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
};
|
|
5367
|
+
const handleClear = () => {
|
|
5368
|
+
setHour(null);
|
|
5369
|
+
setMinute(null);
|
|
5370
|
+
setSecond(null);
|
|
5371
|
+
onChange({ hour: null, minute: null, second: null });
|
|
5372
|
+
hourInputRef.current?.focus();
|
|
5373
|
+
};
|
|
5374
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 10px 60px auto", gap: "2", width: "auto", minWidth: "300px", children: [jsx(Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), placeholder: "HH", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), placeholder: "MM", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: secondInputRef, type: "text", value: second === null ? "" : second.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "second"), placeholder: "SS", maxLength: 2, textAlign: "center" }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }) }));
|
|
5375
|
+
}
|
|
5376
|
+
|
|
5377
|
+
function DateTimePicker$1({ value, onChange, format = "date-time", showSeconds = false, labels = {
|
|
5378
|
+
monthNamesShort: [
|
|
5379
|
+
"Jan",
|
|
5380
|
+
"Feb",
|
|
5381
|
+
"Mar",
|
|
5382
|
+
"Apr",
|
|
5383
|
+
"May",
|
|
5384
|
+
"Jun",
|
|
5385
|
+
"Jul",
|
|
5386
|
+
"Aug",
|
|
5387
|
+
"Sep",
|
|
5388
|
+
"Oct",
|
|
5389
|
+
"Nov",
|
|
5390
|
+
"Dec",
|
|
5391
|
+
],
|
|
5392
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
5393
|
+
backButtonLabel: "Back",
|
|
5394
|
+
forwardButtonLabel: "Next",
|
|
5395
|
+
}, timezone = "Asia/Hong_Kong", }) {
|
|
5396
|
+
const [selectedDate, setSelectedDate] = useState(value || "");
|
|
5397
|
+
// Time state for 12-hour format
|
|
5398
|
+
const [hour12, setHour12] = useState(value ? dayjs(value).hour() % 12 || 12 : null);
|
|
5399
|
+
const [minute, setMinute] = useState(value ? dayjs(value).minute() : null);
|
|
5400
|
+
const [meridiem, setMeridiem] = useState(value ? (dayjs(value).hour() >= 12 ? "pm" : "am") : null);
|
|
5401
|
+
// Time state for 24-hour format
|
|
5402
|
+
const [hour24, setHour24] = useState(value ? dayjs(value).hour() : null);
|
|
5403
|
+
const [second, setSecond] = useState(value ? dayjs(value).second() : null);
|
|
5404
|
+
const handleDateChange = (date) => {
|
|
5405
|
+
setSelectedDate(date);
|
|
5406
|
+
updateDateTime(dayjs(date).tz(timezone).toISOString());
|
|
5407
|
+
};
|
|
5408
|
+
const handleTimeChange = (timeData) => {
|
|
5409
|
+
if (format === "iso-date-time") {
|
|
5410
|
+
setHour24(timeData.hour);
|
|
5411
|
+
setMinute(timeData.minute);
|
|
5412
|
+
if (showSeconds)
|
|
5413
|
+
setSecond(timeData.second);
|
|
5414
|
+
}
|
|
5415
|
+
else {
|
|
5416
|
+
setHour12(timeData.hour);
|
|
5417
|
+
setMinute(timeData.minute);
|
|
5418
|
+
setMeridiem(timeData.meridiem);
|
|
5419
|
+
}
|
|
5420
|
+
updateDateTime(dayjs(selectedDate).tz(timezone).toISOString(), timeData);
|
|
5421
|
+
};
|
|
5422
|
+
const updateDateTime = (date, timeData) => {
|
|
5423
|
+
if (!date) {
|
|
5424
|
+
onChange?.(undefined);
|
|
5425
|
+
return;
|
|
5426
|
+
}
|
|
5427
|
+
// use dayjs to convert the date to the timezone
|
|
5428
|
+
const newDate = dayjs(date).tz(timezone).toDate();
|
|
5429
|
+
if (format === "iso-date-time") {
|
|
5430
|
+
const h = timeData?.hour ?? hour24;
|
|
5431
|
+
const m = timeData?.minute ?? minute;
|
|
5432
|
+
const s = showSeconds ? timeData?.second ?? second : 0;
|
|
5433
|
+
if (h !== null)
|
|
5434
|
+
newDate.setHours(h);
|
|
5435
|
+
if (m !== null)
|
|
5436
|
+
newDate.setMinutes(m);
|
|
5437
|
+
if (s !== null)
|
|
5438
|
+
newDate.setSeconds(s);
|
|
5439
|
+
}
|
|
5440
|
+
else {
|
|
5441
|
+
const h = timeData?.hour ?? hour12;
|
|
5442
|
+
const m = timeData?.minute ?? minute;
|
|
5443
|
+
const mer = timeData?.meridiem ?? meridiem;
|
|
5444
|
+
if (h !== null && mer !== null) {
|
|
5445
|
+
let hour24 = h;
|
|
5446
|
+
if (mer === "am" && h === 12)
|
|
5447
|
+
hour24 = 0;
|
|
5448
|
+
else if (mer === "pm" && h < 12)
|
|
5449
|
+
hour24 = h + 12;
|
|
5450
|
+
newDate.setHours(hour24);
|
|
5451
|
+
}
|
|
5452
|
+
if (m !== null)
|
|
5453
|
+
newDate.setMinutes(m);
|
|
5454
|
+
newDate.setSeconds(0);
|
|
5455
|
+
}
|
|
5456
|
+
onChange?.(dayjs(newDate).tz(timezone).toISOString());
|
|
5457
|
+
};
|
|
5458
|
+
const handleClear = () => {
|
|
5459
|
+
setSelectedDate("");
|
|
5460
|
+
setHour12(null);
|
|
5461
|
+
setHour24(null);
|
|
5462
|
+
setMinute(null);
|
|
5463
|
+
setSecond(null);
|
|
5464
|
+
setMeridiem(null);
|
|
5465
|
+
onChange?.(undefined);
|
|
5466
|
+
};
|
|
5467
|
+
const isISO = format === "iso-date-time";
|
|
5468
|
+
return (jsxs(Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsx(DatePicker$1, { selected: selectedDate
|
|
5469
|
+
? dayjs(selectedDate).tz(timezone).toDate()
|
|
5470
|
+
: new Date(), onDateSelected: ({ date }) => handleDateChange(dayjs(date).tz(timezone).toISOString()), monthsToDisplay: 1, labels: labels }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: second, setSecond: setSecond, onChange: handleTimeChange })) : (jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), selectedDate && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).format(isISO
|
|
5471
|
+
? showSeconds
|
|
5472
|
+
? "YYYY-MM-DD HH:mm:ss"
|
|
5473
|
+
: "YYYY-MM-DD HH:mm"
|
|
5474
|
+
: "YYYY-MM-DD hh:mm A ") }), jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).tz(timezone).format("Z") }), jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: timezone })] }))] }));
|
|
5475
|
+
}
|
|
5476
|
+
|
|
5477
|
+
dayjs.extend(utc);
|
|
5478
|
+
dayjs.extend(timezone);
|
|
5479
|
+
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
5480
|
+
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
5481
|
+
const { timezone } = useSchemaContext();
|
|
5482
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5483
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
|
|
5484
|
+
// with timezone
|
|
5485
|
+
dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
|
|
5486
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5487
|
+
const colLabel = formI18n.colLabel;
|
|
5488
|
+
const [open, setOpen] = useState(false);
|
|
5489
|
+
const selectedDate = watch(colLabel);
|
|
5490
|
+
const displayDate = dayjs(selectedDate)
|
|
5491
|
+
.tz(timezone)
|
|
5492
|
+
.format(displayDateFormat);
|
|
5493
|
+
useEffect(() => {
|
|
5494
|
+
try {
|
|
5495
|
+
if (selectedDate) {
|
|
5496
|
+
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
5497
|
+
// For example, parse as UTC:
|
|
5498
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
5499
|
+
if (!parsedDate.isValid())
|
|
5500
|
+
return;
|
|
5501
|
+
// Format according to dateFormat from schema
|
|
5502
|
+
const formatted = parsedDate.format(dateFormat);
|
|
5503
|
+
// Update the form value only if different to avoid loops
|
|
5504
|
+
if (formatted !== selectedDate) {
|
|
5505
|
+
setValue(colLabel, formatted, {
|
|
5506
|
+
shouldValidate: true,
|
|
5507
|
+
shouldDirty: true,
|
|
5508
|
+
});
|
|
5509
|
+
}
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
catch (e) {
|
|
5513
|
+
console.error(e);
|
|
5514
|
+
}
|
|
5515
|
+
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
5516
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
|
|
5517
|
+
gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
5518
|
+
setOpen(true);
|
|
5519
|
+
}, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { minW: "450px", children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
5520
|
+
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
5521
|
+
}, timezone: timezone, labels: {
|
|
5522
|
+
monthNamesShort: [
|
|
5523
|
+
formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
5524
|
+
formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
5525
|
+
formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
5526
|
+
formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
5527
|
+
formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
5528
|
+
formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
5529
|
+
formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
5530
|
+
formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
5531
|
+
formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
5532
|
+
formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
5533
|
+
formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
5534
|
+
formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
5535
|
+
],
|
|
5536
|
+
weekdayNamesShort: [
|
|
5537
|
+
formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
5538
|
+
formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
5539
|
+
formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
5540
|
+
formI18n.translate.t(`common.weekday_4`, {
|
|
5541
|
+
defaultValue: "Wed",
|
|
5542
|
+
}),
|
|
5543
|
+
formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
5544
|
+
formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
5545
|
+
formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
5546
|
+
],
|
|
5547
|
+
backButtonLabel: formI18n.translate.t(`common.back_button`, {
|
|
5548
|
+
defaultValue: "Back",
|
|
5549
|
+
}),
|
|
5550
|
+
forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
|
|
5551
|
+
defaultValue: "Forward",
|
|
5552
|
+
}),
|
|
5553
|
+
} })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
|
|
5554
|
+
};
|
|
5555
|
+
|
|
4537
5556
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
4538
5557
|
const colSchema = schema;
|
|
4539
|
-
const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
|
|
5558
|
+
const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
|
|
5559
|
+
if (variant === "custom-input") {
|
|
5560
|
+
return jsx(CustomInput, { schema: colSchema, prefix, column });
|
|
5561
|
+
}
|
|
4540
5562
|
if (type === "string") {
|
|
4541
5563
|
if ((schema.enum ?? []).length > 0) {
|
|
4542
5564
|
return jsx(EnumPicker, { schema: colSchema, prefix, column });
|
|
@@ -4545,9 +5567,18 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
4545
5567
|
idPickerSanityCheck(column, foreign_key);
|
|
4546
5568
|
return jsx(IdPicker, { schema: colSchema, prefix, column });
|
|
4547
5569
|
}
|
|
4548
|
-
if (
|
|
5570
|
+
if (format === "date") {
|
|
4549
5571
|
return jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
4550
5572
|
}
|
|
5573
|
+
if (format === "time") {
|
|
5574
|
+
return jsx(TimePicker, { schema: colSchema, prefix, column });
|
|
5575
|
+
}
|
|
5576
|
+
if (format === "date-time") {
|
|
5577
|
+
return jsx(DateTimePicker, { schema: colSchema, prefix, column });
|
|
5578
|
+
}
|
|
5579
|
+
if (variant === "text-area") {
|
|
5580
|
+
return jsx(TextAreaInput, { schema: colSchema, prefix, column });
|
|
5581
|
+
}
|
|
4551
5582
|
return jsx(StringInputField, { schema: colSchema, prefix, column });
|
|
4552
5583
|
}
|
|
4553
5584
|
if (type === "number" || type === "integer") {
|
|
@@ -4573,6 +5604,15 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
4573
5604
|
if (variant === "file-picker") {
|
|
4574
5605
|
return jsx(FilePicker, { schema: colSchema, prefix, column });
|
|
4575
5606
|
}
|
|
5607
|
+
if (variant === "enum-picker") {
|
|
5608
|
+
const { items } = colSchema;
|
|
5609
|
+
const { enum: enumItems } = items;
|
|
5610
|
+
const enumSchema = {
|
|
5611
|
+
type: "string",
|
|
5612
|
+
enum: enumItems,
|
|
5613
|
+
};
|
|
5614
|
+
return (jsx(EnumPicker, { isMultiple: true, schema: enumSchema, prefix, column }));
|
|
5615
|
+
}
|
|
4576
5616
|
if (items) {
|
|
4577
5617
|
return jsx(ArrayRenderer, { schema: colSchema, prefix, column });
|
|
4578
5618
|
}
|
|
@@ -4594,85 +5634,95 @@ const ColumnRenderer = ({ column, properties, prefix, }) => {
|
|
|
4594
5634
|
};
|
|
4595
5635
|
|
|
4596
5636
|
const ArrayViewer = ({ schema, column, prefix }) => {
|
|
4597
|
-
const {
|
|
5637
|
+
const { gridColumn = "span 12", gridRow = "span 1", required, items, } = schema;
|
|
4598
5638
|
const { translate } = useSchemaContext();
|
|
4599
5639
|
const colLabel = `${prefix}${column}`;
|
|
4600
5640
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4601
5641
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4602
5642
|
const values = watch(colLabel) ?? [];
|
|
4603
|
-
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.
|
|
4604
|
-
|
|
4605
|
-
|
|
5643
|
+
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Flex, { flexFlow: "column", gap: 1, children: values.map((field, index) => (jsx(Flex, { flexFlow: "column", bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: "2", borderRadius: "md", borderWidth: "thin", borderColor: {
|
|
5644
|
+
base: "colorPalette.200",
|
|
5645
|
+
_dark: "colorPalette.800",
|
|
5646
|
+
}, children: jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsx(SchemaViewer, { column: `${index}`,
|
|
5647
|
+
prefix: `${colLabel}.`,
|
|
5648
|
+
// @ts-expect-error find suitable types
|
|
5649
|
+
schema: { showLabel: false, ...(items ?? {}) } }) }) }, `form-${prefix}${column}.${index}`))) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4606
5650
|
};
|
|
4607
5651
|
|
|
4608
5652
|
const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
4609
5653
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4610
5654
|
const { translate } = useSchemaContext();
|
|
4611
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5655
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4612
5656
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4613
5657
|
const colLabel = `${prefix}${column}`;
|
|
4614
5658
|
const value = watch(colLabel);
|
|
4615
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
5659
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4616
5660
|
gridRow, children: [jsx(Text, { children: value
|
|
4617
5661
|
? translate.t(removeIndex(`${colLabel}.true`))
|
|
4618
|
-
: translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
5662
|
+
: translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
5663
|
+
};
|
|
5664
|
+
|
|
5665
|
+
const CustomViewer = ({ column, schema, prefix }) => {
|
|
5666
|
+
const formContext = useFormContext();
|
|
5667
|
+
const { inputViewerRender } = schema;
|
|
5668
|
+
return (inputViewerRender &&
|
|
5669
|
+
inputViewerRender({
|
|
5670
|
+
column,
|
|
5671
|
+
schema,
|
|
5672
|
+
prefix,
|
|
5673
|
+
formContext,
|
|
5674
|
+
}));
|
|
4619
5675
|
};
|
|
4620
5676
|
|
|
4621
5677
|
const DateViewer = ({ column, schema, prefix }) => {
|
|
4622
5678
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4623
|
-
const { translate } = useSchemaContext();
|
|
4624
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5679
|
+
const { translate, timezone } = useSchemaContext();
|
|
5680
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", } = schema;
|
|
4625
5681
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4626
5682
|
const colLabel = `${prefix}${column}`;
|
|
4627
5683
|
const selectedDate = watch(colLabel);
|
|
4628
|
-
|
|
4629
|
-
|
|
5684
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5685
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5686
|
+
gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
4630
5687
|
};
|
|
4631
5688
|
|
|
4632
5689
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
4633
5690
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4634
|
-
const
|
|
5691
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4635
5692
|
const { required } = schema;
|
|
4636
5693
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4637
|
-
const { gridColumn, gridRow, renderDisplay } = schema;
|
|
4638
|
-
const colLabel =
|
|
5694
|
+
const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
|
|
5695
|
+
const colLabel = formI18n.colLabel;
|
|
4639
5696
|
const watchEnum = watch(colLabel);
|
|
4640
5697
|
const watchEnums = (watch(colLabel) ?? []);
|
|
4641
|
-
return (jsxs(Field, { label:
|
|
5698
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
|
|
4642
5699
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: "wrap", gap: 1, children: watchEnums.map((enumValue) => {
|
|
4643
5700
|
const item = enumValue;
|
|
4644
5701
|
if (item === undefined) {
|
|
4645
5702
|
return jsx(Fragment, { children: "undefined" });
|
|
4646
5703
|
}
|
|
4647
|
-
return (jsx(Tag, {
|
|
5704
|
+
return (jsx(Tag, { size: "lg", children: !!renderDisplay === true
|
|
4648
5705
|
? renderDisplay(item)
|
|
4649
|
-
:
|
|
4650
|
-
}) })), !isMultiple &&
|
|
5706
|
+
: formI18n.t(item) }, item));
|
|
5707
|
+
}) })), !isMultiple && jsx(Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
|
|
4651
5708
|
};
|
|
4652
5709
|
|
|
4653
5710
|
const FileViewer = ({ column, schema, prefix }) => {
|
|
4654
|
-
const {
|
|
5711
|
+
const { watch } = useFormContext();
|
|
4655
5712
|
const { translate } = useSchemaContext();
|
|
4656
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5713
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
|
|
4657
5714
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4658
5715
|
const currentFiles = (watch(column) ?? []);
|
|
4659
5716
|
const colLabel = `${prefix}${column}`;
|
|
4660
|
-
return (
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
}, placeholder: translate.t(`${colLabel}.fileDropzone`) }), jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
|
|
4664
|
-
return (jsx(Card.Root, { variant: "subtle", children: jsxs(Card.Body, { gap: "2", cursor: "pointer", onClick: () => {
|
|
4665
|
-
setValue(column, currentFiles.filter(({ name }) => {
|
|
4666
|
-
return name !== file.name;
|
|
4667
|
-
}));
|
|
4668
|
-
}, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
|
|
4669
|
-
}) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
|
|
5717
|
+
return (jsx(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
|
|
5718
|
+
return (jsx(Card.Root, { variant: "subtle", children: jsxs(Card.Body, { gap: "2", display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name })] }) }, file.name));
|
|
5719
|
+
}) }) }));
|
|
4670
5720
|
};
|
|
4671
5721
|
|
|
4672
5722
|
const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
4673
5723
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4674
5724
|
const { idMap, translate } = useSchemaContext();
|
|
4675
|
-
const { required, gridColumn, gridRow, renderDisplay, foreign_key } = schema;
|
|
5725
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
|
|
4676
5726
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4677
5727
|
const { display_column } = foreign_key;
|
|
4678
5728
|
const colLabel = `${prefix}${column}`;
|
|
@@ -4688,7 +5738,7 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4688
5738
|
}
|
|
4689
5739
|
return record[display_column];
|
|
4690
5740
|
};
|
|
4691
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.
|
|
5741
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4692
5742
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: "wrap", gap: 1, children: watchIds.map((id) => {
|
|
4693
5743
|
const item = idMap[id];
|
|
4694
5744
|
if (item === undefined) {
|
|
@@ -4697,21 +5747,21 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4697
5747
|
return (jsx(Tag, { closable: true, children: !!renderDisplay === true
|
|
4698
5748
|
? renderDisplay(item)
|
|
4699
5749
|
: item[display_column] }, id));
|
|
4700
|
-
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
5750
|
+
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4701
5751
|
};
|
|
4702
5752
|
|
|
4703
5753
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
4704
5754
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4705
5755
|
const { translate } = useSchemaContext();
|
|
4706
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5756
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4707
5757
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4708
5758
|
const colLabel = `${prefix}${column}`;
|
|
4709
5759
|
const value = watch(colLabel);
|
|
4710
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
5760
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: value }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4711
5761
|
};
|
|
4712
5762
|
|
|
4713
5763
|
const ObjectViewer = ({ schema, column, prefix }) => {
|
|
4714
|
-
const { properties,
|
|
5764
|
+
const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
|
|
4715
5765
|
const { translate } = useSchemaContext();
|
|
4716
5766
|
const colLabel = `${prefix}${column}`;
|
|
4717
5767
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
@@ -4719,25 +5769,28 @@ const ObjectViewer = ({ schema, column, prefix }) => {
|
|
|
4719
5769
|
if (properties === undefined) {
|
|
4720
5770
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
4721
5771
|
}
|
|
4722
|
-
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label",
|
|
5772
|
+
return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: "1", borderRadius: "md", borderWidth: "thin", borderColor: {
|
|
5773
|
+
base: "colorPalette.200",
|
|
5774
|
+
_dark: "colorPalette.800",
|
|
5775
|
+
}, children: Object.keys(properties ?? {}).map((key) => {
|
|
4723
5776
|
return (
|
|
4724
5777
|
// @ts-expect-error find suitable types
|
|
4725
5778
|
jsx(ColumnViewer, { column: `${key}`,
|
|
4726
5779
|
prefix: `${prefix}${column}.`,
|
|
4727
5780
|
properties }, `form-objectviewer-${colLabel}-${key}`));
|
|
4728
|
-
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
5781
|
+
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4729
5782
|
};
|
|
4730
5783
|
|
|
4731
5784
|
const RecordInput = ({ column, schema, prefix }) => {
|
|
4732
5785
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
4733
5786
|
const { translate } = useSchemaContext();
|
|
4734
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5787
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4735
5788
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4736
5789
|
const entries = Object.entries(getValues(column) ?? {});
|
|
4737
5790
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
4738
5791
|
const [newKey, setNewKey] = useState();
|
|
4739
5792
|
const [newValue, setNewValue] = useState();
|
|
4740
|
-
return (jsxs(Field, { label: `${translate.t(`${column}.
|
|
5793
|
+
return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
|
|
4741
5794
|
return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
4742
5795
|
const filtered = entries.filter(([target]) => {
|
|
4743
5796
|
return target !== key;
|
|
@@ -4777,7 +5830,17 @@ const RecordInput = ({ column, schema, prefix }) => {
|
|
|
4777
5830
|
setShowNewEntries(true);
|
|
4778
5831
|
setNewKey(undefined);
|
|
4779
5832
|
setNewValue(undefined);
|
|
4780
|
-
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.
|
|
5833
|
+
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5834
|
+
};
|
|
5835
|
+
|
|
5836
|
+
const StringViewer = ({ column, schema, prefix, }) => {
|
|
5837
|
+
const { watch, formState: { errors }, } = useFormContext();
|
|
5838
|
+
const { translate } = useSchemaContext();
|
|
5839
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
5840
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5841
|
+
const colLabel = `${prefix}${column}`;
|
|
5842
|
+
const value = watch(colLabel);
|
|
5843
|
+
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsx(Text, { children: value }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
|
|
4781
5844
|
};
|
|
4782
5845
|
|
|
4783
5846
|
const TagViewer = ({ column, schema, prefix }) => {
|
|
@@ -4865,19 +5928,50 @@ const TagViewer = ({ column, schema, prefix }) => {
|
|
|
4865
5928
|
}), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
|
|
4866
5929
|
};
|
|
4867
5930
|
|
|
4868
|
-
const
|
|
5931
|
+
const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
4869
5932
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4870
5933
|
const { translate } = useSchemaContext();
|
|
4871
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5934
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4872
5935
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4873
5936
|
const colLabel = `${prefix}${column}`;
|
|
4874
5937
|
const value = watch(colLabel);
|
|
4875
|
-
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
5938
|
+
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Text, { whiteSpace: "pre-wrap", children: value }), " ", errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
|
|
5939
|
+
};
|
|
5940
|
+
|
|
5941
|
+
const TimeViewer = ({ column, schema, prefix }) => {
|
|
5942
|
+
const { watch, formState: { errors }, } = useFormContext();
|
|
5943
|
+
const { translate, timezone } = useSchemaContext();
|
|
5944
|
+
const { required, gridColumn = "span 12", gridRow = "span 1", displayTimeFormat = "hh:mm A", } = schema;
|
|
5945
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5946
|
+
const colLabel = `${prefix}${column}`;
|
|
5947
|
+
const selectedDate = watch(colLabel);
|
|
5948
|
+
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
5949
|
+
.tz(timezone)
|
|
5950
|
+
.isValid()
|
|
5951
|
+
? dayjs(`1970-01-01T${selectedDate}`).tz(timezone).format(displayTimeFormat)
|
|
5952
|
+
: "";
|
|
5953
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5954
|
+
gridRow, children: [jsx(Text, { children: displayedTime }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5955
|
+
};
|
|
5956
|
+
|
|
5957
|
+
const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
5958
|
+
const { watch, formState: { errors }, } = useFormContext();
|
|
5959
|
+
const { translate, timezone } = useSchemaContext();
|
|
5960
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss", } = schema;
|
|
5961
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5962
|
+
const colLabel = `${prefix}${column}`;
|
|
5963
|
+
const selectedDate = watch(colLabel);
|
|
5964
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5965
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5966
|
+
gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
4876
5967
|
};
|
|
4877
5968
|
|
|
4878
5969
|
const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
4879
5970
|
const colSchema = schema;
|
|
4880
|
-
const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
|
|
5971
|
+
const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
|
|
5972
|
+
if (variant === "custom-input") {
|
|
5973
|
+
return jsx(CustomViewer, { schema: colSchema, prefix, column });
|
|
5974
|
+
}
|
|
4881
5975
|
if (type === "string") {
|
|
4882
5976
|
if ((schema.enum ?? []).length > 0) {
|
|
4883
5977
|
return jsx(EnumViewer, { schema: colSchema, prefix, column });
|
|
@@ -4886,9 +5980,18 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
4886
5980
|
idPickerSanityCheck(column, foreign_key);
|
|
4887
5981
|
return jsx(IdViewer, { schema: colSchema, prefix, column });
|
|
4888
5982
|
}
|
|
4889
|
-
if (
|
|
5983
|
+
if (format === "time") {
|
|
5984
|
+
return jsx(TimeViewer, { schema: colSchema, prefix, column });
|
|
5985
|
+
}
|
|
5986
|
+
if (format === "date") {
|
|
4890
5987
|
return jsx(DateViewer, { schema: colSchema, prefix, column });
|
|
4891
5988
|
}
|
|
5989
|
+
if (format === "date-time") {
|
|
5990
|
+
return jsx(DateTimeViewer, { schema: colSchema, prefix, column });
|
|
5991
|
+
}
|
|
5992
|
+
if (variant === "text-area") {
|
|
5993
|
+
return jsx(TextAreaViewer, { schema: colSchema, prefix, column });
|
|
5994
|
+
}
|
|
4892
5995
|
return jsx(StringViewer, { schema: colSchema, prefix, column });
|
|
4893
5996
|
}
|
|
4894
5997
|
if (type === "number" || type === "integer") {
|
|
@@ -4914,6 +6017,15 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
4914
6017
|
if (variant === "file-picker") {
|
|
4915
6018
|
return jsx(FileViewer, { schema: colSchema, prefix, column });
|
|
4916
6019
|
}
|
|
6020
|
+
if (variant === "enum-picker") {
|
|
6021
|
+
const { items } = schema;
|
|
6022
|
+
const { enum: enumItems } = items;
|
|
6023
|
+
const enumSchema = {
|
|
6024
|
+
type: "string",
|
|
6025
|
+
enum: enumItems,
|
|
6026
|
+
};
|
|
6027
|
+
return (jsx(EnumViewer, { isMultiple: true, schema: enumSchema, prefix, column }));
|
|
6028
|
+
}
|
|
4917
6029
|
if (items) {
|
|
4918
6030
|
return jsx(ArrayViewer, { schema: colSchema, prefix, column });
|
|
4919
6031
|
}
|
|
@@ -4937,10 +6049,20 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
4937
6049
|
};
|
|
4938
6050
|
|
|
4939
6051
|
const SubmitButton = () => {
|
|
4940
|
-
const { translate, setValidatedData, setIsError, setIsConfirming } = useSchemaContext();
|
|
6052
|
+
const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, } = useSchemaContext();
|
|
4941
6053
|
const methods = useFormContext();
|
|
4942
6054
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4943
6055
|
const onValid = (data) => {
|
|
6056
|
+
const { isValid, errors } = validateData(data, schema);
|
|
6057
|
+
if (!isValid) {
|
|
6058
|
+
setError({
|
|
6059
|
+
type: "validation",
|
|
6060
|
+
errors,
|
|
6061
|
+
});
|
|
6062
|
+
setIsError(true);
|
|
6063
|
+
return;
|
|
6064
|
+
}
|
|
6065
|
+
// If validation passes, proceed to confirmation
|
|
4944
6066
|
setValidatedData(data);
|
|
4945
6067
|
setIsError(false);
|
|
4946
6068
|
setIsConfirming(true);
|
|
@@ -4951,7 +6073,8 @@ const SubmitButton = () => {
|
|
|
4951
6073
|
};
|
|
4952
6074
|
|
|
4953
6075
|
const FormBody = () => {
|
|
4954
|
-
const { schema, requestUrl, order, ignore, include, onSubmit,
|
|
6076
|
+
const { schema, requestUrl, order, ignore, include, onSubmit, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, displayConfig, } = useSchemaContext();
|
|
6077
|
+
const { showSubmitButton, showResetButton } = displayConfig;
|
|
4955
6078
|
const methods = useFormContext();
|
|
4956
6079
|
const { properties } = schema;
|
|
4957
6080
|
const onBeforeSubmit = () => {
|
|
@@ -4967,6 +6090,26 @@ const FormBody = () => {
|
|
|
4967
6090
|
const onSubmitSuccess = () => {
|
|
4968
6091
|
setIsSuccess(true);
|
|
4969
6092
|
};
|
|
6093
|
+
const validateFormData = (data) => {
|
|
6094
|
+
try {
|
|
6095
|
+
const { isValid, errors } = validateData(data, schema);
|
|
6096
|
+
return {
|
|
6097
|
+
isValid,
|
|
6098
|
+
errors,
|
|
6099
|
+
};
|
|
6100
|
+
}
|
|
6101
|
+
catch (error) {
|
|
6102
|
+
return {
|
|
6103
|
+
isValid: false,
|
|
6104
|
+
errors: [
|
|
6105
|
+
{
|
|
6106
|
+
field: "validation",
|
|
6107
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
6108
|
+
},
|
|
6109
|
+
],
|
|
6110
|
+
};
|
|
6111
|
+
}
|
|
6112
|
+
};
|
|
4970
6113
|
const defaultOnSubmit = async (promise) => {
|
|
4971
6114
|
try {
|
|
4972
6115
|
onBeforeSubmit();
|
|
@@ -4991,12 +6134,28 @@ const FormBody = () => {
|
|
|
4991
6134
|
};
|
|
4992
6135
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4993
6136
|
const onFormSubmit = async (data) => {
|
|
6137
|
+
// Validate data using AJV before submission
|
|
6138
|
+
const validationResult = validateFormData(data);
|
|
6139
|
+
if (!validationResult.isValid) {
|
|
6140
|
+
// Set validation errors
|
|
6141
|
+
const validationErrorMessage = {
|
|
6142
|
+
type: "validation",
|
|
6143
|
+
errors: validationResult.errors,
|
|
6144
|
+
message: translate.t("validation_error"),
|
|
6145
|
+
};
|
|
6146
|
+
onSubmitError(validationErrorMessage);
|
|
6147
|
+
return;
|
|
6148
|
+
}
|
|
4994
6149
|
if (onSubmit === undefined) {
|
|
4995
6150
|
await defaultOnSubmit(defaultSubmitPromise(data));
|
|
4996
6151
|
return;
|
|
4997
6152
|
}
|
|
4998
6153
|
await defaultOnSubmit(onSubmit(data));
|
|
4999
6154
|
};
|
|
6155
|
+
// Custom error renderer for validation errors with i18n support
|
|
6156
|
+
const renderValidationErrors = (validationErrors) => {
|
|
6157
|
+
return (jsx(Flex, { flexFlow: "column", gap: "2", children: validationErrors.map((err, index) => (jsxs(Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Description, { children: err.message }) })] }, index))) }));
|
|
6158
|
+
};
|
|
5000
6159
|
const renderColumns = ({ order, keys, ignore, include, }) => {
|
|
5001
6160
|
const included = include.length > 0 ? include : keys;
|
|
5002
6161
|
const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
|
|
@@ -5011,7 +6170,7 @@ const FormBody = () => {
|
|
|
5011
6170
|
include,
|
|
5012
6171
|
});
|
|
5013
6172
|
if (isSuccess) {
|
|
5014
|
-
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Title, { children: translate.t("
|
|
6173
|
+
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t("submit_success") }) })] }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { onClick: async () => {
|
|
5015
6174
|
setIsError(false);
|
|
5016
6175
|
setIsSubmiting(false);
|
|
5017
6176
|
setIsSuccess(false);
|
|
@@ -5019,10 +6178,10 @@ const FormBody = () => {
|
|
|
5019
6178
|
setValidatedData(undefined);
|
|
5020
6179
|
const data = await getUpdatedData();
|
|
5021
6180
|
methods.reset(data);
|
|
5022
|
-
}, formNoValidate: true, children: translate.t("
|
|
6181
|
+
}, formNoValidate: true, children: translate.t("submit_again") }) })] }));
|
|
5023
6182
|
}
|
|
5024
6183
|
if (isConfirming) {
|
|
5025
|
-
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows:
|
|
6184
|
+
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: "repeat(12, max-content)", autoFlow: "row", children: ordered.map((column) => {
|
|
5026
6185
|
return (jsx(ColumnViewer
|
|
5027
6186
|
// @ts-expect-error find suitable types
|
|
5028
6187
|
, {
|
|
@@ -5032,17 +6191,19 @@ const FormBody = () => {
|
|
|
5032
6191
|
setIsConfirming(false);
|
|
5033
6192
|
}, variant: "subtle", children: translate.t("cancel") }), jsx(Button$1, { onClick: () => {
|
|
5034
6193
|
onFormSubmit(validatedData);
|
|
5035
|
-
}, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children:
|
|
6194
|
+
}, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
|
|
6195
|
+
error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
|
|
5036
6196
|
}
|
|
5037
|
-
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)",
|
|
6197
|
+
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: ordered.map((column) => {
|
|
5038
6198
|
return (jsx(ColumnRenderer
|
|
5039
6199
|
// @ts-expect-error find suitable types
|
|
5040
6200
|
, {
|
|
5041
6201
|
// @ts-expect-error find suitable types
|
|
5042
6202
|
properties: properties, prefix: ``, column }, `form-input-${column}`));
|
|
5043
|
-
}) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [jsx(Button$1, { onClick: () => {
|
|
6203
|
+
}) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
|
|
5044
6204
|
methods.reset();
|
|
5045
|
-
}, variant: "subtle", children: translate.t("reset") }), jsx(SubmitButton, {})] })
|
|
6205
|
+
}, variant: "subtle", children: translate.t("reset") })), showSubmitButton && jsx(SubmitButton, {})] }), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
|
|
6206
|
+
error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
|
|
5046
6207
|
};
|
|
5047
6208
|
|
|
5048
6209
|
const FormTitle = () => {
|
|
@@ -5051,7 +6212,8 @@ const FormTitle = () => {
|
|
|
5051
6212
|
};
|
|
5052
6213
|
|
|
5053
6214
|
const DefaultForm = ({ formConfig, }) => {
|
|
5054
|
-
|
|
6215
|
+
const { showTitle } = formConfig.displayConfig ?? {};
|
|
6216
|
+
return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
|
|
5055
6217
|
};
|
|
5056
6218
|
|
|
5057
6219
|
const useForm = ({ preLoadedValues, keyPrefix }) => {
|
|
@@ -5084,4 +6246,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
|
|
|
5084
6246
|
}
|
|
5085
6247
|
};
|
|
5086
6248
|
|
|
5087
|
-
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog,
|
|
6249
|
+
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|