@bsol-oss/react-datatable5 12.0.0-beta.7 → 12.0.0-beta.70
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 +277 -83
- package/dist/index.js +1577 -469
- package/dist/index.mjs +1585 -477
- 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/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 +17 -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 4", 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,86 @@ const PopoverRoot = Popover.Root;
|
|
|
3721
3943
|
const PopoverBody = Popover.Body;
|
|
3722
3944
|
const PopoverTrigger = Popover.Trigger;
|
|
3723
3945
|
|
|
3946
|
+
function translateWrapper({ prefix, column, label, translate, }) {
|
|
3947
|
+
return translate.t(removeIndex(`${prefix}${column}.${label}`));
|
|
3948
|
+
}
|
|
3949
|
+
|
|
3950
|
+
dayjs.extend(utc);
|
|
3951
|
+
dayjs.extend(timezone);
|
|
3724
3952
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
3725
3953
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
3726
|
-
const { translate } = useSchemaContext();
|
|
3727
|
-
const { required, gridColumn, gridRow } = schema;
|
|
3954
|
+
const { translate, timezone } = useSchemaContext();
|
|
3955
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD", } = schema;
|
|
3728
3956
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3729
3957
|
const colLabel = `${prefix}${column}`;
|
|
3730
3958
|
const [open, setOpen] = useState(false);
|
|
3731
3959
|
const selectedDate = watch(colLabel);
|
|
3732
|
-
const
|
|
3733
|
-
|
|
3734
|
-
|
|
3960
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
3961
|
+
useEffect(() => {
|
|
3962
|
+
try {
|
|
3963
|
+
if (selectedDate) {
|
|
3964
|
+
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
3965
|
+
// For example, parse as UTC:
|
|
3966
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
3967
|
+
if (!parsedDate.isValid())
|
|
3968
|
+
return;
|
|
3969
|
+
// Format according to dateFormat from schema
|
|
3970
|
+
const formatted = parsedDate.format(dateFormat);
|
|
3971
|
+
// Update the form value only if different to avoid loops
|
|
3972
|
+
if (formatted !== selectedDate) {
|
|
3973
|
+
setValue(colLabel, formatted, {
|
|
3974
|
+
shouldValidate: true,
|
|
3975
|
+
shouldDirty: true,
|
|
3976
|
+
});
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
catch (e) {
|
|
3981
|
+
console.error(e);
|
|
3982
|
+
}
|
|
3983
|
+
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
3984
|
+
const customTranslate = (label) => {
|
|
3985
|
+
return translateWrapper({ prefix, column, label, translate });
|
|
3986
|
+
};
|
|
3987
|
+
return (jsxs(Field, { label: `${customTranslate(`field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
3988
|
+
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
3989
|
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"));
|
|
3990
|
+
}, 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 }) => {
|
|
3991
|
+
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
3744
3992
|
setOpen(false);
|
|
3745
|
-
}
|
|
3993
|
+
}, labels: {
|
|
3994
|
+
monthNamesShort: [
|
|
3995
|
+
translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
3996
|
+
translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
3997
|
+
translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
3998
|
+
translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
3999
|
+
translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
4000
|
+
translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
4001
|
+
translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
4002
|
+
translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
4003
|
+
translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
4004
|
+
translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
4005
|
+
translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
4006
|
+
translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
4007
|
+
],
|
|
4008
|
+
weekdayNamesShort: [
|
|
4009
|
+
translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
4010
|
+
translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
4011
|
+
translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
4012
|
+
translate.t(`common.weekday_4`, {
|
|
4013
|
+
defaultValue: "Wed",
|
|
4014
|
+
}),
|
|
4015
|
+
translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
4016
|
+
translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
4017
|
+
translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
4018
|
+
],
|
|
4019
|
+
backButtonLabel: translate.t(`common.back_button`, {
|
|
4020
|
+
defaultValue: "Back",
|
|
4021
|
+
}),
|
|
4022
|
+
forwardButtonLabel: translate.t(`common.forward_button`, {
|
|
4023
|
+
defaultValue: "Forward",
|
|
4024
|
+
}),
|
|
4025
|
+
} })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: customTranslate(`field_required`) }))] }));
|
|
3746
4026
|
};
|
|
3747
4027
|
|
|
3748
4028
|
function filterArray(array, searchTerm) {
|
|
@@ -3755,12 +4035,12 @@ function filterArray(array, searchTerm) {
|
|
|
3755
4035
|
});
|
|
3756
4036
|
}
|
|
3757
4037
|
|
|
3758
|
-
const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
4038
|
+
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
3759
4039
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
3760
4040
|
const { translate } = useSchemaContext();
|
|
3761
|
-
const { required } = schema;
|
|
4041
|
+
const { required, variant } = schema;
|
|
3762
4042
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3763
|
-
const { gridColumn, gridRow, renderDisplay } = schema;
|
|
4043
|
+
const { gridColumn = "span 4", gridRow = "span 1", renderDisplay } = schema;
|
|
3764
4044
|
const [searchText, setSearchText] = useState();
|
|
3765
4045
|
const [limit, setLimit] = useState(10);
|
|
3766
4046
|
const [openSearchResult, setOpenSearchResult] = useState();
|
|
@@ -3775,28 +4055,61 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
3775
4055
|
setSearchText(event.target.value);
|
|
3776
4056
|
setLimit(10);
|
|
3777
4057
|
};
|
|
3778
|
-
|
|
4058
|
+
if (variant === "radio") {
|
|
4059
|
+
return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4060
|
+
gridRow, children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? "").map((item) => {
|
|
4061
|
+
return (jsxs(RadioGroup$1.Item, { onClick: () => {
|
|
4062
|
+
if (!isMultiple) {
|
|
4063
|
+
setOpenSearchResult(false);
|
|
4064
|
+
setValue(colLabel, item);
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4067
|
+
const newSet = new Set([...(watchEnums ?? []), item]);
|
|
4068
|
+
setValue(colLabel, [...newSet]);
|
|
4069
|
+
}, value: item, children: [jsx(RadioGroup$1.ItemHiddenInput, {}), jsx(RadioGroup$1.ItemIndicator, {}), jsx(RadioGroup$1.ItemText, { children: !!renderDisplay === true
|
|
4070
|
+
? renderDisplay(item)
|
|
4071
|
+
: translate.t(removeIndex(`${colLabel}.${item}`)) })] }, `${colLabel}-${item}`));
|
|
4072
|
+
}) }) }) }));
|
|
4073
|
+
}
|
|
4074
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
3779
4075
|
gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchEnums.map((enumValue) => {
|
|
3780
4076
|
const item = enumValue;
|
|
3781
|
-
if (item ===
|
|
3782
|
-
return jsx(Fragment, {
|
|
4077
|
+
if (!!item === false) {
|
|
4078
|
+
return jsx(Fragment, {});
|
|
3783
4079
|
}
|
|
3784
|
-
return (jsx(Tag, { closable: true, onClick: () => {
|
|
3785
|
-
// setSelectedEnums((state) => state.filter((id) => id != item));
|
|
4080
|
+
return (jsx(Tag, { size: "lg", closable: true, onClick: () => {
|
|
3786
4081
|
setValue(column, watchEnums.filter((id) => id != item));
|
|
3787
4082
|
}, children: !!renderDisplay === true
|
|
3788
4083
|
? renderDisplay(item)
|
|
3789
|
-
: translate.t(removeIndex(`${colLabel}.${item}`)) }));
|
|
3790
|
-
}), jsx(Tag, { cursor: "pointer", onClick: () => {
|
|
4084
|
+
: translate.t(removeIndex(`${colLabel}.${item}`)) }, item));
|
|
4085
|
+
}), jsx(Tag, { size: "lg", cursor: "pointer", onClick: () => {
|
|
3791
4086
|
setOpenSearchResult(true);
|
|
3792
|
-
}, children: translate.t(removeIndex(`${colLabel}.
|
|
4087
|
+
}, children: translate.t(removeIndex(`${colLabel}.add_more`)) }, `${colLabel}-add-more-tag`)] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
|
|
3793
4088
|
setOpenSearchResult(true);
|
|
3794
|
-
}, children: watchEnum ===
|
|
4089
|
+
}, justifyContent: "start", children: !!watchEnum === false
|
|
3795
4090
|
? ""
|
|
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(`${
|
|
4091
|
+
: 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
4092
|
onSearchChange(event);
|
|
3798
4093
|
setOpenSearchResult(true);
|
|
3799
|
-
}, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), jsx(Text, { children: `${translate.t(`${
|
|
4094
|
+
}, 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
|
|
4095
|
+
.filter((item) => {
|
|
4096
|
+
const searchTerm = (searchText || "").toLowerCase();
|
|
4097
|
+
if (!searchTerm)
|
|
4098
|
+
return true;
|
|
4099
|
+
// Check if the original enum value contains the search text
|
|
4100
|
+
const enumValueMatch = item
|
|
4101
|
+
.toLowerCase()
|
|
4102
|
+
.includes(searchTerm);
|
|
4103
|
+
// Check if the display value (translation) contains the search text
|
|
4104
|
+
const displayValue = !!renderDisplay === true
|
|
4105
|
+
? renderDisplay(item)
|
|
4106
|
+
: translate.t(removeIndex(`${colLabel}.${item}`));
|
|
4107
|
+
// Convert to string and check if it includes the search term
|
|
4108
|
+
const displayValueString = String(displayValue).toLowerCase();
|
|
4109
|
+
const displayValueMatch = displayValueString.includes(searchTerm);
|
|
4110
|
+
return enumValueMatch || displayValueMatch;
|
|
4111
|
+
})
|
|
4112
|
+
.map((item) => {
|
|
3800
4113
|
const selected = isMultiple
|
|
3801
4114
|
? watchEnums.some((enumValue) => item === enumValue)
|
|
3802
4115
|
: watchEnum == item;
|
|
@@ -3808,10 +4121,10 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
3808
4121
|
}
|
|
3809
4122
|
const newSet = new Set([...(watchEnums ?? []), item]);
|
|
3810
4123
|
setValue(colLabel, [...newSet]);
|
|
3811
|
-
}, ...(selected ? { color: "
|
|
4124
|
+
}, ...(selected ? { color: "colorPalette.400/50" } : {}), children: !!renderDisplay === true
|
|
3812
4125
|
? renderDisplay(item)
|
|
3813
4126
|
: translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
|
|
3814
|
-
}) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: translate.t(removeIndex(`${colLabel}.
|
|
4127
|
+
}) }), 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
4128
|
};
|
|
3816
4129
|
|
|
3817
4130
|
function isEnteringWindow(_ref) {
|
|
@@ -4163,17 +4476,17 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
|
|
|
4163
4476
|
const filesArray = [...event.target.files];
|
|
4164
4477
|
onDrop({ files: filesArray });
|
|
4165
4478
|
};
|
|
4166
|
-
return (jsxs(Grid, { ...getColor(isDraggedOver), ref: ref, cursor: "pointer", onClick: handleClick, borderStyle: "dashed", borderColor: "
|
|
4479
|
+
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
4480
|
};
|
|
4168
4481
|
|
|
4169
4482
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
4170
4483
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
4171
4484
|
const { translate } = useSchemaContext();
|
|
4172
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4485
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", } = schema;
|
|
4173
4486
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4174
4487
|
const currentFiles = (watch(column) ?? []);
|
|
4175
4488
|
const colLabel = `${prefix}${column}`;
|
|
4176
|
-
return (jsxs(Field, { label: `${translate.t(`${colLabel}.
|
|
4489
|
+
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
4490
|
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
4178
4491
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
4179
4492
|
}, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
|
|
@@ -4181,10 +4494,19 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
4181
4494
|
setValue(column, currentFiles.filter(({ name }) => {
|
|
4182
4495
|
return name !== file.name;
|
|
4183
4496
|
}));
|
|
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}.
|
|
4497
|
+
}, 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));
|
|
4498
|
+
}) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4186
4499
|
};
|
|
4187
4500
|
|
|
4501
|
+
const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
|
|
4502
|
+
const { showArrow, children, portalled = true, content, portalRef, ...rest } = props;
|
|
4503
|
+
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] }) }) })] }));
|
|
4504
|
+
});
|
|
4505
|
+
const InfoTip = React.forwardRef(function InfoTip(props, ref) {
|
|
4506
|
+
const { children, ...rest } = props;
|
|
4507
|
+
return (jsx(ToggleTip, { content: children, ...rest, ref: ref, children: jsx(IconButton, { variant: "ghost", "aria-label": "info", size: "2xs", colorPalette: "colorPalette", children: jsx(HiOutlineInformationCircle, {}) }) }));
|
|
4508
|
+
});
|
|
4509
|
+
|
|
4188
4510
|
const getTableData = async ({ serverUrl, in_table, searching = "", where = [], limit = 10, offset = 0, }) => {
|
|
4189
4511
|
if (serverUrl === undefined || serverUrl.length == 0) {
|
|
4190
4512
|
throw new Error("The serverUrl is missing");
|
|
@@ -4216,24 +4538,38 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
|
|
|
4216
4538
|
const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
4217
4539
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4218
4540
|
const { serverUrl, idMap, setIdMap, translate, schema: parentSchema, } = useSchemaContext();
|
|
4219
|
-
const { required, gridColumn, gridRow, renderDisplay, foreign_key } = schema;
|
|
4541
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
|
|
4220
4542
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4221
|
-
const { table, column: column_ref, display_column, } = foreign_key;
|
|
4222
|
-
const [searchText, setSearchText] = useState();
|
|
4543
|
+
const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
|
|
4544
|
+
const [searchText, setSearchText] = useState("");
|
|
4223
4545
|
const [limit, setLimit] = useState(10);
|
|
4224
4546
|
const [openSearchResult, setOpenSearchResult] = useState();
|
|
4225
4547
|
const [page, setPage] = useState(0);
|
|
4226
4548
|
const ref = useRef(null);
|
|
4227
4549
|
const colLabel = `${prefix}${column}`;
|
|
4550
|
+
const watchId = watch(colLabel);
|
|
4551
|
+
const watchIds = isMultiple ? (watch(colLabel) ?? []) : [];
|
|
4552
|
+
// Query for search results
|
|
4228
4553
|
const query = useQuery({
|
|
4229
4554
|
queryKey: [`idpicker`, { column, searchText, limit, page }],
|
|
4230
4555
|
queryFn: async () => {
|
|
4556
|
+
if (customQueryFn) {
|
|
4557
|
+
const { data, idMap } = await customQueryFn({
|
|
4558
|
+
searching: searchText ?? "",
|
|
4559
|
+
limit: limit,
|
|
4560
|
+
offset: page * limit,
|
|
4561
|
+
});
|
|
4562
|
+
setIdMap((state) => {
|
|
4563
|
+
return { ...state, ...idMap };
|
|
4564
|
+
});
|
|
4565
|
+
return data;
|
|
4566
|
+
}
|
|
4231
4567
|
const data = await getTableData({
|
|
4232
4568
|
serverUrl,
|
|
4233
4569
|
searching: searchText ?? "",
|
|
4234
4570
|
in_table: table,
|
|
4235
4571
|
limit: limit,
|
|
4236
|
-
offset: page *
|
|
4572
|
+
offset: page * limit,
|
|
4237
4573
|
});
|
|
4238
4574
|
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
4239
4575
|
return [
|
|
@@ -4248,27 +4584,38 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4248
4584
|
});
|
|
4249
4585
|
return data;
|
|
4250
4586
|
},
|
|
4251
|
-
enabled:
|
|
4587
|
+
enabled: openSearchResult === true,
|
|
4252
4588
|
staleTime: 300000,
|
|
4253
4589
|
});
|
|
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({
|
|
4590
|
+
// Query for currently selected items (to display them properly)
|
|
4591
|
+
const queryDefault = useQuery({
|
|
4261
4592
|
queryKey: [
|
|
4262
|
-
`idpicker`,
|
|
4263
|
-
{ form: parentSchema.title, column,
|
|
4593
|
+
`idpicker-default`,
|
|
4594
|
+
{ form: parentSchema.title, column, id: isMultiple ? watchIds : watchId },
|
|
4264
4595
|
],
|
|
4265
4596
|
queryFn: async () => {
|
|
4597
|
+
if (customQueryFn) {
|
|
4598
|
+
const { data, idMap } = await customQueryFn({
|
|
4599
|
+
searching: watchIds.join(","),
|
|
4600
|
+
limit: isMultiple ? watchIds.length : 1,
|
|
4601
|
+
offset: 0,
|
|
4602
|
+
});
|
|
4603
|
+
setIdMap((state) => {
|
|
4604
|
+
return { ...state, ...idMap };
|
|
4605
|
+
});
|
|
4606
|
+
return data;
|
|
4607
|
+
}
|
|
4608
|
+
if (!watchId && (!watchIds || watchIds.length === 0)) {
|
|
4609
|
+
return { data: [] };
|
|
4610
|
+
}
|
|
4611
|
+
const searchValue = isMultiple ? watchIds.join(",") : watchId;
|
|
4266
4612
|
const data = await getTableData({
|
|
4267
4613
|
serverUrl,
|
|
4268
|
-
searching:
|
|
4614
|
+
searching: searchValue,
|
|
4269
4615
|
in_table: table,
|
|
4270
|
-
|
|
4271
|
-
|
|
4616
|
+
where: [{ id: column_ref, value: isMultiple ? watchIds : watchId }],
|
|
4617
|
+
limit: isMultiple ? watchIds.length : 1,
|
|
4618
|
+
offset: 0,
|
|
4272
4619
|
});
|
|
4273
4620
|
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
4274
4621
|
return [
|
|
@@ -4283,12 +4630,45 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4283
4630
|
});
|
|
4284
4631
|
return data;
|
|
4285
4632
|
},
|
|
4633
|
+
enabled: isMultiple
|
|
4634
|
+
? Array.isArray(watchIds) && watchIds.length > 0
|
|
4635
|
+
: !!watchId,
|
|
4286
4636
|
});
|
|
4637
|
+
// Effect to load selected values when component mounts
|
|
4638
|
+
useEffect(() => {
|
|
4639
|
+
if (isMultiple ? watchIds.length > 0 : !!watchId) {
|
|
4640
|
+
queryDefault.refetch();
|
|
4641
|
+
}
|
|
4642
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4643
|
+
}, []);
|
|
4644
|
+
// Effect to trigger initial data fetch when popover opens
|
|
4645
|
+
useEffect(() => {
|
|
4646
|
+
if (openSearchResult) {
|
|
4647
|
+
// Reset search text when opening the popover
|
|
4648
|
+
setSearchText("");
|
|
4649
|
+
// Reset page to first page
|
|
4650
|
+
setPage(0);
|
|
4651
|
+
// Fetch initial data
|
|
4652
|
+
query.refetch();
|
|
4653
|
+
}
|
|
4654
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4655
|
+
}, [openSearchResult]);
|
|
4287
4656
|
const onSearchChange = async (event) => {
|
|
4288
4657
|
setSearchText(event.target.value);
|
|
4289
4658
|
setPage(0);
|
|
4290
|
-
|
|
4659
|
+
query.refetch();
|
|
4291
4660
|
};
|
|
4661
|
+
const handleLimitChange = (event) => {
|
|
4662
|
+
const newLimit = Number(event.target.value);
|
|
4663
|
+
setLimit(newLimit);
|
|
4664
|
+
// Reset to first page when changing limit
|
|
4665
|
+
setPage(0);
|
|
4666
|
+
// Trigger a new search with the updated limit
|
|
4667
|
+
query.refetch();
|
|
4668
|
+
};
|
|
4669
|
+
const { isLoading, isFetching, data, isPending, isError } = query;
|
|
4670
|
+
const dataList = data?.data ?? [];
|
|
4671
|
+
const count = data?.count ?? 0;
|
|
4292
4672
|
const getPickedValue = () => {
|
|
4293
4673
|
if (Object.keys(idMap).length <= 0) {
|
|
4294
4674
|
return "";
|
|
@@ -4297,52 +4677,67 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4297
4677
|
if (record === undefined) {
|
|
4298
4678
|
return "";
|
|
4299
4679
|
}
|
|
4680
|
+
if (!!renderDisplay === true) {
|
|
4681
|
+
return renderDisplay(record);
|
|
4682
|
+
}
|
|
4300
4683
|
return record[display_column];
|
|
4301
4684
|
};
|
|
4302
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(removeIndex(`${column}.
|
|
4685
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(removeIndex(`${column}.field_label`)))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4303
4686
|
gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchIds.map((id) => {
|
|
4304
4687
|
const item = idMap[id];
|
|
4305
4688
|
if (item === undefined) {
|
|
4306
4689
|
return (jsx(Text, { children: translate.t(removeIndex(`${colLabel}.undefined`)) }, id));
|
|
4307
4690
|
}
|
|
4308
4691
|
return (jsx(Tag, { closable: true, onClick: () => {
|
|
4309
|
-
setValue(
|
|
4692
|
+
setValue(colLabel, watchIds.filter((itemId) => itemId !== item[column_ref]));
|
|
4310
4693
|
}, children: !!renderDisplay === true
|
|
4311
4694
|
? renderDisplay(item)
|
|
4312
4695
|
: item[display_column] }, id));
|
|
4313
4696
|
}), jsx(Tag, { cursor: "pointer", onClick: () => {
|
|
4314
4697
|
setOpenSearchResult(true);
|
|
4315
|
-
}, children: translate.t(removeIndex(`${colLabel}.
|
|
4698
|
+
}, children: translate.t(removeIndex(`${colLabel}.add_more`)) })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
|
|
4316
4699
|
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: translate.t(removeIndex(`${colLabel}.
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4700
|
+
}, 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: translate.t(removeIndex(`${colLabel}.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: `${translate.t(removeIndex(`${colLabel}.total`))} ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit} ${translate.t(removeIndex(`${colLabel}.per_page`), "per page")}` }), jsxs(Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxs(Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/", " ", count > 0
|
|
4701
|
+
? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}`
|
|
4702
|
+
: "0"] })] })] }), jsx(Box, { children: jsxs("select", { value: limit, onChange: handleLimitChange, style: {
|
|
4703
|
+
padding: "4px 8px",
|
|
4704
|
+
borderRadius: "4px",
|
|
4705
|
+
border: "1px solid #ccc",
|
|
4706
|
+
fontSize: "14px",
|
|
4707
|
+
}, 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) => {
|
|
4708
|
+
const selected = isMultiple
|
|
4709
|
+
? watchIds.some((id) => item[column_ref] === id)
|
|
4710
|
+
: watchId === item[column_ref];
|
|
4711
|
+
return (jsx(Box, { cursor: "pointer", onClick: () => {
|
|
4712
|
+
if (!isMultiple) {
|
|
4713
|
+
setOpenSearchResult(false);
|
|
4714
|
+
setValue(colLabel, item[column_ref]);
|
|
4715
|
+
return;
|
|
4716
|
+
}
|
|
4717
|
+
// For multiple selection, don't add if already selected
|
|
4718
|
+
if (selected)
|
|
4719
|
+
return;
|
|
4720
|
+
const newSet = new Set([
|
|
4721
|
+
...(watchIds ?? []),
|
|
4722
|
+
item[column_ref],
|
|
4723
|
+
]);
|
|
4724
|
+
setValue(colLabel, [...newSet]);
|
|
4725
|
+
}, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
|
|
4726
|
+
? {
|
|
4727
|
+
color: "colorPalette.400/50",
|
|
4728
|
+
fontWeight: "bold",
|
|
4729
|
+
}
|
|
4730
|
+
: {}), children: !!renderDisplay === true
|
|
4731
|
+
? renderDisplay(item)
|
|
4732
|
+
: item[display_column] }, item[column_ref]));
|
|
4733
|
+
}) })) : (jsx(Text, { children: searchText
|
|
4734
|
+
? translate.t(removeIndex(`${colLabel}.empty_search_result`))
|
|
4735
|
+
: translate.t(removeIndex(`${colLabel}.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: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4341
4736
|
};
|
|
4342
4737
|
|
|
4343
4738
|
const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
|
|
4344
4739
|
const { children, ...rest } = props;
|
|
4345
|
-
return (
|
|
4740
|
+
return (jsx(NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: children }));
|
|
4346
4741
|
});
|
|
4347
4742
|
const NumberInputField$1 = NumberInput.Input;
|
|
4348
4743
|
NumberInput.Scrubber;
|
|
@@ -4351,17 +4746,17 @@ NumberInput.Label;
|
|
|
4351
4746
|
const NumberInputField = ({ schema, column, prefix, }) => {
|
|
4352
4747
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
4353
4748
|
const { translate } = useSchemaContext();
|
|
4354
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4749
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
4355
4750
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4356
4751
|
const colLabel = `${prefix}${column}`;
|
|
4357
4752
|
const value = watch(`${colLabel}`);
|
|
4358
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
4753
|
+
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
4754
|
setValue(`${colLabel}`, Number(event.target.value));
|
|
4360
|
-
} }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
4755
|
+
} }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4361
4756
|
};
|
|
4362
4757
|
|
|
4363
4758
|
const ObjectInput = ({ schema, column, prefix }) => {
|
|
4364
|
-
const { properties,
|
|
4759
|
+
const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
|
|
4365
4760
|
const { translate } = useSchemaContext();
|
|
4366
4761
|
const colLabel = `${prefix}${column}`;
|
|
4367
4762
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
@@ -4369,25 +4764,28 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
4369
4764
|
if (properties === undefined) {
|
|
4370
4765
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
4371
4766
|
}
|
|
4372
|
-
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label",
|
|
4767
|
+
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: {
|
|
4768
|
+
base: "colorPalette.200",
|
|
4769
|
+
_dark: "colorPalette.800",
|
|
4770
|
+
}, gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
|
|
4373
4771
|
return (
|
|
4374
4772
|
// @ts-expect-error find suitable types
|
|
4375
4773
|
jsx(ColumnRenderer, { column: `${key}`,
|
|
4376
4774
|
prefix: `${prefix}${column}.`,
|
|
4377
4775
|
properties }, `form-${colLabel}-${key}`));
|
|
4378
|
-
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
4776
|
+
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4379
4777
|
};
|
|
4380
4778
|
|
|
4381
4779
|
const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
4382
4780
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
4383
4781
|
const { translate } = useSchemaContext();
|
|
4384
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4782
|
+
const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
|
|
4385
4783
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4386
4784
|
const entries = Object.entries(getValues(column) ?? {});
|
|
4387
4785
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
4388
4786
|
const [newKey, setNewKey] = useState();
|
|
4389
4787
|
const [newValue, setNewValue] = useState();
|
|
4390
|
-
return (jsxs(Field, { label: `${translate.t(`${column}.
|
|
4788
|
+
return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
|
|
4391
4789
|
return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
4392
4790
|
const filtered = entries.filter(([target]) => {
|
|
4393
4791
|
return target !== key;
|
|
@@ -4427,16 +4825,16 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
|
|
|
4427
4825
|
setShowNewEntries(true);
|
|
4428
4826
|
setNewKey(undefined);
|
|
4429
4827
|
setNewValue(undefined);
|
|
4430
|
-
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.
|
|
4828
|
+
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
4431
4829
|
};
|
|
4432
4830
|
|
|
4433
4831
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
4434
4832
|
const { register, formState: { errors }, } = useFormContext();
|
|
4435
4833
|
const { translate } = useSchemaContext();
|
|
4436
|
-
const { required, gridColumn, gridRow } = schema;
|
|
4834
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
4437
4835
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4438
4836
|
const colLabel = `${prefix}${column}`;
|
|
4439
|
-
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
4837
|
+
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
4838
|
};
|
|
4441
4839
|
|
|
4442
4840
|
const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
|
|
@@ -4534,9 +4932,576 @@ const TagPicker = ({ column, schema, prefix }) => {
|
|
|
4534
4932
|
}), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
|
|
4535
4933
|
};
|
|
4536
4934
|
|
|
4935
|
+
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) => {
|
|
4936
|
+
const contentEditableRef = useRef(null);
|
|
4937
|
+
const isControlled = value !== undefined;
|
|
4938
|
+
// Handle input changes
|
|
4939
|
+
const handleInput = (e) => {
|
|
4940
|
+
const text = e.currentTarget.textContent || "";
|
|
4941
|
+
// Check maxLength if specified
|
|
4942
|
+
if (maxLength && text.length > maxLength) {
|
|
4943
|
+
e.currentTarget.textContent = text.slice(0, maxLength);
|
|
4944
|
+
// Move cursor to end
|
|
4945
|
+
const selection = window.getSelection();
|
|
4946
|
+
if (selection) {
|
|
4947
|
+
selection.selectAllChildren(e.currentTarget);
|
|
4948
|
+
selection.collapseToEnd();
|
|
4949
|
+
}
|
|
4950
|
+
return;
|
|
4951
|
+
}
|
|
4952
|
+
onChange?.(text);
|
|
4953
|
+
};
|
|
4954
|
+
// Handle paste events to strip formatting and respect maxLength
|
|
4955
|
+
const handlePaste = (e) => {
|
|
4956
|
+
e.preventDefault();
|
|
4957
|
+
const text = e.clipboardData.getData('text/plain');
|
|
4958
|
+
const currentText = e.currentTarget.textContent || "";
|
|
4959
|
+
let pasteText = text;
|
|
4960
|
+
if (maxLength) {
|
|
4961
|
+
const remainingLength = maxLength - currentText.length;
|
|
4962
|
+
pasteText = text.slice(0, remainingLength);
|
|
4963
|
+
}
|
|
4964
|
+
document.execCommand('insertText', false, pasteText);
|
|
4965
|
+
};
|
|
4966
|
+
// Set initial content
|
|
4967
|
+
useEffect(() => {
|
|
4968
|
+
if (contentEditableRef.current && !isControlled) {
|
|
4969
|
+
const initialValue = defaultValue || "";
|
|
4970
|
+
if (contentEditableRef.current.textContent !== initialValue) {
|
|
4971
|
+
contentEditableRef.current.textContent = initialValue;
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
}, [defaultValue, isControlled]);
|
|
4975
|
+
// Update content when value changes (controlled mode)
|
|
4976
|
+
useEffect(() => {
|
|
4977
|
+
if (contentEditableRef.current && isControlled && value !== undefined) {
|
|
4978
|
+
if (contentEditableRef.current.textContent !== value) {
|
|
4979
|
+
contentEditableRef.current.textContent = value;
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
}, [value, isControlled]);
|
|
4983
|
+
// Auto focus
|
|
4984
|
+
useEffect(() => {
|
|
4985
|
+
if (autoFocus && contentEditableRef.current) {
|
|
4986
|
+
contentEditableRef.current.focus();
|
|
4987
|
+
}
|
|
4988
|
+
}, [autoFocus]);
|
|
4989
|
+
// Forward ref
|
|
4990
|
+
useEffect(() => {
|
|
4991
|
+
if (typeof ref === 'function') {
|
|
4992
|
+
ref(contentEditableRef.current);
|
|
4993
|
+
}
|
|
4994
|
+
else if (ref) {
|
|
4995
|
+
ref.current = contentEditableRef.current;
|
|
4996
|
+
}
|
|
4997
|
+
}, [ref]);
|
|
4998
|
+
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: {
|
|
4999
|
+
borderColor: invalid ? "red.500" : "blue.500",
|
|
5000
|
+
boxShadow: `0 0 0 1px ${invalid ? "red.500" : "blue.500"}`,
|
|
5001
|
+
}, _disabled: {
|
|
5002
|
+
opacity: 0.6,
|
|
5003
|
+
cursor: "not-allowed",
|
|
5004
|
+
bg: "gray.50",
|
|
5005
|
+
}, _empty: {
|
|
5006
|
+
_before: {
|
|
5007
|
+
content: placeholder ? `"${placeholder}"` : undefined,
|
|
5008
|
+
color: "gray.400",
|
|
5009
|
+
pointerEvents: "none",
|
|
5010
|
+
}
|
|
5011
|
+
}, whiteSpace: "pre-wrap", overflowWrap: "break-word", overflow: "auto", maxHeight: `${rows * 4}em`, suppressContentEditableWarning: true, ...props }));
|
|
5012
|
+
// If we have additional field props, wrap in Field component
|
|
5013
|
+
if (label || helperText || errorText || required) {
|
|
5014
|
+
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 })] }));
|
|
5015
|
+
}
|
|
5016
|
+
return textareaElement;
|
|
5017
|
+
});
|
|
5018
|
+
Textarea.displayName = "Textarea";
|
|
5019
|
+
|
|
5020
|
+
const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
5021
|
+
const { register, formState: { errors }, } = useFormContext();
|
|
5022
|
+
const { translate } = useSchemaContext();
|
|
5023
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
5024
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5025
|
+
const colLabel = `${prefix}${column}`;
|
|
5026
|
+
const form = useFormContext();
|
|
5027
|
+
const { setValue, watch } = form;
|
|
5028
|
+
const watchValue = watch(colLabel);
|
|
5029
|
+
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`)) }))] }) }));
|
|
5030
|
+
};
|
|
5031
|
+
|
|
5032
|
+
function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
|
|
5033
|
+
am: "am",
|
|
5034
|
+
pm: "pm",
|
|
5035
|
+
}, onChange = (_newValue) => { }, timezone = "Asia/Hong_Kong", }) {
|
|
5036
|
+
const handleClear = () => {
|
|
5037
|
+
setHour(null);
|
|
5038
|
+
setMinute(null);
|
|
5039
|
+
setMeridiem(null);
|
|
5040
|
+
setInputValue("");
|
|
5041
|
+
setShowInput(false);
|
|
5042
|
+
onChange({ hour: null, minute: null, meridiem: null });
|
|
5043
|
+
};
|
|
5044
|
+
const getTimeString = (hour, minute, meridiem) => {
|
|
5045
|
+
if (hour === null || minute === null || meridiem === null) {
|
|
5046
|
+
return "";
|
|
5047
|
+
}
|
|
5048
|
+
// if the hour is 24, set the hour to 0
|
|
5049
|
+
if (hour === 24) {
|
|
5050
|
+
return dayjs().tz(timezone).hour(0).minute(minute).format("HH:mmZ");
|
|
5051
|
+
}
|
|
5052
|
+
// use dayjs to format the time at current timezone
|
|
5053
|
+
// if meridiem is pm, add 12 hours
|
|
5054
|
+
let newHour = hour;
|
|
5055
|
+
if (meridiem === "pm" && hour !== 12) {
|
|
5056
|
+
newHour = hour + 12;
|
|
5057
|
+
}
|
|
5058
|
+
// if the hour is 12, set the meridiem to am, and set the hour to 0
|
|
5059
|
+
else if (meridiem === "am" && hour === 12) {
|
|
5060
|
+
newHour = 0;
|
|
5061
|
+
}
|
|
5062
|
+
return dayjs().tz(timezone).hour(newHour).minute(minute).format("HH:mmZ");
|
|
5063
|
+
};
|
|
5064
|
+
const stringTime = getTimeString(hour, minute, meridiem);
|
|
5065
|
+
const [inputValue, setInputValue] = useState("");
|
|
5066
|
+
const [showInput, setShowInput] = useState(false);
|
|
5067
|
+
const handleBlur = (text) => {
|
|
5068
|
+
// ignore all non-numeric characters
|
|
5069
|
+
if (!text) {
|
|
5070
|
+
return;
|
|
5071
|
+
}
|
|
5072
|
+
const value = text.replace(/[^0-9apm]/g, "");
|
|
5073
|
+
if (value === "") {
|
|
5074
|
+
handleClear();
|
|
5075
|
+
return;
|
|
5076
|
+
}
|
|
5077
|
+
// if the value is a valid time, parse it and set the hour, minute, and meridiem
|
|
5078
|
+
// if the value is not a valid time, set the stringTime to the value
|
|
5079
|
+
// first two characters are the hour
|
|
5080
|
+
// next two characters are the minute
|
|
5081
|
+
// final two characters are the meridiem
|
|
5082
|
+
const hour = parseInt(value.slice(0, 2));
|
|
5083
|
+
const minute = parseInt(value.slice(2, 4));
|
|
5084
|
+
const meridiem = value.slice(4, 6);
|
|
5085
|
+
// validate the hour and minute
|
|
5086
|
+
if (isNaN(hour) || isNaN(minute)) {
|
|
5087
|
+
setInputValue("");
|
|
5088
|
+
return;
|
|
5089
|
+
}
|
|
5090
|
+
// if the hour is larger than 24, set the hour to 24
|
|
5091
|
+
if (hour > 24) {
|
|
5092
|
+
setInputValue("");
|
|
5093
|
+
return;
|
|
5094
|
+
}
|
|
5095
|
+
let newHour = hour;
|
|
5096
|
+
let newMinute = minute;
|
|
5097
|
+
let newMeridiem = meridiem;
|
|
5098
|
+
// if the hour is 24, set the meridiem to am, and set the hour to 0
|
|
5099
|
+
if (hour === 24) {
|
|
5100
|
+
newMeridiem = "am";
|
|
5101
|
+
newHour = 0;
|
|
5102
|
+
}
|
|
5103
|
+
// if the hour is greater than 12, set the meridiem to pm, and subtract 12 from the hour
|
|
5104
|
+
else if (hour > 12) {
|
|
5105
|
+
newMeridiem = "pm";
|
|
5106
|
+
newHour = hour - 12;
|
|
5107
|
+
}
|
|
5108
|
+
// if the hour is 12, set the meridiem to pm, and set the hour to 12
|
|
5109
|
+
else if (hour === 12) {
|
|
5110
|
+
newMeridiem = "pm";
|
|
5111
|
+
newHour = 12;
|
|
5112
|
+
}
|
|
5113
|
+
// if the hour is 0, set the meridiem to am, and set the hour to 12
|
|
5114
|
+
else if (hour === 0) {
|
|
5115
|
+
newMeridiem = "am";
|
|
5116
|
+
newHour = 12;
|
|
5117
|
+
}
|
|
5118
|
+
else {
|
|
5119
|
+
newMeridiem = meridiem ?? "am";
|
|
5120
|
+
newHour = hour;
|
|
5121
|
+
}
|
|
5122
|
+
if (minute > 59) {
|
|
5123
|
+
newMinute = 0;
|
|
5124
|
+
}
|
|
5125
|
+
else {
|
|
5126
|
+
newMinute = minute;
|
|
5127
|
+
}
|
|
5128
|
+
onChange({
|
|
5129
|
+
hour: newHour,
|
|
5130
|
+
minute: newMinute,
|
|
5131
|
+
meridiem: newMeridiem,
|
|
5132
|
+
});
|
|
5133
|
+
setShowInput(false);
|
|
5134
|
+
};
|
|
5135
|
+
const handleKeyDown = (e) => {
|
|
5136
|
+
if (e.key === "Enter") {
|
|
5137
|
+
handleBlur(e.currentTarget.value);
|
|
5138
|
+
}
|
|
5139
|
+
};
|
|
5140
|
+
const inputRef = useRef(null);
|
|
5141
|
+
return (jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "200px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsx(Input, { onKeyDown: handleKeyDown, onChange: (e) => {
|
|
5142
|
+
setInputValue(e.currentTarget.value);
|
|
5143
|
+
}, onBlur: (e) => {
|
|
5144
|
+
handleBlur(e.currentTarget.value);
|
|
5145
|
+
}, onFocus: (e) => {
|
|
5146
|
+
e.currentTarget.select();
|
|
5147
|
+
}, value: inputValue, display: showInput ? undefined : "none", ref: inputRef }), jsxs(Button$1, { onClick: () => {
|
|
5148
|
+
setShowInput(true);
|
|
5149
|
+
setInputValue(dayjs(`1970-01-01T${getTimeString(hour, minute, meridiem)}`, "hh:mmZ").format("HH:mm"));
|
|
5150
|
+
inputRef.current?.focus();
|
|
5151
|
+
}, 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
|
|
5152
|
+
? dayjs(`1970-01-01T${stringTime}`, "hh:mmZ").format("hh:mm a")
|
|
5153
|
+
: "" })] }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }));
|
|
5154
|
+
}
|
|
5155
|
+
|
|
5156
|
+
dayjs.extend(timezone);
|
|
5157
|
+
const TimePicker = ({ column, schema, prefix }) => {
|
|
5158
|
+
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
5159
|
+
const { translate, timezone } = useSchemaContext();
|
|
5160
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
|
|
5161
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5162
|
+
const colLabel = `${prefix}${column}`;
|
|
5163
|
+
const [open, setOpen] = useState(false);
|
|
5164
|
+
const value = watch(colLabel);
|
|
5165
|
+
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
5166
|
+
? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
|
|
5167
|
+
: "";
|
|
5168
|
+
// Parse the initial time parts from the time string (HH:mm:ssZ)
|
|
5169
|
+
const parseTime = (time) => {
|
|
5170
|
+
if (!time)
|
|
5171
|
+
return { hour: 12, minute: 0, meridiem: "am" };
|
|
5172
|
+
const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
|
|
5173
|
+
if (!parsed.isValid()) {
|
|
5174
|
+
return { hour: 12, minute: 0, meridiem: "am" };
|
|
5175
|
+
}
|
|
5176
|
+
let hour = parsed.hour();
|
|
5177
|
+
const minute = parsed.minute();
|
|
5178
|
+
const meridiem = hour >= 12 ? "pm" : "am";
|
|
5179
|
+
if (hour === 0)
|
|
5180
|
+
hour = 12;
|
|
5181
|
+
else if (hour > 12)
|
|
5182
|
+
hour -= 12;
|
|
5183
|
+
return { hour, minute, meridiem };
|
|
5184
|
+
};
|
|
5185
|
+
const initialTime = parseTime(value);
|
|
5186
|
+
const [hour, setHour] = useState(initialTime.hour);
|
|
5187
|
+
const [minute, setMinute] = useState(initialTime.minute);
|
|
5188
|
+
const [meridiem, setMeridiem] = useState(initialTime.meridiem);
|
|
5189
|
+
useEffect(() => {
|
|
5190
|
+
const { hour, minute, meridiem } = parseTime(value);
|
|
5191
|
+
setHour(hour);
|
|
5192
|
+
setMinute(minute);
|
|
5193
|
+
setMeridiem(meridiem);
|
|
5194
|
+
}, [value]);
|
|
5195
|
+
const getTimeString = (hour, minute, meridiem) => {
|
|
5196
|
+
if (hour === null || minute === null || meridiem === null)
|
|
5197
|
+
return null;
|
|
5198
|
+
let newHour = hour;
|
|
5199
|
+
if (meridiem === "pm" && hour !== 12) {
|
|
5200
|
+
newHour = hour + 12;
|
|
5201
|
+
}
|
|
5202
|
+
return dayjs().tz(timezone).hour(newHour).minute(minute).second(0).format(timeFormat);
|
|
5203
|
+
};
|
|
5204
|
+
// Handle changes to time parts
|
|
5205
|
+
const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
|
|
5206
|
+
setHour(newHour);
|
|
5207
|
+
setMinute(newMinute);
|
|
5208
|
+
setMeridiem(newMeridiem);
|
|
5209
|
+
const timeString = getTimeString(newHour, newMinute, newMeridiem);
|
|
5210
|
+
setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
|
|
5211
|
+
};
|
|
5212
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5213
|
+
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: () => {
|
|
5214
|
+
setOpen(true);
|
|
5215
|
+
}, 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: {
|
|
5216
|
+
am: translate.t(`common.am`, { defaultValue: "AM" }),
|
|
5217
|
+
pm: translate.t(`common.pm`, { defaultValue: "PM" }),
|
|
5218
|
+
} }) }) }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
5219
|
+
};
|
|
5220
|
+
|
|
5221
|
+
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
|
|
5222
|
+
// Refs for focus management
|
|
5223
|
+
const hourInputRef = useRef(null);
|
|
5224
|
+
const minuteInputRef = useRef(null);
|
|
5225
|
+
const secondInputRef = useRef(null);
|
|
5226
|
+
// Centralized handler for key events, value changes, and focus management
|
|
5227
|
+
const handleKeyDown = (e, field) => {
|
|
5228
|
+
const input = e.target;
|
|
5229
|
+
const value = input.value;
|
|
5230
|
+
// Handle navigation between fields
|
|
5231
|
+
if (e.key === "Tab") {
|
|
5232
|
+
return;
|
|
5233
|
+
}
|
|
5234
|
+
if (e.key === ":" && field === "hour") {
|
|
5235
|
+
e.preventDefault();
|
|
5236
|
+
minuteInputRef.current?.focus();
|
|
5237
|
+
return;
|
|
5238
|
+
}
|
|
5239
|
+
if (e.key === ":" && field === "minute") {
|
|
5240
|
+
e.preventDefault();
|
|
5241
|
+
secondInputRef.current?.focus();
|
|
5242
|
+
return;
|
|
5243
|
+
}
|
|
5244
|
+
if (e.key === "Backspace" && value === "") {
|
|
5245
|
+
e.preventDefault();
|
|
5246
|
+
if (field === "minute") {
|
|
5247
|
+
hourInputRef.current?.focus();
|
|
5248
|
+
}
|
|
5249
|
+
else if (field === "second") {
|
|
5250
|
+
minuteInputRef.current?.focus();
|
|
5251
|
+
}
|
|
5252
|
+
return;
|
|
5253
|
+
}
|
|
5254
|
+
// Handle number inputs
|
|
5255
|
+
if (field === "hour") {
|
|
5256
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5257
|
+
const newValue = value + e.key;
|
|
5258
|
+
const numValue = parseInt(newValue, 10);
|
|
5259
|
+
if (numValue > 23) {
|
|
5260
|
+
const digitValue = parseInt(e.key, 10);
|
|
5261
|
+
setHour(digitValue);
|
|
5262
|
+
onChange({ hour: digitValue, minute, second });
|
|
5263
|
+
return;
|
|
5264
|
+
}
|
|
5265
|
+
if (numValue >= 0 && numValue <= 23) {
|
|
5266
|
+
setHour(numValue);
|
|
5267
|
+
onChange({ hour: numValue, minute, second });
|
|
5268
|
+
e.preventDefault();
|
|
5269
|
+
minuteInputRef.current?.focus();
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
else if (field === "minute") {
|
|
5274
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5275
|
+
const newValue = value + e.key;
|
|
5276
|
+
const numValue = parseInt(newValue, 10);
|
|
5277
|
+
if (numValue > 59) {
|
|
5278
|
+
const digitValue = parseInt(e.key, 10);
|
|
5279
|
+
setMinute(digitValue);
|
|
5280
|
+
onChange({ hour, minute: digitValue, second });
|
|
5281
|
+
return;
|
|
5282
|
+
}
|
|
5283
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5284
|
+
setMinute(numValue);
|
|
5285
|
+
onChange({ hour, minute: numValue, second });
|
|
5286
|
+
e.preventDefault();
|
|
5287
|
+
secondInputRef.current?.focus();
|
|
5288
|
+
}
|
|
5289
|
+
}
|
|
5290
|
+
}
|
|
5291
|
+
else if (field === "second") {
|
|
5292
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5293
|
+
const newValue = value + e.key;
|
|
5294
|
+
const numValue = parseInt(newValue, 10);
|
|
5295
|
+
if (numValue > 59) {
|
|
5296
|
+
const digitValue = parseInt(e.key, 10);
|
|
5297
|
+
setSecond(digitValue);
|
|
5298
|
+
onChange({ hour, minute, second: digitValue });
|
|
5299
|
+
return;
|
|
5300
|
+
}
|
|
5301
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5302
|
+
setSecond(numValue);
|
|
5303
|
+
onChange({ hour, minute, second: numValue });
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
};
|
|
5308
|
+
const handleClear = () => {
|
|
5309
|
+
setHour(null);
|
|
5310
|
+
setMinute(null);
|
|
5311
|
+
setSecond(null);
|
|
5312
|
+
onChange({ hour: null, minute: null, second: null });
|
|
5313
|
+
hourInputRef.current?.focus();
|
|
5314
|
+
};
|
|
5315
|
+
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, {}) })] }) }));
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
function DateTimePicker$1({ value, onChange, format = "date-time", showSeconds = false, labels = {
|
|
5319
|
+
monthNamesShort: [
|
|
5320
|
+
"Jan",
|
|
5321
|
+
"Feb",
|
|
5322
|
+
"Mar",
|
|
5323
|
+
"Apr",
|
|
5324
|
+
"May",
|
|
5325
|
+
"Jun",
|
|
5326
|
+
"Jul",
|
|
5327
|
+
"Aug",
|
|
5328
|
+
"Sep",
|
|
5329
|
+
"Oct",
|
|
5330
|
+
"Nov",
|
|
5331
|
+
"Dec",
|
|
5332
|
+
],
|
|
5333
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
5334
|
+
backButtonLabel: "Back",
|
|
5335
|
+
forwardButtonLabel: "Next",
|
|
5336
|
+
}, timezone = "Asia/Hong_Kong", }) {
|
|
5337
|
+
const [selectedDate, setSelectedDate] = useState(value || "");
|
|
5338
|
+
// Time state for 12-hour format
|
|
5339
|
+
const [hour12, setHour12] = useState(value ? dayjs(value).hour() % 12 || 12 : null);
|
|
5340
|
+
const [minute, setMinute] = useState(value ? dayjs(value).minute() : null);
|
|
5341
|
+
const [meridiem, setMeridiem] = useState(value ? (dayjs(value).hour() >= 12 ? "pm" : "am") : null);
|
|
5342
|
+
// Time state for 24-hour format
|
|
5343
|
+
const [hour24, setHour24] = useState(value ? dayjs(value).hour() : null);
|
|
5344
|
+
const [second, setSecond] = useState(value ? dayjs(value).second() : null);
|
|
5345
|
+
const handleDateChange = (date) => {
|
|
5346
|
+
setSelectedDate(date);
|
|
5347
|
+
updateDateTime(dayjs(date).tz(timezone).toISOString());
|
|
5348
|
+
};
|
|
5349
|
+
const handleTimeChange = (timeData) => {
|
|
5350
|
+
if (format === "iso-date-time") {
|
|
5351
|
+
setHour24(timeData.hour);
|
|
5352
|
+
setMinute(timeData.minute);
|
|
5353
|
+
if (showSeconds)
|
|
5354
|
+
setSecond(timeData.second);
|
|
5355
|
+
}
|
|
5356
|
+
else {
|
|
5357
|
+
setHour12(timeData.hour);
|
|
5358
|
+
setMinute(timeData.minute);
|
|
5359
|
+
setMeridiem(timeData.meridiem);
|
|
5360
|
+
}
|
|
5361
|
+
updateDateTime(dayjs(selectedDate).tz(timezone).toISOString(), timeData);
|
|
5362
|
+
};
|
|
5363
|
+
const updateDateTime = (date, timeData) => {
|
|
5364
|
+
if (!date) {
|
|
5365
|
+
onChange?.(undefined);
|
|
5366
|
+
return;
|
|
5367
|
+
}
|
|
5368
|
+
// use dayjs to convert the date to the timezone
|
|
5369
|
+
const newDate = dayjs(date).tz(timezone).toDate();
|
|
5370
|
+
if (format === "iso-date-time") {
|
|
5371
|
+
const h = timeData?.hour ?? hour24;
|
|
5372
|
+
const m = timeData?.minute ?? minute;
|
|
5373
|
+
const s = showSeconds ? timeData?.second ?? second : 0;
|
|
5374
|
+
if (h !== null)
|
|
5375
|
+
newDate.setHours(h);
|
|
5376
|
+
if (m !== null)
|
|
5377
|
+
newDate.setMinutes(m);
|
|
5378
|
+
if (s !== null)
|
|
5379
|
+
newDate.setSeconds(s);
|
|
5380
|
+
}
|
|
5381
|
+
else {
|
|
5382
|
+
const h = timeData?.hour ?? hour12;
|
|
5383
|
+
const m = timeData?.minute ?? minute;
|
|
5384
|
+
const mer = timeData?.meridiem ?? meridiem;
|
|
5385
|
+
if (h !== null && mer !== null) {
|
|
5386
|
+
let hour24 = h;
|
|
5387
|
+
if (mer === "am" && h === 12)
|
|
5388
|
+
hour24 = 0;
|
|
5389
|
+
else if (mer === "pm" && h < 12)
|
|
5390
|
+
hour24 = h + 12;
|
|
5391
|
+
newDate.setHours(hour24);
|
|
5392
|
+
}
|
|
5393
|
+
if (m !== null)
|
|
5394
|
+
newDate.setMinutes(m);
|
|
5395
|
+
newDate.setSeconds(0);
|
|
5396
|
+
}
|
|
5397
|
+
onChange?.(dayjs(newDate).tz(timezone).toISOString());
|
|
5398
|
+
};
|
|
5399
|
+
const handleClear = () => {
|
|
5400
|
+
setSelectedDate("");
|
|
5401
|
+
setHour12(null);
|
|
5402
|
+
setHour24(null);
|
|
5403
|
+
setMinute(null);
|
|
5404
|
+
setSecond(null);
|
|
5405
|
+
setMeridiem(null);
|
|
5406
|
+
onChange?.(undefined);
|
|
5407
|
+
};
|
|
5408
|
+
const isISO = format === "iso-date-time";
|
|
5409
|
+
return (jsxs(Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsx(DatePicker$1, { selected: selectedDate
|
|
5410
|
+
? dayjs(selectedDate).tz(timezone).toDate()
|
|
5411
|
+
: 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
|
|
5412
|
+
? showSeconds
|
|
5413
|
+
? "YYYY-MM-DD HH:mm:ss"
|
|
5414
|
+
: "YYYY-MM-DD HH:mm"
|
|
5415
|
+
: "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 })] }))] }));
|
|
5416
|
+
}
|
|
5417
|
+
|
|
5418
|
+
dayjs.extend(utc);
|
|
5419
|
+
dayjs.extend(timezone);
|
|
5420
|
+
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
5421
|
+
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
5422
|
+
const { translate, timezone } = useSchemaContext();
|
|
5423
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
|
|
5424
|
+
// with timezone
|
|
5425
|
+
dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
|
|
5426
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5427
|
+
const colLabel = `${prefix}${column}`;
|
|
5428
|
+
const [open, setOpen] = useState(false);
|
|
5429
|
+
const selectedDate = watch(colLabel);
|
|
5430
|
+
const displayDate = dayjs(selectedDate)
|
|
5431
|
+
.tz(timezone)
|
|
5432
|
+
.format(displayDateFormat);
|
|
5433
|
+
useEffect(() => {
|
|
5434
|
+
try {
|
|
5435
|
+
if (selectedDate) {
|
|
5436
|
+
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
5437
|
+
// For example, parse as UTC:
|
|
5438
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
5439
|
+
if (!parsedDate.isValid())
|
|
5440
|
+
return;
|
|
5441
|
+
// Format according to dateFormat from schema
|
|
5442
|
+
const formatted = parsedDate.format(dateFormat);
|
|
5443
|
+
// Update the form value only if different to avoid loops
|
|
5444
|
+
if (formatted !== selectedDate) {
|
|
5445
|
+
setValue(colLabel, formatted, {
|
|
5446
|
+
shouldValidate: true,
|
|
5447
|
+
shouldDirty: true,
|
|
5448
|
+
});
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5452
|
+
catch (e) {
|
|
5453
|
+
console.error(e);
|
|
5454
|
+
}
|
|
5455
|
+
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
5456
|
+
const customTranslate = (label) => {
|
|
5457
|
+
return translateWrapper({ prefix, column, label, translate });
|
|
5458
|
+
};
|
|
5459
|
+
return (jsxs(Field, { label: `${customTranslate(`field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5460
|
+
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: () => {
|
|
5461
|
+
setOpen(true);
|
|
5462
|
+
}, 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) => {
|
|
5463
|
+
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
5464
|
+
}, timezone: timezone, labels: {
|
|
5465
|
+
monthNamesShort: [
|
|
5466
|
+
translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
5467
|
+
translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
5468
|
+
translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
5469
|
+
translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
5470
|
+
translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
5471
|
+
translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
5472
|
+
translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
5473
|
+
translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
5474
|
+
translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
5475
|
+
translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
5476
|
+
translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
5477
|
+
translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
5478
|
+
],
|
|
5479
|
+
weekdayNamesShort: [
|
|
5480
|
+
translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
5481
|
+
translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
5482
|
+
translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
5483
|
+
translate.t(`common.weekday_4`, {
|
|
5484
|
+
defaultValue: "Wed",
|
|
5485
|
+
}),
|
|
5486
|
+
translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
5487
|
+
translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
5488
|
+
translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
5489
|
+
],
|
|
5490
|
+
backButtonLabel: translate.t(`common.back_button`, {
|
|
5491
|
+
defaultValue: "Back",
|
|
5492
|
+
}),
|
|
5493
|
+
forwardButtonLabel: translate.t(`common.forward_button`, {
|
|
5494
|
+
defaultValue: "Forward",
|
|
5495
|
+
}),
|
|
5496
|
+
} })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: customTranslate(`field_required`) }))] }));
|
|
5497
|
+
};
|
|
5498
|
+
|
|
4537
5499
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
4538
5500
|
const colSchema = schema;
|
|
4539
|
-
const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
|
|
5501
|
+
const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
|
|
5502
|
+
if (variant === "custom-input") {
|
|
5503
|
+
return jsx(CustomInput, { schema: colSchema, prefix, column });
|
|
5504
|
+
}
|
|
4540
5505
|
if (type === "string") {
|
|
4541
5506
|
if ((schema.enum ?? []).length > 0) {
|
|
4542
5507
|
return jsx(EnumPicker, { schema: colSchema, prefix, column });
|
|
@@ -4545,9 +5510,18 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
4545
5510
|
idPickerSanityCheck(column, foreign_key);
|
|
4546
5511
|
return jsx(IdPicker, { schema: colSchema, prefix, column });
|
|
4547
5512
|
}
|
|
4548
|
-
if (
|
|
5513
|
+
if (format === "date") {
|
|
4549
5514
|
return jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
4550
5515
|
}
|
|
5516
|
+
if (format === "time") {
|
|
5517
|
+
return jsx(TimePicker, { schema: colSchema, prefix, column });
|
|
5518
|
+
}
|
|
5519
|
+
if (format === "date-time") {
|
|
5520
|
+
return jsx(DateTimePicker, { schema: colSchema, prefix, column });
|
|
5521
|
+
}
|
|
5522
|
+
if (variant === "text-area") {
|
|
5523
|
+
return jsx(TextAreaInput, { schema: colSchema, prefix, column });
|
|
5524
|
+
}
|
|
4551
5525
|
return jsx(StringInputField, { schema: colSchema, prefix, column });
|
|
4552
5526
|
}
|
|
4553
5527
|
if (type === "number" || type === "integer") {
|
|
@@ -4573,6 +5547,15 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
4573
5547
|
if (variant === "file-picker") {
|
|
4574
5548
|
return jsx(FilePicker, { schema: colSchema, prefix, column });
|
|
4575
5549
|
}
|
|
5550
|
+
if (variant === "enum-picker") {
|
|
5551
|
+
const { items } = colSchema;
|
|
5552
|
+
const { enum: enumItems } = items;
|
|
5553
|
+
const enumSchema = {
|
|
5554
|
+
type: "string",
|
|
5555
|
+
enum: enumItems,
|
|
5556
|
+
};
|
|
5557
|
+
return (jsx(EnumPicker, { isMultiple: true, schema: enumSchema, prefix, column }));
|
|
5558
|
+
}
|
|
4576
5559
|
if (items) {
|
|
4577
5560
|
return jsx(ArrayRenderer, { schema: colSchema, prefix, column });
|
|
4578
5561
|
}
|
|
@@ -4594,39 +5577,56 @@ const ColumnRenderer = ({ column, properties, prefix, }) => {
|
|
|
4594
5577
|
};
|
|
4595
5578
|
|
|
4596
5579
|
const ArrayViewer = ({ schema, column, prefix }) => {
|
|
4597
|
-
const {
|
|
5580
|
+
const { gridColumn = "span 12", gridRow = "span 1", required, items, } = schema;
|
|
4598
5581
|
const { translate } = useSchemaContext();
|
|
4599
5582
|
const colLabel = `${prefix}${column}`;
|
|
4600
5583
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4601
5584
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4602
5585
|
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
|
-
|
|
5586
|
+
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: {
|
|
5587
|
+
base: "colorPalette.200",
|
|
5588
|
+
_dark: "colorPalette.800",
|
|
5589
|
+
}, children: jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsx(SchemaViewer, { column: `${index}`,
|
|
5590
|
+
prefix: `${colLabel}.`,
|
|
5591
|
+
// @ts-expect-error find suitable types
|
|
5592
|
+
schema: { showLabel: false, ...(items ?? {}) } }) }) }, `form-${prefix}${column}.${index}`))) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4606
5593
|
};
|
|
4607
5594
|
|
|
4608
5595
|
const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
4609
5596
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4610
5597
|
const { translate } = useSchemaContext();
|
|
4611
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5598
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
4612
5599
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4613
5600
|
const colLabel = `${prefix}${column}`;
|
|
4614
5601
|
const value = watch(colLabel);
|
|
4615
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
5602
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4616
5603
|
gridRow, children: [jsx(Text, { children: value
|
|
4617
5604
|
? translate.t(removeIndex(`${colLabel}.true`))
|
|
4618
|
-
: translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
5605
|
+
: translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
5606
|
+
};
|
|
5607
|
+
|
|
5608
|
+
const CustomViewer = ({ column, schema, prefix }) => {
|
|
5609
|
+
const formContext = useFormContext();
|
|
5610
|
+
const { inputViewerRender } = schema;
|
|
5611
|
+
return (inputViewerRender &&
|
|
5612
|
+
inputViewerRender({
|
|
5613
|
+
column,
|
|
5614
|
+
schema,
|
|
5615
|
+
prefix,
|
|
5616
|
+
formContext,
|
|
5617
|
+
}));
|
|
4619
5618
|
};
|
|
4620
5619
|
|
|
4621
5620
|
const DateViewer = ({ column, schema, prefix }) => {
|
|
4622
5621
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4623
|
-
const { translate } = useSchemaContext();
|
|
4624
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5622
|
+
const { translate, timezone } = useSchemaContext();
|
|
5623
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", } = schema;
|
|
4625
5624
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4626
5625
|
const colLabel = `${prefix}${column}`;
|
|
4627
5626
|
const selectedDate = watch(colLabel);
|
|
4628
|
-
|
|
4629
|
-
|
|
5627
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5628
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5629
|
+
gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
4630
5630
|
};
|
|
4631
5631
|
|
|
4632
5632
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
@@ -4634,45 +5634,41 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
4634
5634
|
const { translate } = useSchemaContext();
|
|
4635
5635
|
const { required } = schema;
|
|
4636
5636
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4637
|
-
const { gridColumn, gridRow, renderDisplay } = schema;
|
|
5637
|
+
const { gridColumn = "span 4", gridRow = "span 1", renderDisplay } = schema;
|
|
4638
5638
|
const colLabel = `${prefix}${column}`;
|
|
4639
5639
|
const watchEnum = watch(colLabel);
|
|
4640
5640
|
const watchEnums = (watch(colLabel) ?? []);
|
|
4641
|
-
|
|
5641
|
+
const customTranslate = (label) => {
|
|
5642
|
+
return translateWrapper({ prefix, column, label, translate });
|
|
5643
|
+
};
|
|
5644
|
+
return (jsxs(Field, { label: `${customTranslate(`field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4642
5645
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: "wrap", gap: 1, children: watchEnums.map((enumValue) => {
|
|
4643
5646
|
const item = enumValue;
|
|
4644
5647
|
if (item === undefined) {
|
|
4645
5648
|
return jsx(Fragment, { children: "undefined" });
|
|
4646
5649
|
}
|
|
4647
|
-
return (jsx(Tag, {
|
|
5650
|
+
return (jsx(Tag, { size: "lg", children: !!renderDisplay === true
|
|
4648
5651
|
? renderDisplay(item)
|
|
4649
|
-
:
|
|
4650
|
-
}) })), !isMultiple &&
|
|
5652
|
+
: customTranslate(item) }, item));
|
|
5653
|
+
}) })), !isMultiple && jsx(Text, { children: customTranslate(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: customTranslate(`field_required`) }))] }));
|
|
4651
5654
|
};
|
|
4652
5655
|
|
|
4653
5656
|
const FileViewer = ({ column, schema, prefix }) => {
|
|
4654
|
-
const {
|
|
5657
|
+
const { watch } = useFormContext();
|
|
4655
5658
|
const { translate } = useSchemaContext();
|
|
4656
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5659
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", } = schema;
|
|
4657
5660
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4658
5661
|
const currentFiles = (watch(column) ?? []);
|
|
4659
5662
|
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`)) }))] }));
|
|
5663
|
+
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) => {
|
|
5664
|
+
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));
|
|
5665
|
+
}) }) }));
|
|
4670
5666
|
};
|
|
4671
5667
|
|
|
4672
5668
|
const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
4673
5669
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4674
5670
|
const { idMap, translate } = useSchemaContext();
|
|
4675
|
-
const { required, gridColumn, gridRow, renderDisplay, foreign_key } = schema;
|
|
5671
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
|
|
4676
5672
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4677
5673
|
const { display_column } = foreign_key;
|
|
4678
5674
|
const colLabel = `${prefix}${column}`;
|
|
@@ -4688,7 +5684,7 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4688
5684
|
}
|
|
4689
5685
|
return record[display_column];
|
|
4690
5686
|
};
|
|
4691
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.
|
|
5687
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
4692
5688
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: "wrap", gap: 1, children: watchIds.map((id) => {
|
|
4693
5689
|
const item = idMap[id];
|
|
4694
5690
|
if (item === undefined) {
|
|
@@ -4697,21 +5693,21 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4697
5693
|
return (jsx(Tag, { closable: true, children: !!renderDisplay === true
|
|
4698
5694
|
? renderDisplay(item)
|
|
4699
5695
|
: item[display_column] }, id));
|
|
4700
|
-
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
5696
|
+
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4701
5697
|
};
|
|
4702
5698
|
|
|
4703
5699
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
4704
5700
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4705
5701
|
const { translate } = useSchemaContext();
|
|
4706
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5702
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
4707
5703
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4708
5704
|
const colLabel = `${prefix}${column}`;
|
|
4709
5705
|
const value = watch(colLabel);
|
|
4710
|
-
return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
5706
|
+
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
5707
|
};
|
|
4712
5708
|
|
|
4713
5709
|
const ObjectViewer = ({ schema, column, prefix }) => {
|
|
4714
|
-
const { properties,
|
|
5710
|
+
const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
|
|
4715
5711
|
const { translate } = useSchemaContext();
|
|
4716
5712
|
const colLabel = `${prefix}${column}`;
|
|
4717
5713
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
@@ -4719,25 +5715,28 @@ const ObjectViewer = ({ schema, column, prefix }) => {
|
|
|
4719
5715
|
if (properties === undefined) {
|
|
4720
5716
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
4721
5717
|
}
|
|
4722
|
-
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label",
|
|
5718
|
+
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: {
|
|
5719
|
+
base: "colorPalette.200",
|
|
5720
|
+
_dark: "colorPalette.800",
|
|
5721
|
+
}, children: Object.keys(properties ?? {}).map((key) => {
|
|
4723
5722
|
return (
|
|
4724
5723
|
// @ts-expect-error find suitable types
|
|
4725
5724
|
jsx(ColumnViewer, { column: `${key}`,
|
|
4726
5725
|
prefix: `${prefix}${column}.`,
|
|
4727
5726
|
properties }, `form-objectviewer-${colLabel}-${key}`));
|
|
4728
|
-
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.
|
|
5727
|
+
}) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4729
5728
|
};
|
|
4730
5729
|
|
|
4731
5730
|
const RecordInput = ({ column, schema, prefix }) => {
|
|
4732
5731
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
4733
5732
|
const { translate } = useSchemaContext();
|
|
4734
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5733
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
4735
5734
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4736
5735
|
const entries = Object.entries(getValues(column) ?? {});
|
|
4737
5736
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
4738
5737
|
const [newKey, setNewKey] = useState();
|
|
4739
5738
|
const [newValue, setNewValue] = useState();
|
|
4740
|
-
return (jsxs(Field, { label: `${translate.t(`${column}.
|
|
5739
|
+
return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
|
|
4741
5740
|
return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
4742
5741
|
const filtered = entries.filter(([target]) => {
|
|
4743
5742
|
return target !== key;
|
|
@@ -4777,7 +5776,17 @@ const RecordInput = ({ column, schema, prefix }) => {
|
|
|
4777
5776
|
setShowNewEntries(true);
|
|
4778
5777
|
setNewKey(undefined);
|
|
4779
5778
|
setNewValue(undefined);
|
|
4780
|
-
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.
|
|
5779
|
+
}, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5780
|
+
};
|
|
5781
|
+
|
|
5782
|
+
const StringViewer = ({ column, schema, prefix, }) => {
|
|
5783
|
+
const { watch, formState: { errors }, } = useFormContext();
|
|
5784
|
+
const { translate } = useSchemaContext();
|
|
5785
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
5786
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5787
|
+
const colLabel = `${prefix}${column}`;
|
|
5788
|
+
const value = watch(colLabel);
|
|
5789
|
+
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
5790
|
};
|
|
4782
5791
|
|
|
4783
5792
|
const TagViewer = ({ column, schema, prefix }) => {
|
|
@@ -4865,19 +5874,50 @@ const TagViewer = ({ column, schema, prefix }) => {
|
|
|
4865
5874
|
}), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
|
|
4866
5875
|
};
|
|
4867
5876
|
|
|
4868
|
-
const
|
|
5877
|
+
const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
4869
5878
|
const { watch, formState: { errors }, } = useFormContext();
|
|
4870
5879
|
const { translate } = useSchemaContext();
|
|
4871
|
-
const { required, gridColumn, gridRow } = schema;
|
|
5880
|
+
const { required, gridColumn = "span 4", gridRow = "span 1" } = schema;
|
|
4872
5881
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4873
5882
|
const colLabel = `${prefix}${column}`;
|
|
4874
5883
|
const value = watch(colLabel);
|
|
4875
|
-
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.
|
|
5884
|
+
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`)) }))] }) }));
|
|
5885
|
+
};
|
|
5886
|
+
|
|
5887
|
+
const TimeViewer = ({ column, schema, prefix }) => {
|
|
5888
|
+
const { watch, formState: { errors }, } = useFormContext();
|
|
5889
|
+
const { translate, timezone } = useSchemaContext();
|
|
5890
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayTimeFormat = "hh:mm A", } = schema;
|
|
5891
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5892
|
+
const colLabel = `${prefix}${column}`;
|
|
5893
|
+
const selectedDate = watch(colLabel);
|
|
5894
|
+
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
5895
|
+
.tz(timezone)
|
|
5896
|
+
.isValid()
|
|
5897
|
+
? dayjs(`1970-01-01T${selectedDate}`).tz(timezone).format(displayTimeFormat)
|
|
5898
|
+
: "";
|
|
5899
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5900
|
+
gridRow, children: [jsx(Text, { children: displayedTime }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5901
|
+
};
|
|
5902
|
+
|
|
5903
|
+
const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
5904
|
+
const { watch, formState: { errors }, } = useFormContext();
|
|
5905
|
+
const { translate, timezone } = useSchemaContext();
|
|
5906
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss", } = schema;
|
|
5907
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5908
|
+
const colLabel = `${prefix}${column}`;
|
|
5909
|
+
const selectedDate = watch(colLabel);
|
|
5910
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5911
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5912
|
+
gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
4876
5913
|
};
|
|
4877
5914
|
|
|
4878
5915
|
const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
4879
5916
|
const colSchema = schema;
|
|
4880
|
-
const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
|
|
5917
|
+
const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
|
|
5918
|
+
if (variant === "custom-input") {
|
|
5919
|
+
return jsx(CustomViewer, { schema: colSchema, prefix, column });
|
|
5920
|
+
}
|
|
4881
5921
|
if (type === "string") {
|
|
4882
5922
|
if ((schema.enum ?? []).length > 0) {
|
|
4883
5923
|
return jsx(EnumViewer, { schema: colSchema, prefix, column });
|
|
@@ -4886,9 +5926,18 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
4886
5926
|
idPickerSanityCheck(column, foreign_key);
|
|
4887
5927
|
return jsx(IdViewer, { schema: colSchema, prefix, column });
|
|
4888
5928
|
}
|
|
4889
|
-
if (
|
|
5929
|
+
if (format === "time") {
|
|
5930
|
+
return jsx(TimeViewer, { schema: colSchema, prefix, column });
|
|
5931
|
+
}
|
|
5932
|
+
if (format === "date") {
|
|
4890
5933
|
return jsx(DateViewer, { schema: colSchema, prefix, column });
|
|
4891
5934
|
}
|
|
5935
|
+
if (format === "date-time") {
|
|
5936
|
+
return jsx(DateTimeViewer, { schema: colSchema, prefix, column });
|
|
5937
|
+
}
|
|
5938
|
+
if (variant === "text-area") {
|
|
5939
|
+
return jsx(TextAreaViewer, { schema: colSchema, prefix, column });
|
|
5940
|
+
}
|
|
4892
5941
|
return jsx(StringViewer, { schema: colSchema, prefix, column });
|
|
4893
5942
|
}
|
|
4894
5943
|
if (type === "number" || type === "integer") {
|
|
@@ -4914,6 +5963,15 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
4914
5963
|
if (variant === "file-picker") {
|
|
4915
5964
|
return jsx(FileViewer, { schema: colSchema, prefix, column });
|
|
4916
5965
|
}
|
|
5966
|
+
if (variant === "enum-picker") {
|
|
5967
|
+
const { items } = schema;
|
|
5968
|
+
const { enum: enumItems } = items;
|
|
5969
|
+
const enumSchema = {
|
|
5970
|
+
type: "string",
|
|
5971
|
+
enum: enumItems,
|
|
5972
|
+
};
|
|
5973
|
+
return (jsx(EnumViewer, { isMultiple: true, schema: enumSchema, prefix, column }));
|
|
5974
|
+
}
|
|
4917
5975
|
if (items) {
|
|
4918
5976
|
return jsx(ArrayViewer, { schema: colSchema, prefix, column });
|
|
4919
5977
|
}
|
|
@@ -4937,10 +5995,20 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
4937
5995
|
};
|
|
4938
5996
|
|
|
4939
5997
|
const SubmitButton = () => {
|
|
4940
|
-
const { translate, setValidatedData, setIsError, setIsConfirming } = useSchemaContext();
|
|
5998
|
+
const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, } = useSchemaContext();
|
|
4941
5999
|
const methods = useFormContext();
|
|
4942
6000
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4943
6001
|
const onValid = (data) => {
|
|
6002
|
+
const { isValid, errors } = validateData(data, schema);
|
|
6003
|
+
if (!isValid) {
|
|
6004
|
+
setError({
|
|
6005
|
+
type: "validation",
|
|
6006
|
+
errors,
|
|
6007
|
+
});
|
|
6008
|
+
setIsError(true);
|
|
6009
|
+
return;
|
|
6010
|
+
}
|
|
6011
|
+
// If validation passes, proceed to confirmation
|
|
4944
6012
|
setValidatedData(data);
|
|
4945
6013
|
setIsError(false);
|
|
4946
6014
|
setIsConfirming(true);
|
|
@@ -4951,7 +6019,8 @@ const SubmitButton = () => {
|
|
|
4951
6019
|
};
|
|
4952
6020
|
|
|
4953
6021
|
const FormBody = () => {
|
|
4954
|
-
const { schema, requestUrl, order, ignore, include, onSubmit,
|
|
6022
|
+
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();
|
|
6023
|
+
const { showSubmitButton, showResetButton } = displayConfig;
|
|
4955
6024
|
const methods = useFormContext();
|
|
4956
6025
|
const { properties } = schema;
|
|
4957
6026
|
const onBeforeSubmit = () => {
|
|
@@ -4967,6 +6036,26 @@ const FormBody = () => {
|
|
|
4967
6036
|
const onSubmitSuccess = () => {
|
|
4968
6037
|
setIsSuccess(true);
|
|
4969
6038
|
};
|
|
6039
|
+
const validateFormData = (data) => {
|
|
6040
|
+
try {
|
|
6041
|
+
const { isValid, errors } = validateData(data, schema);
|
|
6042
|
+
return {
|
|
6043
|
+
isValid,
|
|
6044
|
+
errors,
|
|
6045
|
+
};
|
|
6046
|
+
}
|
|
6047
|
+
catch (error) {
|
|
6048
|
+
return {
|
|
6049
|
+
isValid: false,
|
|
6050
|
+
errors: [
|
|
6051
|
+
{
|
|
6052
|
+
field: "validation",
|
|
6053
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
6054
|
+
},
|
|
6055
|
+
],
|
|
6056
|
+
};
|
|
6057
|
+
}
|
|
6058
|
+
};
|
|
4970
6059
|
const defaultOnSubmit = async (promise) => {
|
|
4971
6060
|
try {
|
|
4972
6061
|
onBeforeSubmit();
|
|
@@ -4991,12 +6080,28 @@ const FormBody = () => {
|
|
|
4991
6080
|
};
|
|
4992
6081
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4993
6082
|
const onFormSubmit = async (data) => {
|
|
6083
|
+
// Validate data using AJV before submission
|
|
6084
|
+
const validationResult = validateFormData(data);
|
|
6085
|
+
if (!validationResult.isValid) {
|
|
6086
|
+
// Set validation errors
|
|
6087
|
+
const validationErrorMessage = {
|
|
6088
|
+
type: "validation",
|
|
6089
|
+
errors: validationResult.errors,
|
|
6090
|
+
message: translate.t("validation_error"),
|
|
6091
|
+
};
|
|
6092
|
+
onSubmitError(validationErrorMessage);
|
|
6093
|
+
return;
|
|
6094
|
+
}
|
|
4994
6095
|
if (onSubmit === undefined) {
|
|
4995
6096
|
await defaultOnSubmit(defaultSubmitPromise(data));
|
|
4996
6097
|
return;
|
|
4997
6098
|
}
|
|
4998
6099
|
await defaultOnSubmit(onSubmit(data));
|
|
4999
6100
|
};
|
|
6101
|
+
// Custom error renderer for validation errors with i18n support
|
|
6102
|
+
const renderValidationErrors = (validationErrors) => {
|
|
6103
|
+
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))) }));
|
|
6104
|
+
};
|
|
5000
6105
|
const renderColumns = ({ order, keys, ignore, include, }) => {
|
|
5001
6106
|
const included = include.length > 0 ? include : keys;
|
|
5002
6107
|
const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
|
|
@@ -5011,7 +6116,7 @@ const FormBody = () => {
|
|
|
5011
6116
|
include,
|
|
5012
6117
|
});
|
|
5013
6118
|
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("
|
|
6119
|
+
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
6120
|
setIsError(false);
|
|
5016
6121
|
setIsSubmiting(false);
|
|
5017
6122
|
setIsSuccess(false);
|
|
@@ -5019,10 +6124,10 @@ const FormBody = () => {
|
|
|
5019
6124
|
setValidatedData(undefined);
|
|
5020
6125
|
const data = await getUpdatedData();
|
|
5021
6126
|
methods.reset(data);
|
|
5022
|
-
}, formNoValidate: true, children: translate.t("
|
|
6127
|
+
}, formNoValidate: true, children: translate.t("submit_again") }) })] }));
|
|
5023
6128
|
}
|
|
5024
6129
|
if (isConfirming) {
|
|
5025
|
-
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows:
|
|
6130
|
+
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
6131
|
return (jsx(ColumnViewer
|
|
5027
6132
|
// @ts-expect-error find suitable types
|
|
5028
6133
|
, {
|
|
@@ -5032,17 +6137,19 @@ const FormBody = () => {
|
|
|
5032
6137
|
setIsConfirming(false);
|
|
5033
6138
|
}, variant: "subtle", children: translate.t("cancel") }), jsx(Button$1, { onClick: () => {
|
|
5034
6139
|
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:
|
|
6140
|
+
}, 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" &&
|
|
6141
|
+
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
6142
|
}
|
|
5037
|
-
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)",
|
|
6143
|
+
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: ordered.map((column) => {
|
|
5038
6144
|
return (jsx(ColumnRenderer
|
|
5039
6145
|
// @ts-expect-error find suitable types
|
|
5040
6146
|
, {
|
|
5041
6147
|
// @ts-expect-error find suitable types
|
|
5042
6148
|
properties: properties, prefix: ``, column }, `form-input-${column}`));
|
|
5043
|
-
}) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [jsx(Button$1, { onClick: () => {
|
|
6149
|
+
}) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
|
|
5044
6150
|
methods.reset();
|
|
5045
|
-
}, variant: "subtle", children: translate.t("reset") }), jsx(SubmitButton, {})] })
|
|
6151
|
+
}, variant: "subtle", children: translate.t("reset") })), showSubmitButton && jsx(SubmitButton, {})] }), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
|
|
6152
|
+
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
6153
|
};
|
|
5047
6154
|
|
|
5048
6155
|
const FormTitle = () => {
|
|
@@ -5051,7 +6158,8 @@ const FormTitle = () => {
|
|
|
5051
6158
|
};
|
|
5052
6159
|
|
|
5053
6160
|
const DefaultForm = ({ formConfig, }) => {
|
|
5054
|
-
|
|
6161
|
+
const { showTitle } = formConfig.displayConfig ?? {};
|
|
6162
|
+
return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
|
|
5055
6163
|
};
|
|
5056
6164
|
|
|
5057
6165
|
const useForm = ({ preLoadedValues, keyPrefix }) => {
|
|
@@ -5084,4 +6192,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
|
|
|
5084
6192
|
}
|
|
5085
6193
|
};
|
|
5086
6194
|
|
|
5087
|
-
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog,
|
|
6195
|
+
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 };
|