@bsol-oss/react-datatable5 12.0.0-beta.95 → 13.0.1-beta.1
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 +1 -0
- package/dist/index.d.ts +166 -41
- package/dist/index.js +1220 -652
- package/dist/index.mjs +1222 -655
- package/dist/types/components/DataTable/DataTable.d.ts +1 -3
- package/dist/types/components/DataTable/DataTableServer.d.ts +7 -9
- package/dist/types/components/DataTable/context/DataTableContext.d.ts +4 -6
- package/dist/types/components/DataTable/controls/MobileTableControls.d.ts +29 -0
- package/dist/types/components/DataTable/controls/TableControls.d.ts +2 -2
- package/dist/types/components/DataTable/display/CalendarDisplay.d.ts +84 -0
- package/dist/types/components/DataTable/display/DataDisplay.d.ts +0 -2
- package/dist/types/components/DataTable/display/MobileTableDisplay.d.ts +5 -0
- package/dist/types/components/DataTable/display/RecordDisplay.d.ts +1 -3
- package/dist/types/components/DataTable/hooks/useIsMobile.d.ts +6 -0
- package/dist/types/components/DataTable/useDataTable.d.ts +3 -6
- package/dist/types/components/DataTable/useDataTableServer.d.ts +4 -4
- package/dist/types/components/DataTable/utils/getColumns.d.ts +3 -5
- package/dist/types/components/DatePicker/DatePicker.d.ts +7 -8
- package/dist/types/components/DatePicker/DateTimePicker.d.ts +3 -1
- package/dist/types/components/DatePicker/IsoTimePicker.d.ts +5 -1
- package/dist/types/components/DatePicker/RangeDatePicker.d.ts +4 -4
- package/dist/types/components/DatePicker/useCalendar.d.ts +48 -0
- package/dist/types/components/Form/SchemaFormContext.d.ts +5 -3
- package/dist/types/components/Form/components/core/FormBody.d.ts +1 -2
- package/dist/types/components/Form/components/core/FormRoot.d.ts +6 -4
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +1 -2
- package/dist/types/components/Form/components/fields/IdPicker.d.ts +8 -0
- package/dist/types/components/Form/components/fields/IdPickerMultiple.d.ts +7 -0
- package/dist/types/components/Form/components/fields/IdPickerSingle.d.ts +7 -0
- package/dist/types/components/Form/components/fields/useIdPickerData.d.ts +68 -0
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +9 -0
- package/dist/types/components/Form/useForm.d.ts +7 -2
- package/dist/types/components/Form/utils/useFormI18n.d.ts +14 -12
- package/dist/types/components/TimePicker/TimePicker.d.ts +4 -6
- package/dist/types/components/ui/provider.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -3
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
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, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, Skeleton, NumberInput, Show, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading } from '@chakra-ui/react';
|
|
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, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, Skeleton, NumberInput, Show, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading, Stack } from '@chakra-ui/react';
|
|
3
3
|
import { AiOutlineColumnWidth } from 'react-icons/ai';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import
|
|
5
|
+
import { createContext, useContext, useState, useMemo, useCallback, useEffect, useRef, forwardRef } from 'react';
|
|
6
6
|
import { LuX, LuCheck, LuChevronRight, LuCopy, LuExternalLink, LuSearch, LuImage, LuFile } from 'react-icons/lu';
|
|
7
7
|
import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineChecklist, MdClear, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdDateRange } from 'react-icons/md';
|
|
8
8
|
import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
|
|
9
9
|
import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
|
|
10
10
|
import { CgClose, CgTrash } from 'react-icons/cg';
|
|
11
|
-
import Dayzed from '@bsol-oss/dayzed-react19';
|
|
12
11
|
import { HiMiniEllipsisHorizontal, HiChevronLeft, HiChevronRight } from 'react-icons/hi2';
|
|
13
12
|
import { IoMdEye, IoMdCheckbox, IoMdClock } from 'react-icons/io';
|
|
14
13
|
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
@@ -24,7 +23,6 @@ import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
|
|
|
24
23
|
import { HiColorSwatch } from 'react-icons/hi';
|
|
25
24
|
import { flexRender, createColumnHelper, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel } from '@tanstack/react-table';
|
|
26
25
|
import { GrAscend, GrDescend } from 'react-icons/gr';
|
|
27
|
-
import { useTranslation } from 'react-i18next';
|
|
28
26
|
import axios from 'axios';
|
|
29
27
|
import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
|
|
30
28
|
import Ajv from 'ajv';
|
|
@@ -38,36 +36,35 @@ import { rankItem } from '@tanstack/match-sorter-utils';
|
|
|
38
36
|
|
|
39
37
|
const DataTableContext = createContext({
|
|
40
38
|
table: {},
|
|
41
|
-
globalFilter:
|
|
39
|
+
globalFilter: '',
|
|
42
40
|
setGlobalFilter: () => { },
|
|
43
|
-
type:
|
|
44
|
-
translate: {},
|
|
41
|
+
type: 'client',
|
|
45
42
|
data: [],
|
|
46
43
|
columns: [],
|
|
47
44
|
columnOrder: [],
|
|
48
45
|
columnFilters: [],
|
|
49
|
-
density:
|
|
46
|
+
density: 'sm',
|
|
50
47
|
sorting: [],
|
|
51
48
|
setPagination: function () {
|
|
52
|
-
throw new Error(
|
|
49
|
+
throw new Error('Function not implemented.');
|
|
53
50
|
},
|
|
54
51
|
setSorting: function () {
|
|
55
|
-
throw new Error(
|
|
52
|
+
throw new Error('Function not implemented.');
|
|
56
53
|
},
|
|
57
54
|
setColumnFilters: function () {
|
|
58
|
-
throw new Error(
|
|
55
|
+
throw new Error('Function not implemented.');
|
|
59
56
|
},
|
|
60
57
|
setRowSelection: function () {
|
|
61
|
-
throw new Error(
|
|
58
|
+
throw new Error('Function not implemented.');
|
|
62
59
|
},
|
|
63
60
|
setColumnOrder: function () {
|
|
64
|
-
throw new Error(
|
|
61
|
+
throw new Error('Function not implemented.');
|
|
65
62
|
},
|
|
66
63
|
setDensity: function () {
|
|
67
|
-
throw new Error(
|
|
64
|
+
throw new Error('Function not implemented.');
|
|
68
65
|
},
|
|
69
66
|
setColumnVisibility: function () {
|
|
70
|
-
throw new Error(
|
|
67
|
+
throw new Error('Function not implemented.');
|
|
71
68
|
},
|
|
72
69
|
pagination: {
|
|
73
70
|
pageIndex: 0,
|
|
@@ -76,21 +73,21 @@ const DataTableContext = createContext({
|
|
|
76
73
|
rowSelection: {},
|
|
77
74
|
columnVisibility: {},
|
|
78
75
|
tableLabel: {
|
|
79
|
-
view:
|
|
80
|
-
edit:
|
|
81
|
-
filterButtonText:
|
|
82
|
-
filterTitle:
|
|
83
|
-
filterReset:
|
|
84
|
-
filterClose:
|
|
85
|
-
reloadTooltip:
|
|
86
|
-
reloadButtonText:
|
|
87
|
-
resetSelection:
|
|
88
|
-
resetSorting:
|
|
89
|
-
rowCountText:
|
|
90
|
-
hasErrorText:
|
|
91
|
-
globalFilterPlaceholder:
|
|
92
|
-
trueLabel:
|
|
93
|
-
falseLabel:
|
|
76
|
+
view: 'View',
|
|
77
|
+
edit: 'Edit',
|
|
78
|
+
filterButtonText: 'Filter',
|
|
79
|
+
filterTitle: 'Filter',
|
|
80
|
+
filterReset: 'Reset',
|
|
81
|
+
filterClose: 'Close',
|
|
82
|
+
reloadTooltip: 'Reload',
|
|
83
|
+
reloadButtonText: 'Reload',
|
|
84
|
+
resetSelection: 'Reset Selection',
|
|
85
|
+
resetSorting: 'Reset Sorting',
|
|
86
|
+
rowCountText: '',
|
|
87
|
+
hasErrorText: 'Has Error',
|
|
88
|
+
globalFilterPlaceholder: 'Search',
|
|
89
|
+
trueLabel: 'True',
|
|
90
|
+
falseLabel: 'False',
|
|
94
91
|
},
|
|
95
92
|
});
|
|
96
93
|
|
|
@@ -167,6 +164,166 @@ const Radio = React.forwardRef(function Radio(props, ref) {
|
|
|
167
164
|
});
|
|
168
165
|
const RadioGroup = RadioGroup$1.Root;
|
|
169
166
|
|
|
167
|
+
// Helper function to check if two dates are the same day
|
|
168
|
+
function isSameDay(date1, date2) {
|
|
169
|
+
return (date1.getFullYear() === date2.getFullYear() &&
|
|
170
|
+
date1.getMonth() === date2.getMonth() &&
|
|
171
|
+
date1.getDate() === date2.getDate());
|
|
172
|
+
}
|
|
173
|
+
// Helper function to check if a date is today
|
|
174
|
+
function isToday(date) {
|
|
175
|
+
const today = new Date();
|
|
176
|
+
return isSameDay(date, today);
|
|
177
|
+
}
|
|
178
|
+
// Helper function to check if a date is selected
|
|
179
|
+
function isSelected(date, selected) {
|
|
180
|
+
if (!selected)
|
|
181
|
+
return false;
|
|
182
|
+
if (Array.isArray(selected)) {
|
|
183
|
+
return selected.some((d) => isSameDay(d, date));
|
|
184
|
+
}
|
|
185
|
+
return isSameDay(selected, date);
|
|
186
|
+
}
|
|
187
|
+
// Helper function to check if a date is selectable
|
|
188
|
+
function isSelectable(date, minDate, maxDate) {
|
|
189
|
+
if (minDate) {
|
|
190
|
+
// Normalize to start of day for comparison
|
|
191
|
+
const minDateStart = new Date(minDate);
|
|
192
|
+
minDateStart.setHours(0, 0, 0, 0);
|
|
193
|
+
const dateStart = new Date(date);
|
|
194
|
+
dateStart.setHours(0, 0, 0, 0);
|
|
195
|
+
if (dateStart < minDateStart)
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
if (maxDate) {
|
|
199
|
+
// Normalize to start of day for comparison
|
|
200
|
+
const maxDateStart = new Date(maxDate);
|
|
201
|
+
maxDateStart.setHours(0, 0, 0, 0);
|
|
202
|
+
const dateStart = new Date(date);
|
|
203
|
+
dateStart.setHours(0, 0, 0, 0);
|
|
204
|
+
if (dateStart > maxDateStart)
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
// Generate calendar weeks for a given month
|
|
210
|
+
function generateCalendarWeeks(year, month, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate) {
|
|
211
|
+
const weeks = [];
|
|
212
|
+
const firstDay = new Date(year, month, 1);
|
|
213
|
+
const lastDay = new Date(year, month + 1, 0);
|
|
214
|
+
// Get the first day of the week for the first day of the month
|
|
215
|
+
let firstDayWeekday = firstDay.getDay();
|
|
216
|
+
// Adjust for firstDayOfWeek
|
|
217
|
+
firstDayWeekday = (firstDayWeekday - firstDayOfWeek + 7) % 7;
|
|
218
|
+
// Start from the first day of the week that contains the first day of the month
|
|
219
|
+
const startDate = new Date(firstDay);
|
|
220
|
+
startDate.setDate(startDate.getDate() - firstDayWeekday);
|
|
221
|
+
let currentDate = new Date(startDate);
|
|
222
|
+
const endDate = new Date(lastDay);
|
|
223
|
+
// Find the last day of the week that contains the last day of the month
|
|
224
|
+
let lastDayWeekday = lastDay.getDay();
|
|
225
|
+
lastDayWeekday = (lastDayWeekday - firstDayOfWeek + 7) % 7;
|
|
226
|
+
endDate.setDate(endDate.getDate() + (6 - lastDayWeekday));
|
|
227
|
+
while (currentDate <= endDate) {
|
|
228
|
+
const week = [];
|
|
229
|
+
for (let i = 0; i < 7; i++) {
|
|
230
|
+
const date = new Date(currentDate);
|
|
231
|
+
const isCurrentMonth = date.getMonth() === month;
|
|
232
|
+
if (!showOutsideDays && !isCurrentMonth) {
|
|
233
|
+
week.push(null);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
const calendarDate = {
|
|
237
|
+
date,
|
|
238
|
+
selected: isSelected(date, selected),
|
|
239
|
+
selectable: isSelectable(date, minDate, maxDate) &&
|
|
240
|
+
(showOutsideDays || isCurrentMonth),
|
|
241
|
+
today: isToday(date),
|
|
242
|
+
isCurrentMonth,
|
|
243
|
+
};
|
|
244
|
+
week.push(calendarDate);
|
|
245
|
+
}
|
|
246
|
+
currentDate.setDate(currentDate.getDate() + 1);
|
|
247
|
+
}
|
|
248
|
+
weeks.push(week);
|
|
249
|
+
}
|
|
250
|
+
return weeks;
|
|
251
|
+
}
|
|
252
|
+
// Generate calendars for the given months
|
|
253
|
+
function generateCalendars(startDate, monthsToDisplay, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate) {
|
|
254
|
+
const calendars = [];
|
|
255
|
+
const currentDate = new Date(startDate);
|
|
256
|
+
for (let i = 0; i < monthsToDisplay; i++) {
|
|
257
|
+
const year = currentDate.getFullYear();
|
|
258
|
+
const month = currentDate.getMonth();
|
|
259
|
+
const weeks = generateCalendarWeeks(year, month, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate);
|
|
260
|
+
calendars.push({
|
|
261
|
+
month,
|
|
262
|
+
year,
|
|
263
|
+
weeks,
|
|
264
|
+
});
|
|
265
|
+
// Move to next month
|
|
266
|
+
currentDate.setMonth(month + 1);
|
|
267
|
+
}
|
|
268
|
+
return calendars;
|
|
269
|
+
}
|
|
270
|
+
function useCalendar({ selected, firstDayOfWeek = 0, showOutsideDays = true, date, minDate, maxDate, monthsToDisplay = 1, onDateSelected, }) {
|
|
271
|
+
const [currentDate, setCurrentDate] = useState(() => {
|
|
272
|
+
return date ? new Date(date) : new Date();
|
|
273
|
+
});
|
|
274
|
+
const calendars = useMemo(() => {
|
|
275
|
+
return generateCalendars(currentDate, monthsToDisplay, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate);
|
|
276
|
+
}, [
|
|
277
|
+
currentDate,
|
|
278
|
+
monthsToDisplay,
|
|
279
|
+
firstDayOfWeek,
|
|
280
|
+
showOutsideDays,
|
|
281
|
+
selected,
|
|
282
|
+
minDate,
|
|
283
|
+
maxDate,
|
|
284
|
+
]);
|
|
285
|
+
const navigate = useCallback((offset) => {
|
|
286
|
+
setCurrentDate((prev) => {
|
|
287
|
+
const newDate = new Date(prev);
|
|
288
|
+
newDate.setMonth(prev.getMonth() + offset);
|
|
289
|
+
return newDate;
|
|
290
|
+
});
|
|
291
|
+
}, []);
|
|
292
|
+
const getBackProps = useCallback((props) => {
|
|
293
|
+
return {
|
|
294
|
+
onClick: () => {
|
|
295
|
+
navigate(-(props?.offset || 1));
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}, [navigate]);
|
|
299
|
+
const getForwardProps = useCallback((props) => {
|
|
300
|
+
return {
|
|
301
|
+
onClick: () => {
|
|
302
|
+
navigate(props?.offset || 1);
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}, [navigate]);
|
|
306
|
+
const getDateProps = useCallback((props) => {
|
|
307
|
+
return {
|
|
308
|
+
onClick: () => {
|
|
309
|
+
if (props.dateObj.selectable && onDateSelected) {
|
|
310
|
+
onDateSelected({
|
|
311
|
+
date: props.dateObj.date,
|
|
312
|
+
selected: selected || props.dateObj.date,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
onMouseEnter: props.onMouseEnter,
|
|
317
|
+
};
|
|
318
|
+
}, [onDateSelected, selected]);
|
|
319
|
+
return {
|
|
320
|
+
calendars,
|
|
321
|
+
getBackProps,
|
|
322
|
+
getForwardProps,
|
|
323
|
+
getDateProps,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
170
327
|
const RangeDatePickerContext = createContext({
|
|
171
328
|
labels: {
|
|
172
329
|
monthNamesFull: [
|
|
@@ -232,7 +389,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
232
389
|
if (!dateObj) {
|
|
233
390
|
return jsx(Box, {}, key);
|
|
234
391
|
}
|
|
235
|
-
const { date, selected, selectable, today } = dateObj;
|
|
392
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
236
393
|
const getStyle = ({ selected, unavailable, today, isInRange, }) => {
|
|
237
394
|
if (unavailable) {
|
|
238
395
|
return {
|
|
@@ -270,7 +427,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
270
427
|
unavailable: !selectable,
|
|
271
428
|
today,
|
|
272
429
|
isInRange: isInRange(date),
|
|
273
|
-
}), children: selectable ? date.getDate() : 'X' }, key));
|
|
430
|
+
}), opacity: isCurrentMonth ? 1 : 0.4, children: selectable ? date.getDate() : 'X' }, key));
|
|
274
431
|
})) })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
275
432
|
}
|
|
276
433
|
return null;
|
|
@@ -293,10 +450,57 @@ const RangeDatePicker = ({ labels = {
|
|
|
293
450
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
294
451
|
backButtonLabel: 'Back',
|
|
295
452
|
forwardButtonLabel: 'Next',
|
|
296
|
-
}, selected = [], onDateSelected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay,
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
453
|
+
}, selected = [], onDateSelected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
|
|
454
|
+
const handleDateSelected = (obj) => {
|
|
455
|
+
if (onDateSelected) {
|
|
456
|
+
const dateObj = obj.date;
|
|
457
|
+
const currentSelected = Array.isArray(obj.selected)
|
|
458
|
+
? obj.selected
|
|
459
|
+
: [obj.selected];
|
|
460
|
+
// Range selection logic: if one date selected, add second; if two selected, replace with new date
|
|
461
|
+
let newSelected;
|
|
462
|
+
if (currentSelected.length === 0) {
|
|
463
|
+
newSelected = [dateObj];
|
|
464
|
+
}
|
|
465
|
+
else if (currentSelected.length === 1) {
|
|
466
|
+
const firstDate = currentSelected[0];
|
|
467
|
+
if (dateObj < firstDate) {
|
|
468
|
+
newSelected = [dateObj, firstDate];
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
newSelected = [firstDate, dateObj];
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
newSelected = [dateObj];
|
|
476
|
+
}
|
|
477
|
+
// Check if date is selectable
|
|
478
|
+
const selectable = !minDate || dateObj >= minDate;
|
|
479
|
+
if (maxDate) {
|
|
480
|
+
const isSelectable = dateObj <= maxDate;
|
|
481
|
+
if (!isSelectable)
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
onDateSelected({
|
|
485
|
+
selected: newSelected,
|
|
486
|
+
selectable,
|
|
487
|
+
date: dateObj,
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
const calendarData = useCalendar({
|
|
492
|
+
onDateSelected: handleDateSelected,
|
|
493
|
+
selected,
|
|
494
|
+
firstDayOfWeek,
|
|
495
|
+
showOutsideDays,
|
|
496
|
+
date,
|
|
497
|
+
minDate,
|
|
498
|
+
maxDate,
|
|
499
|
+
monthsToDisplay,
|
|
500
|
+
});
|
|
501
|
+
return (jsx(RangeDatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsx(Calendar$1, { ...calendarData,
|
|
502
|
+
firstDayOfWeek,
|
|
503
|
+
selected: selected })) }));
|
|
300
504
|
};
|
|
301
505
|
|
|
302
506
|
const getRangeDates = ({ selectable, date, selectedDates, }) => {
|
|
@@ -532,7 +736,7 @@ const MenuTrigger = Menu.Trigger;
|
|
|
532
736
|
|
|
533
737
|
const PageSizeControl = ({ pageSizes = [10, 20, 30, 40, 50], }) => {
|
|
534
738
|
const { table } = useDataTableContext();
|
|
535
|
-
return (jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children:
|
|
739
|
+
return (jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Button$1, { variant: 'ghost', gap: '0.5rem', children: table.getState().pagination.pageSize }) }), jsx(MenuContent, { children: pageSizes.map((pageSize) => (jsx(MenuItem, { value: `chakra-table-pageSize-${pageSize}`, onClick: () => {
|
|
536
740
|
table.setPageSize(Number(pageSize));
|
|
537
741
|
}, children: pageSize }, `chakra-table-pageSize-${pageSize}`))) })] }));
|
|
538
742
|
};
|
|
@@ -560,81 +764,149 @@ const PaginationRoot = React.forwardRef(function PaginationRoot(props, ref) {
|
|
|
560
764
|
}
|
|
561
765
|
const container = containerRef.current;
|
|
562
766
|
let rafId = null;
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
767
|
+
let timeoutId = null;
|
|
768
|
+
const measureButtonWidth = () => {
|
|
769
|
+
// Try to measure actual rendered buttons for accuracy
|
|
770
|
+
// Look for page number buttons (they contain numeric text)
|
|
771
|
+
const allButtons = container.querySelectorAll('button');
|
|
772
|
+
const pageButtons = [];
|
|
773
|
+
allButtons.forEach((button) => {
|
|
774
|
+
const text = button.textContent?.trim();
|
|
775
|
+
// Page buttons contain numbers, prev/next buttons contain icons
|
|
776
|
+
if (text && /^\d+$/.test(text)) {
|
|
777
|
+
pageButtons.push(button);
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
if (pageButtons.length > 0) {
|
|
781
|
+
// Measure multiple buttons and take the average for accuracy
|
|
782
|
+
let totalWidth = 0;
|
|
783
|
+
let count = 0;
|
|
784
|
+
pageButtons.forEach((button) => {
|
|
785
|
+
const width = button.offsetWidth;
|
|
786
|
+
if (width > 0) {
|
|
787
|
+
totalWidth += width;
|
|
788
|
+
count++;
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
if (count > 0) {
|
|
792
|
+
return Math.ceil(totalWidth / count);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
// Fallback to estimated widths based on size
|
|
571
796
|
const buttonWidthMap = {
|
|
572
797
|
xs: 28,
|
|
573
798
|
sm: 36,
|
|
574
799
|
md: 40,
|
|
575
800
|
lg: 44,
|
|
576
801
|
};
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
802
|
+
return buttonWidthMap[size] || 36;
|
|
803
|
+
};
|
|
804
|
+
const measurePrevNextWidth = () => {
|
|
805
|
+
const allButtons = container.querySelectorAll('button');
|
|
806
|
+
let prevWidth = 0;
|
|
807
|
+
let nextWidth = 0;
|
|
808
|
+
allButtons.forEach((button) => {
|
|
809
|
+
const html = button.innerHTML;
|
|
810
|
+
// Check if it's a prev/next button by looking for chevron icons or SVG
|
|
811
|
+
if (html.includes('chevron') ||
|
|
812
|
+
html.includes('Chevron') ||
|
|
813
|
+
button.querySelector('svg')) {
|
|
814
|
+
const width = button.offsetWidth;
|
|
815
|
+
if (width > 0) {
|
|
816
|
+
// First icon button is likely prev, last is next
|
|
817
|
+
if (prevWidth === 0) {
|
|
818
|
+
prevWidth = width;
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
nextWidth = width;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
587
824
|
}
|
|
825
|
+
});
|
|
826
|
+
if (prevWidth > 0 && nextWidth > 0) {
|
|
827
|
+
return prevWidth + nextWidth;
|
|
588
828
|
}
|
|
589
|
-
//
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
829
|
+
// Fallback: use page button width estimate
|
|
830
|
+
return measureButtonWidth() * 2;
|
|
831
|
+
};
|
|
832
|
+
const calculateSiblingCount = () => {
|
|
833
|
+
if (!container)
|
|
834
|
+
return;
|
|
835
|
+
const width = container.offsetWidth;
|
|
836
|
+
if (width === 0)
|
|
837
|
+
return;
|
|
838
|
+
// Measure actual button widths
|
|
839
|
+
const pageButtonWidth = measureButtonWidth();
|
|
840
|
+
const prevNextWidth = measurePrevNextWidth();
|
|
841
|
+
// Get computed gap from container (HStack gap)
|
|
842
|
+
const containerStyles = window.getComputedStyle(container);
|
|
843
|
+
const gap = parseFloat(containerStyles.gap) || 8;
|
|
844
|
+
// Account for gaps: prev button + gap + page buttons + gap + next button
|
|
845
|
+
// We need at least 2 gaps (before and after page buttons)
|
|
846
|
+
const availableWidth = Math.max(0, width - prevNextWidth - gap * 2);
|
|
594
847
|
// Each page button takes buttonWidth + gap
|
|
595
|
-
const buttonWithGap =
|
|
596
|
-
const
|
|
597
|
-
// Calculate sibling count
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const minRequired = 5;
|
|
604
|
-
const extraButtons = Math.max(0, maxButtons - minRequired);
|
|
605
|
-
// Calculate sibling count
|
|
606
|
-
// If we have enough space for ellipsis (2 buttons), account for that
|
|
848
|
+
const buttonWithGap = pageButtonWidth + gap;
|
|
849
|
+
const maxPageButtons = Math.floor(availableWidth / buttonWithGap);
|
|
850
|
+
// Calculate sibling count based on pagination structure
|
|
851
|
+
// Structure: [prev] [first] [ellipsis?] [siblings] [current] [siblings] [ellipsis?] [last] [next]
|
|
852
|
+
// Minimum: prev(1) + first(1) + current(1) + last(1) + next(1) = 5 buttons
|
|
853
|
+
// With siblings and ellipsis: 5 + siblings*2 + ellipsis*2
|
|
854
|
+
const minRequired = 5; // prev, first, current, last, next
|
|
855
|
+
const extraButtons = Math.max(0, maxPageButtons - minRequired);
|
|
607
856
|
let calculated = minSiblingCount;
|
|
608
857
|
if (extraButtons >= 4) {
|
|
609
|
-
//
|
|
858
|
+
// Enough space for ellipsis (2 buttons) + siblings on both sides
|
|
859
|
+
// Structure: [prev] [1] [...] [siblings] [current] [siblings] [...] [last] [next]
|
|
860
|
+
// Extra buttons = ellipsis(2) + siblings*2
|
|
610
861
|
calculated = Math.floor((extraButtons - 2) / 2);
|
|
611
862
|
}
|
|
612
863
|
else if (extraButtons >= 2) {
|
|
613
864
|
// Space for some siblings but not ellipsis
|
|
865
|
+
// Structure: [prev] [1] [siblings] [current] [siblings] [last] [next]
|
|
614
866
|
calculated = Math.floor(extraButtons / 2);
|
|
615
867
|
}
|
|
616
868
|
// Apply max limit if provided
|
|
617
869
|
if (maxSiblingCount !== undefined) {
|
|
618
870
|
calculated = Math.min(calculated, maxSiblingCount);
|
|
619
871
|
}
|
|
620
|
-
|
|
872
|
+
const finalSiblingCount = Math.max(minSiblingCount, calculated);
|
|
873
|
+
// Only update if value changed to avoid unnecessary re-renders
|
|
874
|
+
setCalculatedSiblingCount((prev) => {
|
|
875
|
+
if (prev !== finalSiblingCount) {
|
|
876
|
+
return finalSiblingCount;
|
|
877
|
+
}
|
|
878
|
+
return prev;
|
|
879
|
+
});
|
|
621
880
|
};
|
|
622
|
-
const
|
|
623
|
-
//
|
|
881
|
+
const scheduleCalculation = () => {
|
|
882
|
+
// Cancel any pending calculations
|
|
624
883
|
if (rafId !== null) {
|
|
625
884
|
cancelAnimationFrame(rafId);
|
|
626
885
|
}
|
|
627
|
-
|
|
628
|
-
|
|
886
|
+
if (timeoutId !== null) {
|
|
887
|
+
clearTimeout(timeoutId);
|
|
888
|
+
}
|
|
889
|
+
// Use requestAnimationFrame for smooth updates
|
|
890
|
+
rafId = requestAnimationFrame(() => {
|
|
891
|
+
// Small delay to ensure DOM is fully rendered
|
|
892
|
+
timeoutId = setTimeout(calculateSiblingCount, 50);
|
|
893
|
+
});
|
|
894
|
+
};
|
|
895
|
+
const resizeObserver = new ResizeObserver(scheduleCalculation);
|
|
629
896
|
resizeObserver.observe(container);
|
|
630
|
-
// Initial calculation
|
|
631
|
-
|
|
897
|
+
// Initial calculation - try multiple times to ensure buttons are rendered
|
|
898
|
+
scheduleCalculation();
|
|
899
|
+
// Also try after a longer delay as fallback
|
|
900
|
+
const fallbackTimeout = setTimeout(calculateSiblingCount, 200);
|
|
632
901
|
return () => {
|
|
633
902
|
resizeObserver.disconnect();
|
|
634
903
|
if (rafId !== null) {
|
|
635
904
|
cancelAnimationFrame(rafId);
|
|
636
905
|
}
|
|
637
|
-
|
|
906
|
+
if (timeoutId !== null) {
|
|
907
|
+
clearTimeout(timeoutId);
|
|
908
|
+
}
|
|
909
|
+
clearTimeout(fallbackTimeout);
|
|
638
910
|
};
|
|
639
911
|
}, [size, siblingCount, minSiblingCount, maxSiblingCount]);
|
|
640
912
|
const mergedRef = React.useCallback((node) => {
|
|
@@ -814,12 +1086,19 @@ const ResetSelectionButton = () => {
|
|
|
814
1086
|
const RowCountText = () => {
|
|
815
1087
|
const { table, type } = useDataTableContext();
|
|
816
1088
|
const getCount = () => {
|
|
817
|
-
if (type ===
|
|
1089
|
+
if (type === 'client') {
|
|
818
1090
|
return table.getFilteredRowModel().flatRows.length ?? 0;
|
|
819
1091
|
}
|
|
820
1092
|
return table.getRowCount();
|
|
821
1093
|
};
|
|
822
|
-
|
|
1094
|
+
const totalCount = getCount();
|
|
1095
|
+
const { pageIndex, pageSize } = table.getState().pagination;
|
|
1096
|
+
if (totalCount === 0) {
|
|
1097
|
+
return jsx(Text, { children: "0 of 0" });
|
|
1098
|
+
}
|
|
1099
|
+
const start = pageIndex * pageSize + 1;
|
|
1100
|
+
const end = Math.min((pageIndex + 1) * pageSize, totalCount);
|
|
1101
|
+
return jsx(Text, { children: `${start}-${end} / ${totalCount}` });
|
|
823
1102
|
};
|
|
824
1103
|
|
|
825
1104
|
// pulling this into a separate file so adapter(s) that don't
|
|
@@ -2928,17 +3207,17 @@ const TableFilterTags = () => {
|
|
|
2928
3207
|
|
|
2929
3208
|
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 = {}, }) => {
|
|
2930
3209
|
const { tableLabel, table } = useDataTableContext();
|
|
2931
|
-
const {
|
|
2932
|
-
return (jsxs(Grid, { templateRows:
|
|
3210
|
+
const { hasErrorText } = tableLabel;
|
|
3211
|
+
return (jsxs(Grid, { templateRows: 'auto 1fr', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: '0.5rem', p: 1, ...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) => {
|
|
2933
3212
|
const { column, options } = option;
|
|
2934
3213
|
const tableColumn = table.getColumn(column);
|
|
2935
|
-
return (jsxs(Flex, { alignItems:
|
|
3214
|
+
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) => {
|
|
2936
3215
|
if (tags.length === 0) {
|
|
2937
3216
|
return tableColumn?.setFilterValue(undefined);
|
|
2938
3217
|
}
|
|
2939
3218
|
tableColumn?.setFilterValue(tags);
|
|
2940
3219
|
} })] }, column));
|
|
2941
|
-
}) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, {
|
|
3220
|
+
}) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, { children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Flex, { justifyContent: 'space-between', children: [jsxs(Flex, { gap: '1rem', alignItems: 'center', children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && jsx(RowCountText, {})] }), jsx(Box, { justifySelf: 'end', children: showPagination && jsx(Pagination, {}) })] }))] }));
|
|
2942
3221
|
};
|
|
2943
3222
|
|
|
2944
3223
|
const EmptyState$1 = React.forwardRef(function EmptyState(props, ref) {
|
|
@@ -3100,7 +3379,7 @@ const Table = ({ children, emptyComponent = EmptyResult, canResize = true, showL
|
|
|
3100
3379
|
if (!showLoading && table.getRowModel().rows.length <= 0) {
|
|
3101
3380
|
return emptyComponent;
|
|
3102
3381
|
}
|
|
3103
|
-
return (jsx(Box, { ref: containerRef, width: "100%", overflow: "auto", children: jsx(Table$1.Root, { stickyHeader: true,
|
|
3382
|
+
return (jsx(Box, { ref: containerRef, width: "100%", overflow: "auto", children: jsx(Table$1.Root, { stickyHeader: true, width: canResize ? table.getCenterTotalSize() : undefined, display: 'grid', alignContent: 'start', ...props, children: children }) }));
|
|
3104
3383
|
};
|
|
3105
3384
|
|
|
3106
3385
|
const Checkbox = React.forwardRef(function Checkbox(props, ref) {
|
|
@@ -3146,11 +3425,7 @@ const TableBody = ({ showSelector = false, canResize = true, }) => {
|
|
|
3146
3425
|
// styling resize and pinning start
|
|
3147
3426
|
flex: `${canResize ? '0' : '1'} 0 ${cell.column.getSize()}px`,
|
|
3148
3427
|
// this is to avoid the cell from being too wide
|
|
3149
|
-
minWidth: `0`,
|
|
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}`));
|
|
3428
|
+
minWidth: `0`, ...getTdProps(cell), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
3154
3429
|
})] }, `chakra-table-row-${row.id}`));
|
|
3155
3430
|
}) }));
|
|
3156
3431
|
};
|
|
@@ -3160,11 +3435,7 @@ const TableRowSelector = ({ row }) => {
|
|
|
3160
3435
|
const isSelected = isRowSelected(row.id, rowSelection);
|
|
3161
3436
|
const canSelect = canRowSelect(row);
|
|
3162
3437
|
const toggleHandler = createRowToggleHandler(row, rowSelection, setRowSelection);
|
|
3163
|
-
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid',
|
|
3164
|
-
base: 'colorPalette.900',
|
|
3165
|
-
_dark: 'colorPalette.100',
|
|
3166
|
-
},
|
|
3167
|
-
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: isSelected,
|
|
3438
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid', justifyItems: 'center', alignItems: 'center', children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: isSelected,
|
|
3168
3439
|
disabled: !canSelect,
|
|
3169
3440
|
onCheckedChange: toggleHandler }) }));
|
|
3170
3441
|
};
|
|
@@ -3281,18 +3552,6 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3281
3552
|
const columnMeta = header.column.columnDef.meta;
|
|
3282
3553
|
return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
|
|
3283
3554
|
};
|
|
3284
|
-
const getThProps = (header) => {
|
|
3285
|
-
const thProps = header.column.getIsPinned()
|
|
3286
|
-
? {
|
|
3287
|
-
left: showSelector
|
|
3288
|
-
? `${header.getStart('left') + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3289
|
-
: `${header.getStart('left')}px`,
|
|
3290
|
-
position: 'sticky',
|
|
3291
|
-
zIndex: 100 + 1,
|
|
3292
|
-
}
|
|
3293
|
-
: {};
|
|
3294
|
-
return thProps;
|
|
3295
|
-
};
|
|
3296
3555
|
const stickyProps = {
|
|
3297
3556
|
position: 'sticky',
|
|
3298
3557
|
top: 0,
|
|
@@ -3344,11 +3603,7 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3344
3603
|
[header.id]: finalWidth,
|
|
3345
3604
|
}));
|
|
3346
3605
|
};
|
|
3347
|
-
return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}),
|
|
3348
|
-
base: 'colorPalette.900',
|
|
3349
|
-
_dark: 'colorPalette.100',
|
|
3350
|
-
},
|
|
3351
|
-
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: areAllRowsSelected(table, rowSelection),
|
|
3606
|
+
return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}), ...tableHeaderProps, children: table.getHeaderGroups().map((headerGroup) => (jsxs(Table$1.Row, { display: 'flex', ...tableRowProps, children: [showSelector && (jsx(Table$1.ColumnHeader, { padding: `${table.getDensityValue()}px`, display: 'grid', justifyItems: 'center', alignItems: 'center', children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: areAllRowsSelected(table, rowSelection),
|
|
3352
3607
|
// indeterminate: areSomeRowsSelected(table, rowSelection),
|
|
3353
3608
|
onChange: createToggleAllRowsHandler(table, rowSelection, setRowSelection) }) })), headerGroup.headers.map((header) => {
|
|
3354
3609
|
const resizeProps = {
|
|
@@ -3358,30 +3613,11 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3358
3613
|
};
|
|
3359
3614
|
return (jsxs(Table$1.ColumnHeader, { padding: 0, columnSpan: `${header.colSpan}`,
|
|
3360
3615
|
// styling resize and pinning start
|
|
3361
|
-
flex: `${canResize ? '0' : '1'} 0 ${header.column.getSize()}px`, display: 'grid', gridTemplateColumns: '1fr auto', zIndex: 1500 + header.index,
|
|
3362
|
-
base: 'colorPalette.800',
|
|
3363
|
-
_dark: 'colorPalette.200',
|
|
3364
|
-
},
|
|
3365
|
-
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: {
|
|
3366
|
-
base: 'colorPalette.800',
|
|
3367
|
-
_dark: 'colorPalette.200',
|
|
3368
|
-
_hover: {
|
|
3369
|
-
base: 'colorPalette.700',
|
|
3370
|
-
_dark: 'colorPalette.300',
|
|
3371
|
-
},
|
|
3372
|
-
},
|
|
3373
|
-
bg: {
|
|
3374
|
-
base: 'colorPalette.100',
|
|
3375
|
-
_dark: 'colorPalette.900',
|
|
3376
|
-
_hover: {
|
|
3377
|
-
base: 'colorPalette.200',
|
|
3378
|
-
_dark: 'colorPalette.800',
|
|
3379
|
-
},
|
|
3380
|
-
}, children: jsxs(Flex, { gap: "0.5rem", alignItems: 'center', children: [header.isPlaceholder
|
|
3616
|
+
flex: `${canResize ? '0' : '1'} 0 ${header.column.getSize()}px`, display: 'grid', gridTemplateColumns: '1fr auto', zIndex: 1500 + header.index, children: [jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Flex, { padding: `${table.getDensityValue()}px`, alignItems: 'center', justifyContent: 'start', borderRadius: '0rem', overflow: 'auto', children: jsxs(Flex, { gap: "0.5rem", alignItems: 'center', children: [header.isPlaceholder
|
|
3381
3617
|
? null
|
|
3382
3618
|
: 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: () => {
|
|
3383
3619
|
header.column.pin('left');
|
|
3384
|
-
}, children: [jsx(MdPushPin, {}), getHeaderText(header, 'pinColumn')] }) })), header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3620
|
+
}, p: 1, children: [jsx(MdPushPin, {}), getHeaderText(header, 'pinColumn')] }) })), header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3385
3621
|
header.column.pin(false);
|
|
3386
3622
|
}, 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: () => {
|
|
3387
3623
|
table.setSorting((state) => {
|
|
@@ -3581,7 +3817,7 @@ const ErrorAlert = ({ showMessage = true }) => {
|
|
|
3581
3817
|
const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: defaultPagination = {
|
|
3582
3818
|
pageIndex: 0, //initial page index
|
|
3583
3819
|
pageSize: 10, //default page size
|
|
3584
|
-
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter =
|
|
3820
|
+
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = '', density: defaultDensity = 'sm', } = {
|
|
3585
3821
|
sorting: [],
|
|
3586
3822
|
pagination: {
|
|
3587
3823
|
pageIndex: 0, //initial page index
|
|
@@ -3591,9 +3827,9 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3591
3827
|
columnFilters: [],
|
|
3592
3828
|
columnOrder: [],
|
|
3593
3829
|
columnVisibility: {},
|
|
3594
|
-
globalFilter:
|
|
3595
|
-
density:
|
|
3596
|
-
},
|
|
3830
|
+
globalFilter: '',
|
|
3831
|
+
density: 'sm',
|
|
3832
|
+
}, } = {
|
|
3597
3833
|
default: {
|
|
3598
3834
|
sorting: [],
|
|
3599
3835
|
pagination: {
|
|
@@ -3604,8 +3840,8 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3604
3840
|
columnFilters: [],
|
|
3605
3841
|
columnOrder: [],
|
|
3606
3842
|
columnVisibility: {},
|
|
3607
|
-
globalFilter:
|
|
3608
|
-
density:
|
|
3843
|
+
globalFilter: '',
|
|
3844
|
+
density: 'sm',
|
|
3609
3845
|
},
|
|
3610
3846
|
}) => {
|
|
3611
3847
|
const [sorting, setSorting] = useState(defaultSorting);
|
|
@@ -3616,7 +3852,6 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3616
3852
|
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter);
|
|
3617
3853
|
const [density, setDensity] = useState(defaultDensity);
|
|
3618
3854
|
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility);
|
|
3619
|
-
const translate = useTranslation("", { keyPrefix });
|
|
3620
3855
|
return {
|
|
3621
3856
|
sorting,
|
|
3622
3857
|
setSorting,
|
|
@@ -3634,12 +3869,11 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3634
3869
|
setDensity,
|
|
3635
3870
|
columnVisibility,
|
|
3636
3871
|
setColumnVisibility,
|
|
3637
|
-
translate,
|
|
3638
3872
|
};
|
|
3639
3873
|
};
|
|
3640
3874
|
|
|
3641
3875
|
const useDataTableServer = (props) => {
|
|
3642
|
-
const { url, default: defaultProps,
|
|
3876
|
+
const { url, default: defaultProps, placeholderData, queryFn: customQueryFn, } = props;
|
|
3643
3877
|
const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
|
|
3644
3878
|
const [sorting, setSorting] = useState(defaultSorting || []);
|
|
3645
3879
|
const [columnFilters, setColumnFilters] = useState(defaultColumnFilters || []); // can set initial column filter state here
|
|
@@ -3649,8 +3883,8 @@ const useDataTableServer = (props) => {
|
|
|
3649
3883
|
});
|
|
3650
3884
|
const [rowSelection, setRowSelection] = useState(defaultRowSelection || {});
|
|
3651
3885
|
const [columnOrder, setColumnOrder] = useState(defaultColumnOrder || []);
|
|
3652
|
-
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter ||
|
|
3653
|
-
const [density, setDensity] = useState(defaultDensity ||
|
|
3886
|
+
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter || '');
|
|
3887
|
+
const [density, setDensity] = useState(defaultDensity || 'sm');
|
|
3654
3888
|
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility || {});
|
|
3655
3889
|
const { pageSize, pageIndex } = pagination;
|
|
3656
3890
|
const params = {
|
|
@@ -3662,7 +3896,7 @@ const useDataTableServer = (props) => {
|
|
|
3662
3896
|
};
|
|
3663
3897
|
const defaultQueryFn = async () => {
|
|
3664
3898
|
if (!url) {
|
|
3665
|
-
throw new Error(
|
|
3899
|
+
throw new Error('url is required');
|
|
3666
3900
|
}
|
|
3667
3901
|
const response = await axios.get(url, {
|
|
3668
3902
|
params,
|
|
@@ -3676,7 +3910,6 @@ const useDataTableServer = (props) => {
|
|
|
3676
3910
|
: defaultQueryFn,
|
|
3677
3911
|
placeholderData,
|
|
3678
3912
|
});
|
|
3679
|
-
const translate = useTranslation("", { keyPrefix });
|
|
3680
3913
|
return {
|
|
3681
3914
|
sorting,
|
|
3682
3915
|
setSorting,
|
|
@@ -3695,7 +3928,6 @@ const useDataTableServer = (props) => {
|
|
|
3695
3928
|
columnVisibility,
|
|
3696
3929
|
setColumnVisibility,
|
|
3697
3930
|
query,
|
|
3698
|
-
translate,
|
|
3699
3931
|
};
|
|
3700
3932
|
};
|
|
3701
3933
|
|
|
@@ -3714,11 +3946,8 @@ const snakeToLabel = (str) => {
|
|
|
3714
3946
|
.join(" "); // Join with space
|
|
3715
3947
|
};
|
|
3716
3948
|
|
|
3717
|
-
const RecordDisplay = ({ object, boxProps,
|
|
3949
|
+
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
3718
3950
|
const getColumn = ({ field }) => {
|
|
3719
|
-
if (translate !== undefined) {
|
|
3720
|
-
return translate.t(`${prefix}${field}`);
|
|
3721
|
-
}
|
|
3722
3951
|
return snakeToLabel(field);
|
|
3723
3952
|
};
|
|
3724
3953
|
if (object === null) {
|
|
@@ -3726,7 +3955,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = '', }) => {
|
|
|
3726
3955
|
}
|
|
3727
3956
|
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
3728
3957
|
const uniqueKey = `${prefix}${field}-${index}`;
|
|
3729
|
-
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}
|
|
3958
|
+
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsx(Text, { children: JSON.stringify(value) }))] }, uniqueKey));
|
|
3730
3959
|
}) }));
|
|
3731
3960
|
};
|
|
3732
3961
|
|
|
@@ -3740,15 +3969,12 @@ const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
|
3740
3969
|
throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
|
|
3741
3970
|
}
|
|
3742
3971
|
};
|
|
3743
|
-
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400,
|
|
3972
|
+
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
|
|
3744
3973
|
const { properties } = schema;
|
|
3745
|
-
idListSanityCheck(
|
|
3974
|
+
idListSanityCheck('ignore', ignore, properties);
|
|
3746
3975
|
widthSanityCheck(width, ignore, properties);
|
|
3747
|
-
idListSanityCheck(
|
|
3976
|
+
idListSanityCheck('meta', Object.keys(meta), properties);
|
|
3748
3977
|
const getColumn = ({ column }) => {
|
|
3749
|
-
if (translate !== undefined) {
|
|
3750
|
-
return translate.t(`${column}`);
|
|
3751
|
-
}
|
|
3752
3978
|
return snakeToLabel(column);
|
|
3753
3979
|
};
|
|
3754
3980
|
const keys = Object.keys(properties);
|
|
@@ -3757,15 +3983,15 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
|
|
|
3757
3983
|
return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
|
|
3758
3984
|
});
|
|
3759
3985
|
const columnHelper = createColumnHelper();
|
|
3760
|
-
// @ts-expect-error find type for unknown
|
|
3761
3986
|
const columns = [
|
|
3762
3987
|
...ignored.map((column, index) => {
|
|
3988
|
+
// @ts-expect-error column accessor type issue with generic TData
|
|
3763
3989
|
return columnHelper.accessor(column, {
|
|
3764
3990
|
cell: (props) => {
|
|
3765
3991
|
// @ts-expect-error find type for unknown
|
|
3766
3992
|
const value = props.row.original[column];
|
|
3767
|
-
if (typeof value ===
|
|
3768
|
-
return (jsx(Grid, { overflow:
|
|
3993
|
+
if (typeof value === 'object') {
|
|
3994
|
+
return (jsx(Grid, { overflow: 'auto', children: jsx(RecordDisplay, { object: value }) }));
|
|
3769
3995
|
}
|
|
3770
3996
|
return jsx(TextCell, { children: value });
|
|
3771
3997
|
},
|
|
@@ -3797,6 +4023,11 @@ const SchemaFormContext = createContext({
|
|
|
3797
4023
|
include: [],
|
|
3798
4024
|
onSubmit: async () => { },
|
|
3799
4025
|
rowNumber: 0,
|
|
4026
|
+
/** Default translate fallback - returns key as-is */
|
|
4027
|
+
translate: {
|
|
4028
|
+
t: (key) => key,
|
|
4029
|
+
ready: true,
|
|
4030
|
+
},
|
|
3800
4031
|
requestOptions: {},
|
|
3801
4032
|
timezone: 'Asia/Hong_Kong',
|
|
3802
4033
|
displayConfig: {
|
|
@@ -4029,7 +4260,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4029
4260
|
showSubmitButton: true,
|
|
4030
4261
|
showResetButton: true,
|
|
4031
4262
|
showTitle: true,
|
|
4032
|
-
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, insideDialog = false, }) => {
|
|
4263
|
+
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
4033
4264
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
4034
4265
|
const [isError, setIsError] = useState(false);
|
|
4035
4266
|
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
@@ -4120,6 +4351,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4120
4351
|
enumPickerLabels,
|
|
4121
4352
|
filePickerLabels,
|
|
4122
4353
|
formButtonLabels,
|
|
4354
|
+
timePickerLabels,
|
|
4123
4355
|
ajvResolver: ajvResolver(schema),
|
|
4124
4356
|
insideDialog,
|
|
4125
4357
|
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
@@ -4130,31 +4362,33 @@ function removeIndex(str) {
|
|
|
4130
4362
|
}
|
|
4131
4363
|
|
|
4132
4364
|
/**
|
|
4133
|
-
* Custom hook
|
|
4365
|
+
* Custom hook for form field labels and fallback text.
|
|
4134
4366
|
* Automatically handles colLabel construction and removeIndex logic.
|
|
4367
|
+
* Uses schema.title when available, otherwise falls back to translate function.
|
|
4135
4368
|
*
|
|
4136
4369
|
* @param column - The column name
|
|
4137
4370
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4138
|
-
* @
|
|
4371
|
+
* @param schema - Optional schema object with title property
|
|
4372
|
+
* @returns Object with label helper functions
|
|
4139
4373
|
*
|
|
4140
4374
|
* @example
|
|
4141
4375
|
* ```tsx
|
|
4142
|
-
* const formI18n = useFormI18n(column, prefix);
|
|
4376
|
+
* const formI18n = useFormI18n(column, prefix, schema);
|
|
4143
4377
|
*
|
|
4144
|
-
* // Get field label
|
|
4378
|
+
* // Get field label (prefers schema.title)
|
|
4145
4379
|
* <Field label={formI18n.label()} />
|
|
4146
4380
|
*
|
|
4147
|
-
* // Get error message
|
|
4381
|
+
* // Get required error message
|
|
4148
4382
|
* <Text>{formI18n.required()}</Text>
|
|
4149
4383
|
*
|
|
4150
|
-
* // Get custom
|
|
4384
|
+
* // Get custom text
|
|
4151
4385
|
* <Text>{formI18n.t('add_more')}</Text>
|
|
4152
4386
|
*
|
|
4153
4387
|
* // Access the raw colLabel
|
|
4154
4388
|
* const colLabel = formI18n.colLabel;
|
|
4155
4389
|
* ```
|
|
4156
4390
|
*/
|
|
4157
|
-
const useFormI18n
|
|
4391
|
+
const useFormI18n = (column, prefix = '', schema) => {
|
|
4158
4392
|
const { translate } = useSchemaContext();
|
|
4159
4393
|
const colLabel = `${prefix}${column}`;
|
|
4160
4394
|
return {
|
|
@@ -4163,7 +4397,7 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4163
4397
|
*/
|
|
4164
4398
|
colLabel,
|
|
4165
4399
|
/**
|
|
4166
|
-
* Get the field label from schema title prop, or fall back to
|
|
4400
|
+
* Get the field label from schema title prop, or fall back to translate function
|
|
4167
4401
|
* Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
4168
4402
|
*/
|
|
4169
4403
|
label: (options) => {
|
|
@@ -4173,18 +4407,18 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4173
4407
|
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
4174
4408
|
},
|
|
4175
4409
|
/**
|
|
4176
|
-
* Get the required error message
|
|
4410
|
+
* Get the required error message
|
|
4177
4411
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4178
4412
|
*/
|
|
4179
4413
|
required: (options) => {
|
|
4180
4414
|
return translate.t(removeIndex(`${colLabel}.field_required`), options);
|
|
4181
4415
|
},
|
|
4182
4416
|
/**
|
|
4183
|
-
* Get
|
|
4417
|
+
* Get text for any custom key relative to the field
|
|
4184
4418
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
4185
4419
|
*
|
|
4186
|
-
* @param key - The
|
|
4187
|
-
* @param options - Optional
|
|
4420
|
+
* @param key - The key suffix (e.g., 'add_more', 'total', etc.)
|
|
4421
|
+
* @param options - Optional options (e.g., defaultValue, interpolation variables)
|
|
4188
4422
|
*/
|
|
4189
4423
|
t: (key, options) => {
|
|
4190
4424
|
return translate.t(removeIndex(`${colLabel}.${key}`), options);
|
|
@@ -4202,8 +4436,9 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4202
4436
|
const { type } = items;
|
|
4203
4437
|
const colLabel = `${prefix}${column}`;
|
|
4204
4438
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4205
|
-
const formI18n = useFormI18n
|
|
4439
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4206
4440
|
const { formState: { errors }, setValue, watch, } = useFormContext();
|
|
4441
|
+
const { formButtonLabels } = useSchemaContext();
|
|
4207
4442
|
const fields = (watch(colLabel) ?? []);
|
|
4208
4443
|
return (jsxs(Flex, { gridRow, gridColumn, flexFlow: 'column', gap: 2, children: [jsxs(Box, { as: "label", children: [formI18n.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: {
|
|
4209
4444
|
base: 'colorPalette.200',
|
|
@@ -4229,7 +4464,7 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4229
4464
|
return;
|
|
4230
4465
|
}
|
|
4231
4466
|
setValue(colLabel, [...fields, {}]);
|
|
4232
|
-
}, children:
|
|
4467
|
+
}, children: formButtonLabels?.add ?? 'Add' }) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
4233
4468
|
};
|
|
4234
4469
|
|
|
4235
4470
|
const Field = React.forwardRef(function Field(props, ref) {
|
|
@@ -4243,7 +4478,7 @@ const BooleanPicker = ({ schema, column, prefix }) => {
|
|
|
4243
4478
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4244
4479
|
const colLabel = `${prefix}${column}`;
|
|
4245
4480
|
const value = watch(colLabel);
|
|
4246
|
-
const formI18n = useFormI18n
|
|
4481
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4247
4482
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4248
4483
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
|
|
4249
4484
|
setValue(colLabel, !value);
|
|
@@ -4264,50 +4499,50 @@ const CustomInput = ({ column, schema, prefix }) => {
|
|
|
4264
4499
|
|
|
4265
4500
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
4266
4501
|
const { labels } = useContext(DatePickerContext);
|
|
4267
|
-
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
4502
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
4268
4503
|
if (calendars.length) {
|
|
4269
|
-
return (jsxs(Grid, { children: [jsxs(Grid, { templateColumns:
|
|
4504
|
+
return (jsxs(Grid, { children: [jsxs(Grid, { templateColumns: 'repeat(4, auto)', justifyContent: 'center', children: [jsx(Button$1, { variant: 'ghost', ...getBackProps({
|
|
4270
4505
|
calendars,
|
|
4271
4506
|
offset: 12,
|
|
4272
|
-
}), children:
|
|
4507
|
+
}), 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({
|
|
4273
4508
|
calendars,
|
|
4274
4509
|
offset: 12,
|
|
4275
|
-
}), children:
|
|
4510
|
+
}), 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) => {
|
|
4276
4511
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
4277
|
-
return (jsx(Text, { textAlign:
|
|
4512
|
+
return (jsx(Text, { textAlign: 'center', children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
4278
4513
|
}), calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
4279
4514
|
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
4280
4515
|
if (!dateObj) {
|
|
4281
4516
|
return jsx(Grid, {}, key);
|
|
4282
4517
|
}
|
|
4283
|
-
const { date, selected, selectable, today } = dateObj;
|
|
4518
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
4284
4519
|
const getDateColor = ({ today, selected, selectable, }) => {
|
|
4285
4520
|
if (!selectable) {
|
|
4286
|
-
return
|
|
4521
|
+
return 'gray';
|
|
4287
4522
|
}
|
|
4288
4523
|
if (selected) {
|
|
4289
|
-
return
|
|
4524
|
+
return 'blue';
|
|
4290
4525
|
}
|
|
4291
4526
|
if (today) {
|
|
4292
|
-
return
|
|
4527
|
+
return 'green';
|
|
4293
4528
|
}
|
|
4294
|
-
return
|
|
4529
|
+
return '';
|
|
4295
4530
|
};
|
|
4296
4531
|
const getVariant = ({ today, selected, selectable, }) => {
|
|
4297
4532
|
if (!selectable) {
|
|
4298
|
-
return
|
|
4533
|
+
return 'surface';
|
|
4299
4534
|
}
|
|
4300
4535
|
if (selected) {
|
|
4301
|
-
return
|
|
4536
|
+
return 'solid';
|
|
4302
4537
|
}
|
|
4303
4538
|
if (today) {
|
|
4304
|
-
return
|
|
4539
|
+
return 'surface';
|
|
4305
4540
|
}
|
|
4306
|
-
return
|
|
4541
|
+
return 'ghost';
|
|
4307
4542
|
};
|
|
4308
4543
|
const color = getDateColor({ today, selected, selectable });
|
|
4309
4544
|
const variant = getVariant({ today, selected, selectable });
|
|
4310
|
-
return (jsx(Button$1, { variant: variant, colorPalette: color, ...getDateProps({ dateObj }), children: selectable ? date.getDate() :
|
|
4545
|
+
return (jsx(Button$1, { variant: variant, colorPalette: color, opacity: isCurrentMonth ? 1 : 0.4, ...getDateProps({ dateObj }), children: selectable ? date.getDate() : 'X' }, key));
|
|
4311
4546
|
}))] })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
4312
4547
|
}
|
|
4313
4548
|
return null;
|
|
@@ -4315,50 +4550,55 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
4315
4550
|
const DatePickerContext = createContext({
|
|
4316
4551
|
labels: {
|
|
4317
4552
|
monthNamesShort: [
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4553
|
+
'Jan',
|
|
4554
|
+
'Feb',
|
|
4555
|
+
'Mar',
|
|
4556
|
+
'Apr',
|
|
4557
|
+
'May',
|
|
4558
|
+
'Jun',
|
|
4559
|
+
'Jul',
|
|
4560
|
+
'Aug',
|
|
4561
|
+
'Sep',
|
|
4562
|
+
'Oct',
|
|
4563
|
+
'Nov',
|
|
4564
|
+
'Dec',
|
|
4330
4565
|
],
|
|
4331
|
-
weekdayNamesShort: [
|
|
4332
|
-
backButtonLabel:
|
|
4333
|
-
forwardButtonLabel:
|
|
4566
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4567
|
+
backButtonLabel: 'Back',
|
|
4568
|
+
forwardButtonLabel: 'Next',
|
|
4334
4569
|
},
|
|
4335
4570
|
});
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4571
|
+
const DatePicker$1 = ({ labels = {
|
|
4572
|
+
monthNamesShort: [
|
|
4573
|
+
'Jan',
|
|
4574
|
+
'Feb',
|
|
4575
|
+
'Mar',
|
|
4576
|
+
'Apr',
|
|
4577
|
+
'May',
|
|
4578
|
+
'Jun',
|
|
4579
|
+
'Jul',
|
|
4580
|
+
'Aug',
|
|
4581
|
+
'Sep',
|
|
4582
|
+
'Oct',
|
|
4583
|
+
'Nov',
|
|
4584
|
+
'Dec',
|
|
4585
|
+
],
|
|
4586
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4587
|
+
backButtonLabel: 'Back',
|
|
4588
|
+
forwardButtonLabel: 'Next',
|
|
4589
|
+
}, onDateSelected, selected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
|
|
4590
|
+
const calendarData = useCalendar({
|
|
4591
|
+
onDateSelected,
|
|
4592
|
+
selected,
|
|
4593
|
+
firstDayOfWeek,
|
|
4594
|
+
showOutsideDays,
|
|
4595
|
+
date,
|
|
4596
|
+
minDate,
|
|
4597
|
+
maxDate,
|
|
4598
|
+
monthsToDisplay,
|
|
4599
|
+
});
|
|
4600
|
+
return (jsx(DatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsx(Calendar, { ...calendarData,
|
|
4601
|
+
firstDayOfWeek })) }));
|
|
4362
4602
|
};
|
|
4363
4603
|
|
|
4364
4604
|
dayjs.extend(utc);
|
|
@@ -4366,7 +4606,7 @@ dayjs.extend(timezone);
|
|
|
4366
4606
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
4367
4607
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4368
4608
|
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
4369
|
-
const formI18n = useFormI18n
|
|
4609
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4370
4610
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4371
4611
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4372
4612
|
const colLabel = formI18n.colLabel;
|
|
@@ -4400,74 +4640,30 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4400
4640
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4401
4641
|
const datePickerLabels = {
|
|
4402
4642
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
formI18n.translate.t(`common.month_5`, {
|
|
4416
|
-
defaultValue: 'May',
|
|
4417
|
-
}),
|
|
4418
|
-
formI18n.translate.t(`common.month_6`, {
|
|
4419
|
-
defaultValue: 'June',
|
|
4420
|
-
}),
|
|
4421
|
-
formI18n.translate.t(`common.month_7`, {
|
|
4422
|
-
defaultValue: 'July',
|
|
4423
|
-
}),
|
|
4424
|
-
formI18n.translate.t(`common.month_8`, {
|
|
4425
|
-
defaultValue: 'August',
|
|
4426
|
-
}),
|
|
4427
|
-
formI18n.translate.t(`common.month_9`, {
|
|
4428
|
-
defaultValue: 'September',
|
|
4429
|
-
}),
|
|
4430
|
-
formI18n.translate.t(`common.month_10`, {
|
|
4431
|
-
defaultValue: 'October',
|
|
4432
|
-
}),
|
|
4433
|
-
formI18n.translate.t(`common.month_11`, {
|
|
4434
|
-
defaultValue: 'November',
|
|
4435
|
-
}),
|
|
4436
|
-
formI18n.translate.t(`common.month_12`, {
|
|
4437
|
-
defaultValue: 'December',
|
|
4438
|
-
}),
|
|
4643
|
+
'January',
|
|
4644
|
+
'February',
|
|
4645
|
+
'March',
|
|
4646
|
+
'April',
|
|
4647
|
+
'May',
|
|
4648
|
+
'June',
|
|
4649
|
+
'July',
|
|
4650
|
+
'August',
|
|
4651
|
+
'September',
|
|
4652
|
+
'October',
|
|
4653
|
+
'November',
|
|
4654
|
+
'December',
|
|
4439
4655
|
],
|
|
4440
4656
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
defaultValue: 'Tue',
|
|
4449
|
-
}),
|
|
4450
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
4451
|
-
defaultValue: 'Wed',
|
|
4452
|
-
}),
|
|
4453
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
4454
|
-
defaultValue: 'Thu',
|
|
4455
|
-
}),
|
|
4456
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
4457
|
-
defaultValue: 'Fri',
|
|
4458
|
-
}),
|
|
4459
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
4460
|
-
defaultValue: 'Sat',
|
|
4461
|
-
}),
|
|
4657
|
+
'Sun',
|
|
4658
|
+
'Mon',
|
|
4659
|
+
'Tue',
|
|
4660
|
+
'Wed',
|
|
4661
|
+
'Thu',
|
|
4662
|
+
'Fri',
|
|
4663
|
+
'Sat',
|
|
4462
4664
|
],
|
|
4463
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4464
|
-
|
|
4465
|
-
defaultValue: 'Back',
|
|
4466
|
-
}),
|
|
4467
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4468
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
4469
|
-
defaultValue: 'Forward',
|
|
4470
|
-
}),
|
|
4665
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
4666
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
4471
4667
|
};
|
|
4472
4668
|
const datePickerContent = (jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4473
4669
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
@@ -4484,7 +4680,7 @@ dayjs.extend(timezone);
|
|
|
4484
4680
|
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4485
4681
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4486
4682
|
const { timezone, insideDialog } = useSchemaContext();
|
|
4487
|
-
const formI18n = useFormI18n
|
|
4683
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4488
4684
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4489
4685
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4490
4686
|
const colLabel = formI18n.colLabel;
|
|
@@ -4582,7 +4778,7 @@ const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
|
4582
4778
|
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
4583
4779
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4584
4780
|
const { enumPickerLabels, insideDialog } = useSchemaContext();
|
|
4585
|
-
const formI18n = useFormI18n
|
|
4781
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4586
4782
|
const { required, variant } = schema;
|
|
4587
4783
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4588
4784
|
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
@@ -5129,7 +5325,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
|
|
|
5129
5325
|
}) })) }))] }));
|
|
5130
5326
|
};
|
|
5131
5327
|
|
|
5132
|
-
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels,
|
|
5328
|
+
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, colLabel, }) {
|
|
5133
5329
|
const [selectedFile, setSelectedFile] = useState(undefined);
|
|
5134
5330
|
const [activeTab, setActiveTab] = useState('browse');
|
|
5135
5331
|
const [uploadingFiles, setUploadingFiles] = useState(new Set());
|
|
@@ -5198,15 +5394,8 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5198
5394
|
const showTabs = enableUpload && !!onUploadFile && !!onFetchFiles;
|
|
5199
5395
|
if (!onFetchFiles && !onUploadFile)
|
|
5200
5396
|
return null;
|
|
5201
|
-
return (jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsx(DialogCloseTrigger, {})] }), jsx(DialogBody, { children: showTabs ? (jsxs(Tabs.Root, { value: activeTab, onValueChange: (e) => setActiveTab(e.value ?? 'browse'), children: [jsxs(Tabs.List, { children: [jsx(Tabs.Trigger, { value: "browse", children: labels?.browseTab ??
|
|
5202
|
-
|
|
5203
|
-
'Browse Library' }), jsx(Tabs.Trigger, { value: "upload", children: labels?.uploadTab ??
|
|
5204
|
-
translate(removeIndex(`${colLabel}.upload_tab`)) ??
|
|
5205
|
-
'Upload Files' })] }), jsx(Tabs.Content, { value: "browse", children: onFetchFiles && (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFile: selectedFile, onFileSelect: setSelectedFile })) }), jsx(Tabs.Content, { value: "upload", children: jsxs(VStack, { align: "stretch", gap: 4, children: [jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
5206
|
-
translate(removeIndex(`${colLabel}.fileDropzone`)) ??
|
|
5207
|
-
'Drop files here or click to upload' }), uploadingFiles.size > 0 && (jsx(Box, { children: Array.from(uploadingFiles).map((fileKey) => (jsx(Box, { py: 2, children: jsxs(HStack, { gap: 2, children: [jsx(Spinner, { size: "sm", colorPalette: "blue" }), jsxs(Text, { fontSize: "sm", color: "fg.muted", children: [labels?.uploading ??
|
|
5208
|
-
translate(removeIndex(`${colLabel}.uploading`)) ??
|
|
5209
|
-
'Uploading...', ' ', fileKey.split('-')[0]] })] }) }, fileKey))) })), uploadErrors.size > 0 && (jsx(VStack, { align: "stretch", gap: 2, children: Array.from(uploadErrors.entries()).map(([fileKey, error]) => (jsx(Box, { bg: {
|
|
5397
|
+
return (jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsx(DialogCloseTrigger, {})] }), jsx(DialogBody, { children: showTabs ? (jsxs(Tabs.Root, { value: activeTab, onValueChange: (e) => setActiveTab(e.value ?? 'browse'), children: [jsxs(Tabs.List, { children: [jsx(Tabs.Trigger, { value: "browse", children: labels?.browseTab ?? 'Browse Library' }), jsx(Tabs.Trigger, { value: "upload", children: labels?.uploadTab ?? 'Upload Files' })] }), jsx(Tabs.Content, { value: "browse", children: onFetchFiles && (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFile: selectedFile, onFileSelect: setSelectedFile })) }), jsx(Tabs.Content, { value: "upload", children: jsxs(VStack, { align: "stretch", gap: 4, children: [jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
5398
|
+
'Drop files here or click to upload' }), uploadingFiles.size > 0 && (jsx(Box, { children: Array.from(uploadingFiles).map((fileKey) => (jsx(Box, { py: 2, children: jsxs(HStack, { gap: 2, children: [jsx(Spinner, { size: "sm", colorPalette: "blue" }), jsxs(Text, { fontSize: "sm", color: "fg.muted", children: [labels?.uploading ?? 'Uploading...', ' ', fileKey.split('-')[0]] })] }) }, fileKey))) })), uploadErrors.size > 0 && (jsx(VStack, { align: "stretch", gap: 2, children: Array.from(uploadErrors.entries()).map(([fileKey, error]) => (jsx(Box, { bg: {
|
|
5210
5399
|
base: 'colorPalette.50',
|
|
5211
5400
|
_dark: 'colorPalette.900/20',
|
|
5212
5401
|
}, border: "1px solid", borderColor: {
|
|
@@ -5215,18 +5404,12 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5215
5404
|
}, colorPalette: "red", borderRadius: "md", p: 3, children: jsxs(Text, { fontSize: "sm", color: {
|
|
5216
5405
|
base: 'colorPalette.600',
|
|
5217
5406
|
_dark: 'colorPalette.300',
|
|
5218
|
-
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ??
|
|
5219
|
-
translate(removeIndex(`${colLabel}.upload_failed`)) ??
|
|
5220
|
-
'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFile: selectedFile, onFileSelect: setSelectedFile })) : null }), jsx(DialogFooter, { children: jsxs(HStack, { gap: 3, justify: "end", children: [jsx(Button$1, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
|
|
5221
|
-
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
5222
|
-
'Cancel' }), jsx(Button$1, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ??
|
|
5223
|
-
translate(removeIndex(`${colLabel}.select`)) ??
|
|
5224
|
-
'Select' })] }) })] }) }));
|
|
5407
|
+
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ?? 'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFile: selectedFile, onFileSelect: setSelectedFile })) : null }), jsx(DialogFooter, { children: jsxs(HStack, { gap: 3, justify: "end", children: [jsx(Button$1, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ?? 'Cancel' }), jsx(Button$1, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ?? 'Select' })] }) })] }) }));
|
|
5225
5408
|
}
|
|
5226
5409
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
5227
5410
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5228
5411
|
const { filePickerLabels } = useSchemaContext();
|
|
5229
|
-
const formI18n = useFormI18n
|
|
5412
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5230
5413
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5231
5414
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5232
5415
|
const isSingleSelect = type === 'string';
|
|
@@ -5302,7 +5485,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5302
5485
|
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
5303
5486
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5304
5487
|
const { filePickerLabels } = useSchemaContext();
|
|
5305
|
-
const formI18n = useFormI18n
|
|
5488
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5306
5489
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
5307
5490
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5308
5491
|
const isSingleSelect = type === 'string';
|
|
@@ -5398,8 +5581,8 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5398
5581
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsx(VStack, { align: "stretch", gap: 2, children: jsx(Button$1, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
5399
5582
|
formI18n.t('browse_library') ??
|
|
5400
5583
|
'Browse from Library' }) }), jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5401
|
-
|
|
5402
|
-
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels,
|
|
5584
|
+
filePickerLabels?.dialogTitle ??
|
|
5585
|
+
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5403
5586
|
const file = fileMap.get(fileId);
|
|
5404
5587
|
const isImage = file
|
|
5405
5588
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5448,17 +5631,79 @@ const defaultRenderDisplay = (item) => {
|
|
|
5448
5631
|
return JSON.stringify(item);
|
|
5449
5632
|
};
|
|
5450
5633
|
|
|
5451
|
-
|
|
5634
|
+
/**
|
|
5635
|
+
* Load initial values for IdPicker fields into idMap
|
|
5636
|
+
* Uses customQueryFn if available, otherwise falls back to getTableData
|
|
5637
|
+
*
|
|
5638
|
+
* @param params - Configuration for loading initial values
|
|
5639
|
+
* @returns Promise with fetched data and idMap
|
|
5640
|
+
*/
|
|
5641
|
+
const loadInitialValues = async ({ ids, foreign_key, serverUrl, setIdMap, }) => {
|
|
5642
|
+
if (!ids || ids.length === 0) {
|
|
5643
|
+
return { data: { data: [], count: 0 }, idMap: {} };
|
|
5644
|
+
}
|
|
5645
|
+
const { table, column: column_ref, customQueryFn } = foreign_key;
|
|
5646
|
+
// Filter out IDs that are already in idMap (optional optimization)
|
|
5647
|
+
// For now, we'll fetch all requested IDs to ensure consistency
|
|
5648
|
+
if (customQueryFn) {
|
|
5649
|
+
const { data, idMap: returnedIdMap } = await customQueryFn({
|
|
5650
|
+
searching: '',
|
|
5651
|
+
limit: ids.length,
|
|
5652
|
+
offset: 0,
|
|
5653
|
+
where: [
|
|
5654
|
+
{
|
|
5655
|
+
id: column_ref,
|
|
5656
|
+
value: ids.length === 1 ? ids[0] : ids, // CustomQueryFn accepts string | string[]
|
|
5657
|
+
},
|
|
5658
|
+
],
|
|
5659
|
+
});
|
|
5660
|
+
// Update idMap with returned values
|
|
5661
|
+
if (returnedIdMap && Object.keys(returnedIdMap).length > 0) {
|
|
5662
|
+
setIdMap((state) => {
|
|
5663
|
+
return { ...state, ...returnedIdMap };
|
|
5664
|
+
});
|
|
5665
|
+
}
|
|
5666
|
+
return { data, idMap: returnedIdMap || {} };
|
|
5667
|
+
}
|
|
5668
|
+
// Fallback to default getTableData
|
|
5669
|
+
const data = await getTableData({
|
|
5670
|
+
serverUrl,
|
|
5671
|
+
searching: '',
|
|
5672
|
+
in_table: table,
|
|
5673
|
+
limit: ids.length,
|
|
5674
|
+
offset: 0,
|
|
5675
|
+
where: [
|
|
5676
|
+
{
|
|
5677
|
+
id: column_ref,
|
|
5678
|
+
value: ids, // Always pass as array
|
|
5679
|
+
},
|
|
5680
|
+
],
|
|
5681
|
+
});
|
|
5682
|
+
// Build idMap from fetched data
|
|
5683
|
+
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
5684
|
+
return [
|
|
5685
|
+
item[column_ref],
|
|
5686
|
+
{
|
|
5687
|
+
...item,
|
|
5688
|
+
},
|
|
5689
|
+
];
|
|
5690
|
+
}));
|
|
5691
|
+
// Update idMap state
|
|
5692
|
+
setIdMap((state) => {
|
|
5693
|
+
return { ...state, ...newMap };
|
|
5694
|
+
});
|
|
5695
|
+
return { data: data, idMap: newMap };
|
|
5696
|
+
};
|
|
5697
|
+
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5452
5698
|
const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
|
|
5453
5699
|
const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5454
|
-
const
|
|
5455
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
5456
|
-
const isRequired = required?.some((columnId) => columnId === column);
|
|
5700
|
+
const { renderDisplay, foreign_key } = schema;
|
|
5457
5701
|
const { table, column: column_ref, customQueryFn, } = foreign_key;
|
|
5458
5702
|
const [searchText, setSearchText] = useState('');
|
|
5459
5703
|
const [debouncedSearchText, setDebouncedSearchText] = useState('');
|
|
5460
5704
|
const [limit] = useState(50); // Increased limit for combobox
|
|
5461
|
-
|
|
5705
|
+
// Get colLabel from schema context (we'll compute it here)
|
|
5706
|
+
const colLabel = `${prefix}${column}`;
|
|
5462
5707
|
const watchedValue = watch(colLabel);
|
|
5463
5708
|
const watchId = !isMultiple ? watchedValue : undefined;
|
|
5464
5709
|
const watchIds = isMultiple
|
|
@@ -5505,48 +5750,14 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5505
5750
|
if (missingIds.length === 0) {
|
|
5506
5751
|
return { data: [], count: 0 };
|
|
5507
5752
|
}
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
offset: 0,
|
|
5513
|
-
where: [
|
|
5514
|
-
{
|
|
5515
|
-
id: column_ref,
|
|
5516
|
-
value: missingIds.length === 1 ? missingIds[0] : missingIds,
|
|
5517
|
-
},
|
|
5518
|
-
],
|
|
5519
|
-
});
|
|
5520
|
-
setIdMap((state) => {
|
|
5521
|
-
return { ...state, ...idMap };
|
|
5522
|
-
});
|
|
5523
|
-
return data;
|
|
5524
|
-
}
|
|
5525
|
-
const data = await getTableData({
|
|
5753
|
+
// Use the reusable loadInitialValues function
|
|
5754
|
+
const result = await loadInitialValues({
|
|
5755
|
+
ids: missingIds,
|
|
5756
|
+
foreign_key: foreign_key,
|
|
5526
5757
|
serverUrl,
|
|
5527
|
-
|
|
5528
|
-
in_table: table,
|
|
5529
|
-
limit: missingIds.length,
|
|
5530
|
-
offset: 0,
|
|
5531
|
-
where: [
|
|
5532
|
-
{
|
|
5533
|
-
id: column_ref,
|
|
5534
|
-
value: missingIds.length === 1 ? missingIds[0] : missingIds,
|
|
5535
|
-
},
|
|
5536
|
-
],
|
|
5537
|
-
});
|
|
5538
|
-
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
5539
|
-
return [
|
|
5540
|
-
item[column_ref],
|
|
5541
|
-
{
|
|
5542
|
-
...item,
|
|
5543
|
-
},
|
|
5544
|
-
];
|
|
5545
|
-
}));
|
|
5546
|
-
setIdMap((state) => {
|
|
5547
|
-
return { ...state, ...newMap };
|
|
5758
|
+
setIdMap,
|
|
5548
5759
|
});
|
|
5549
|
-
return data;
|
|
5760
|
+
return result.data;
|
|
5550
5761
|
},
|
|
5551
5762
|
enabled: missingIds.length > 0, // Only fetch if there are missing IDs
|
|
5552
5763
|
staleTime: 300000,
|
|
@@ -5657,20 +5868,6 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5657
5868
|
itemToValue: (item) => item.value,
|
|
5658
5869
|
filter: contains,
|
|
5659
5870
|
});
|
|
5660
|
-
// Handle input value change (search)
|
|
5661
|
-
const handleInputValueChange = (details) => {
|
|
5662
|
-
setSearchText(details.inputValue);
|
|
5663
|
-
// Filter will be applied after data is fetched
|
|
5664
|
-
};
|
|
5665
|
-
// Handle value change
|
|
5666
|
-
const handleValueChange = (details) => {
|
|
5667
|
-
if (isMultiple) {
|
|
5668
|
-
setValue(colLabel, details.value);
|
|
5669
|
-
}
|
|
5670
|
-
else {
|
|
5671
|
-
setValue(colLabel, details.value[0] || '');
|
|
5672
|
-
}
|
|
5673
|
-
};
|
|
5674
5871
|
// Track previous comboboxItems to avoid unnecessary updates
|
|
5675
5872
|
const prevComboboxItemsRef = useRef('');
|
|
5676
5873
|
const prevSearchTextRef = useRef('');
|
|
@@ -5700,8 +5897,106 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5700
5897
|
// comboboxItems and searchText are the only dependencies we care about
|
|
5701
5898
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5702
5899
|
}, [comboboxItems, searchText]);
|
|
5900
|
+
return {
|
|
5901
|
+
colLabel,
|
|
5902
|
+
currentValue,
|
|
5903
|
+
searchText,
|
|
5904
|
+
setSearchText,
|
|
5905
|
+
debouncedSearchText,
|
|
5906
|
+
isLoading,
|
|
5907
|
+
isFetching,
|
|
5908
|
+
isPending,
|
|
5909
|
+
isError,
|
|
5910
|
+
isSearching,
|
|
5911
|
+
isLoadingInitialValues,
|
|
5912
|
+
isFetchingInitialValues,
|
|
5913
|
+
missingIds,
|
|
5914
|
+
comboboxItems,
|
|
5915
|
+
collection,
|
|
5916
|
+
filter,
|
|
5917
|
+
set,
|
|
5918
|
+
idMap,
|
|
5919
|
+
idPickerLabels,
|
|
5920
|
+
insideDialog: insideDialog ?? false,
|
|
5921
|
+
renderDisplay,
|
|
5922
|
+
column_ref,
|
|
5923
|
+
errors,
|
|
5924
|
+
setValue,
|
|
5925
|
+
};
|
|
5926
|
+
};
|
|
5927
|
+
|
|
5928
|
+
const IdPickerSingle = ({ column, schema, prefix, }) => {
|
|
5929
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5930
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
5931
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5932
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
5933
|
+
column,
|
|
5934
|
+
schema,
|
|
5935
|
+
prefix,
|
|
5936
|
+
isMultiple: false,
|
|
5937
|
+
});
|
|
5938
|
+
const handleInputValueChange = (details) => {
|
|
5939
|
+
setSearchText(details.inputValue);
|
|
5940
|
+
};
|
|
5941
|
+
const handleValueChange = (details) => {
|
|
5942
|
+
setValue(colLabel, details.value[0] || '');
|
|
5943
|
+
};
|
|
5944
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
5703
5945
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5704
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [
|
|
5946
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsx(Flex, { mb: 2, children: (() => {
|
|
5947
|
+
const id = currentValue[0];
|
|
5948
|
+
const item = idMap[id];
|
|
5949
|
+
// Show loading skeleton while fetching initial values
|
|
5950
|
+
if (item === undefined &&
|
|
5951
|
+
(isLoadingInitialValues || isFetchingInitialValues) &&
|
|
5952
|
+
missingIds.includes(id)) {
|
|
5953
|
+
return jsx(Skeleton, { height: "24px", width: "100px", borderRadius: "md" });
|
|
5954
|
+
}
|
|
5955
|
+
// Only show "not found" if we're not loading and item is still missing
|
|
5956
|
+
if (item === undefined) {
|
|
5957
|
+
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }));
|
|
5958
|
+
}
|
|
5959
|
+
return jsx(Text, { fontSize: "sm", children: renderDisplayFunction(item) });
|
|
5960
|
+
})() })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: false, closeOnSelect: true, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5961
|
+
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5962
|
+
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxs(Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, { size: "xs" }), isError && (jsx(Icon, { color: "fg.error", children: jsx(BiError, {}) })), currentValue.length > 0 && (jsx(Combobox.ClearTrigger, { onClick: () => {
|
|
5963
|
+
setValue(colLabel, '');
|
|
5964
|
+
} })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5965
|
+
// Show skeleton items to prevent UI shift
|
|
5966
|
+
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5967
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5968
|
+
: idPickerLabels?.initialResults ??
|
|
5969
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
5970
|
+
? renderDisplayFunction(item.raw)
|
|
5971
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5972
|
+
// Show skeleton items to prevent UI shift
|
|
5973
|
+
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5974
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5975
|
+
: idPickerLabels?.initialResults ??
|
|
5976
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
5977
|
+
? renderDisplayFunction(item.raw)
|
|
5978
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5979
|
+
};
|
|
5980
|
+
|
|
5981
|
+
const IdPickerMultiple = ({ column, schema, prefix, }) => {
|
|
5982
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5983
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
5984
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5985
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
5986
|
+
column,
|
|
5987
|
+
schema,
|
|
5988
|
+
prefix,
|
|
5989
|
+
isMultiple: true,
|
|
5990
|
+
});
|
|
5991
|
+
const handleInputValueChange = (details) => {
|
|
5992
|
+
setSearchText(details.inputValue);
|
|
5993
|
+
};
|
|
5994
|
+
const handleValueChange = (details) => {
|
|
5995
|
+
setValue(colLabel, details.value);
|
|
5996
|
+
};
|
|
5997
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
5998
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5999
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsx(Flex, { flexFlow: 'wrap', gap: 1, mb: 2, children: currentValue.map((id) => {
|
|
5705
6000
|
const item = idMap[id];
|
|
5706
6001
|
// Show loading skeleton while fetching initial values
|
|
5707
6002
|
if (item === undefined &&
|
|
@@ -5711,34 +6006,28 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5711
6006
|
}
|
|
5712
6007
|
// Only show "not found" if we're not loading and item is still missing
|
|
5713
6008
|
if (item === undefined) {
|
|
5714
|
-
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ??
|
|
6009
|
+
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
5715
6010
|
}
|
|
5716
6011
|
return (jsx(Tag, { closable: true, onClick: () => {
|
|
5717
6012
|
const newValue = currentValue.filter((itemId) => itemId !== id);
|
|
5718
6013
|
setValue(colLabel, newValue);
|
|
5719
|
-
}, children:
|
|
5720
|
-
|
|
5721
|
-
: defaultRenderDisplay(item) }, id));
|
|
5722
|
-
}) })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: isMultiple, closeOnSelect: !isMultiple, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
6014
|
+
}, children: renderDisplayFunction(item) }, id));
|
|
6015
|
+
}) })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: true, closeOnSelect: false, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5723
6016
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5724
|
-
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ??
|
|
5725
|
-
setValue(colLabel, '');
|
|
5726
|
-
} })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: formI18n.t('loading_failed') })) : isFetching || isLoading || isPending || isSearching ? (
|
|
6017
|
+
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxs(Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, { size: "xs" }), isError && (jsx(Icon, { color: "fg.error", children: jsx(BiError, {}) })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5727
6018
|
// Show skeleton items to prevent UI shift
|
|
5728
6019
|
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5729
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5730
|
-
formI18n.t('empty_search_result')
|
|
6020
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5731
6021
|
: idPickerLabels?.initialResults ??
|
|
5732
|
-
|
|
5733
|
-
?
|
|
5734
|
-
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children:
|
|
6022
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
6023
|
+
? renderDisplayFunction(item.raw)
|
|
6024
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5735
6025
|
// Show skeleton items to prevent UI shift
|
|
5736
6026
|
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5737
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5738
|
-
formI18n.t('empty_search_result')
|
|
6027
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5739
6028
|
: idPickerLabels?.initialResults ??
|
|
5740
|
-
|
|
5741
|
-
?
|
|
6029
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
6030
|
+
? renderDisplayFunction(item.raw)
|
|
5742
6031
|
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5743
6032
|
};
|
|
5744
6033
|
|
|
@@ -5812,7 +6101,7 @@ const NumberInputField = ({ schema, column, prefix, }) => {
|
|
|
5812
6101
|
const colLabel = `${prefix}${column}`;
|
|
5813
6102
|
const value = watch(`${colLabel}`);
|
|
5814
6103
|
const fieldError = getFieldError(errors, colLabel);
|
|
5815
|
-
const formI18n = useFormI18n
|
|
6104
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5816
6105
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn, gridRow, errorText: fieldError
|
|
5817
6106
|
? fieldError.includes('required')
|
|
5818
6107
|
? formI18n.required()
|
|
@@ -5830,7 +6119,7 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5830
6119
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
5831
6120
|
const colLabel = `${prefix}${column}`;
|
|
5832
6121
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5833
|
-
const formI18n = useFormI18n
|
|
6122
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5834
6123
|
const { formState: { errors }, } = useFormContext();
|
|
5835
6124
|
if (properties === undefined) {
|
|
5836
6125
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -5850,14 +6139,14 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5850
6139
|
|
|
5851
6140
|
const RecordInput = ({ column, schema, prefix }) => {
|
|
5852
6141
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
5853
|
-
const {
|
|
6142
|
+
const { formButtonLabels } = useSchemaContext();
|
|
5854
6143
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5855
6144
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5856
6145
|
const entries = Object.entries(getValues(column) ?? {});
|
|
5857
6146
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
5858
6147
|
const [newKey, setNewKey] = useState();
|
|
5859
6148
|
const [newValue, setNewValue] = useState();
|
|
5860
|
-
const formI18n = useFormI18n
|
|
6149
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5861
6150
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`] ? formI18n.required() : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
|
|
5862
6151
|
return (jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
5863
6152
|
const filtered = entries.filter(([target]) => {
|
|
@@ -5894,11 +6183,11 @@ const RecordInput = ({ column, schema, prefix }) => {
|
|
|
5894
6183
|
setShowNewEntries(false);
|
|
5895
6184
|
setNewKey(undefined);
|
|
5896
6185
|
setNewValue(undefined);
|
|
5897
|
-
}, children:
|
|
6186
|
+
}, children: formButtonLabels?.save ?? 'Save' })] })] }) }), jsx(Button, { onClick: () => {
|
|
5898
6187
|
setShowNewEntries(true);
|
|
5899
6188
|
setNewKey(undefined);
|
|
5900
6189
|
setNewValue(undefined);
|
|
5901
|
-
}, children:
|
|
6190
|
+
}, children: formButtonLabels?.addNew ?? 'Add New' })] }));
|
|
5902
6191
|
};
|
|
5903
6192
|
|
|
5904
6193
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
@@ -5907,7 +6196,7 @@ const StringInputField = ({ column, schema, prefix, }) => {
|
|
|
5907
6196
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5908
6197
|
const colLabel = `${prefix}${column}`;
|
|
5909
6198
|
const fieldError = getFieldError(errors, colLabel);
|
|
5910
|
-
const formI18n = useFormI18n
|
|
6199
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5911
6200
|
return (jsx(Fragment, { children: jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
|
|
5912
6201
|
};
|
|
5913
6202
|
|
|
@@ -6099,7 +6388,7 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6099
6388
|
const form = useFormContext();
|
|
6100
6389
|
const { setValue, watch } = form;
|
|
6101
6390
|
const fieldError = getFieldError(errors, colLabel);
|
|
6102
|
-
const formI18n = useFormI18n
|
|
6391
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6103
6392
|
const watchValue = watch(colLabel);
|
|
6104
6393
|
return (jsx(Fragment, { children: jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
|
|
6105
6394
|
? fieldError.includes('required')
|
|
@@ -6110,18 +6399,13 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6110
6399
|
|
|
6111
6400
|
dayjs.extend(utc);
|
|
6112
6401
|
dayjs.extend(timezone);
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
},
|
|
6119
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6120
|
-
onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, portalled = true, }) {
|
|
6121
|
-
// Generate time options (every 15 minutes)
|
|
6402
|
+
const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem, onChange = () => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6403
|
+
placeholder: 'hh:mm AM/PM',
|
|
6404
|
+
emptyMessage: 'No time found',
|
|
6405
|
+
}, }) => {
|
|
6406
|
+
// Generate time options (every 15 minutes in 12-hour format)
|
|
6122
6407
|
const timeOptions = useMemo(() => {
|
|
6123
6408
|
const options = [];
|
|
6124
|
-
const meridiemOptions = ['am', 'pm'];
|
|
6125
6409
|
// Get start time for comparison if provided
|
|
6126
6410
|
let startDateTime = null;
|
|
6127
6411
|
let shouldFilterByDate = false;
|
|
@@ -6136,14 +6420,16 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6136
6420
|
selectedDateObj.format('YYYY-MM-DD');
|
|
6137
6421
|
}
|
|
6138
6422
|
}
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
//
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6423
|
+
// Generate 12-hour format options (1-12 for hours, AM/PM)
|
|
6424
|
+
for (let h = 1; h <= 12; h++) {
|
|
6425
|
+
for (let m = 0; m < 60; m += 15) {
|
|
6426
|
+
for (const mer of ['am', 'pm']) {
|
|
6427
|
+
// Convert 12-hour to 24-hour for comparison
|
|
6428
|
+
let hour24 = h;
|
|
6429
|
+
if (mer === 'am' && h === 12)
|
|
6430
|
+
hour24 = 0;
|
|
6431
|
+
else if (mer === 'pm' && h < 12)
|
|
6432
|
+
hour24 = h + 12;
|
|
6147
6433
|
// Filter out times that would result in negative duration (only when dates are the same)
|
|
6148
6434
|
if (startDateTime && selectedDate && shouldFilterByDate) {
|
|
6149
6435
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
@@ -6186,20 +6472,23 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6186
6472
|
}
|
|
6187
6473
|
}
|
|
6188
6474
|
}
|
|
6475
|
+
const hourDisplay = h.toString();
|
|
6476
|
+
const minuteDisplay = m.toString().padStart(2, '0');
|
|
6477
|
+
const timeDisplay = `${hourDisplay}:${minuteDisplay} ${mer.toUpperCase()}`;
|
|
6189
6478
|
options.push({
|
|
6190
|
-
label:
|
|
6191
|
-
value: `${h}:${m
|
|
6479
|
+
label: timeDisplay,
|
|
6480
|
+
value: `${h}:${m}:${mer}`,
|
|
6192
6481
|
hour: h,
|
|
6193
6482
|
minute: m,
|
|
6194
6483
|
meridiem: mer,
|
|
6195
|
-
searchText:
|
|
6484
|
+
searchText: timeDisplay, // Use base time without duration for searching
|
|
6196
6485
|
durationText,
|
|
6197
6486
|
});
|
|
6198
6487
|
}
|
|
6199
6488
|
}
|
|
6200
6489
|
}
|
|
6201
6490
|
return options;
|
|
6202
|
-
}, [
|
|
6491
|
+
}, [startTime, selectedDate, timezone]);
|
|
6203
6492
|
const { contains } = useFilter({ sensitivity: 'base' });
|
|
6204
6493
|
const { collection, filter } = useListCollection({
|
|
6205
6494
|
initialItems: timeOptions,
|
|
@@ -6212,7 +6501,7 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6212
6501
|
if (hour === null || minute === null || meridiem === null) {
|
|
6213
6502
|
return '';
|
|
6214
6503
|
}
|
|
6215
|
-
return `${hour}:${minute
|
|
6504
|
+
return `${hour}:${minute}:${meridiem}`;
|
|
6216
6505
|
}, [hour, minute, meridiem]);
|
|
6217
6506
|
// Calculate duration difference
|
|
6218
6507
|
const durationDiff = useMemo(() => {
|
|
@@ -6223,15 +6512,14 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6223
6512
|
meridiem === null) {
|
|
6224
6513
|
return null;
|
|
6225
6514
|
}
|
|
6226
|
-
const hour24 = meridiem === 'am'
|
|
6227
|
-
? hour === 12
|
|
6228
|
-
? 0
|
|
6229
|
-
: hour
|
|
6230
|
-
: hour === 12
|
|
6231
|
-
? 12
|
|
6232
|
-
: hour + 12;
|
|
6233
6515
|
const startDateObj = dayjs(startTime).tz(timezone);
|
|
6234
6516
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
6517
|
+
// Convert 12-hour to 24-hour format
|
|
6518
|
+
let hour24 = hour;
|
|
6519
|
+
if (meridiem === 'am' && hour === 12)
|
|
6520
|
+
hour24 = 0;
|
|
6521
|
+
else if (meridiem === 'pm' && hour < 12)
|
|
6522
|
+
hour24 = hour + 12;
|
|
6235
6523
|
const currentDateTime = selectedDateObj
|
|
6236
6524
|
.hour(hour24)
|
|
6237
6525
|
.minute(minute)
|
|
@@ -6296,83 +6584,54 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6296
6584
|
if (!trimmedValue) {
|
|
6297
6585
|
return;
|
|
6298
6586
|
}
|
|
6299
|
-
//
|
|
6300
|
-
const
|
|
6301
|
-
|
|
6302
|
-
// Matches: 1-2 digits hour, optional colon, 2 digits minute, am/pm
|
|
6303
|
-
const pattern12HourWithMeridiem = /^(\d{1,2}):?(\d{2})(am|pm)$/;
|
|
6304
|
-
const match12Hour = normalized.match(pattern12HourWithMeridiem);
|
|
6587
|
+
// Parse formats like "1:30 PM", "1:30PM", "1:30 pm", "1:30pm"
|
|
6588
|
+
const timePattern12Hour = /^(\d{1,2}):(\d{1,2})\s*(am|pm|AM|PM)$/i;
|
|
6589
|
+
const match12Hour = trimmedValue.match(timePattern12Hour);
|
|
6305
6590
|
if (match12Hour) {
|
|
6306
6591
|
const parsedHour = parseInt(match12Hour[1], 10);
|
|
6307
6592
|
const parsedMinute = parseInt(match12Hour[2], 10);
|
|
6308
|
-
const parsedMeridiem = match12Hour[3];
|
|
6309
|
-
// Validate
|
|
6310
|
-
if (parsedHour
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6593
|
+
const parsedMeridiem = match12Hour[3].toLowerCase();
|
|
6594
|
+
// Validate ranges
|
|
6595
|
+
if (parsedHour >= 1 &&
|
|
6596
|
+
parsedHour <= 12 &&
|
|
6597
|
+
parsedMinute >= 0 &&
|
|
6598
|
+
parsedMinute <= 59) {
|
|
6599
|
+
setHour(parsedHour);
|
|
6600
|
+
setMinute(parsedMinute);
|
|
6601
|
+
setMeridiem(parsedMeridiem);
|
|
6602
|
+
onChange({
|
|
6603
|
+
hour: parsedHour,
|
|
6604
|
+
minute: parsedMinute,
|
|
6605
|
+
meridiem: parsedMeridiem,
|
|
6606
|
+
});
|
|
6319
6607
|
return;
|
|
6320
6608
|
}
|
|
6321
|
-
setHour(parsedHour);
|
|
6322
|
-
setMinute(parsedMinute);
|
|
6323
|
-
setMeridiem(parsedMeridiem);
|
|
6324
|
-
onChange({
|
|
6325
|
-
hour: parsedHour,
|
|
6326
|
-
minute: parsedMinute,
|
|
6327
|
-
meridiem: parsedMeridiem,
|
|
6328
|
-
});
|
|
6329
|
-
return;
|
|
6330
6609
|
}
|
|
6331
|
-
//
|
|
6332
|
-
|
|
6333
|
-
const
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
//
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
}
|
|
6356
|
-
else if (parsedHour === 12) {
|
|
6357
|
-
parsedHour = 12;
|
|
6358
|
-
parsedMeridiem = 'pm';
|
|
6359
|
-
}
|
|
6360
|
-
else if (parsedHour > 12) {
|
|
6361
|
-
parsedHour = parsedHour - 12;
|
|
6362
|
-
parsedMeridiem = 'pm';
|
|
6363
|
-
}
|
|
6364
|
-
else {
|
|
6365
|
-
parsedMeridiem = 'am';
|
|
6610
|
+
// Try to parse formats like "130pm" or "130 pm" (without colon)
|
|
6611
|
+
const timePatternNoColon = /^(\d{1,4})\s*(am|pm|AM|PM)$/i;
|
|
6612
|
+
const matchNoColon = trimmedValue.match(timePatternNoColon);
|
|
6613
|
+
if (matchNoColon) {
|
|
6614
|
+
const numbersOnly = matchNoColon[1];
|
|
6615
|
+
const parsedMeridiem = matchNoColon[2].toLowerCase();
|
|
6616
|
+
if (numbersOnly.length >= 3) {
|
|
6617
|
+
const parsedHour = parseInt(numbersOnly.slice(0, -2), 10);
|
|
6618
|
+
const parsedMinute = parseInt(numbersOnly.slice(-2), 10);
|
|
6619
|
+
// Validate ranges
|
|
6620
|
+
if (parsedHour >= 1 &&
|
|
6621
|
+
parsedHour <= 12 &&
|
|
6622
|
+
parsedMinute >= 0 &&
|
|
6623
|
+
parsedMinute <= 59) {
|
|
6624
|
+
setHour(parsedHour);
|
|
6625
|
+
setMinute(parsedMinute);
|
|
6626
|
+
setMeridiem(parsedMeridiem);
|
|
6627
|
+
onChange({
|
|
6628
|
+
hour: parsedHour,
|
|
6629
|
+
minute: parsedMinute,
|
|
6630
|
+
meridiem: parsedMeridiem,
|
|
6631
|
+
});
|
|
6632
|
+
return;
|
|
6633
|
+
}
|
|
6366
6634
|
}
|
|
6367
|
-
setHour(parsedHour);
|
|
6368
|
-
setMinute(parsedMinute);
|
|
6369
|
-
setMeridiem(parsedMeridiem);
|
|
6370
|
-
onChange({
|
|
6371
|
-
hour: parsedHour,
|
|
6372
|
-
minute: parsedMinute,
|
|
6373
|
-
meridiem: parsedMeridiem,
|
|
6374
|
-
});
|
|
6375
|
-
return;
|
|
6376
6635
|
}
|
|
6377
6636
|
// Parse failed, select first result
|
|
6378
6637
|
selectFirstResult();
|
|
@@ -6419,17 +6678,17 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6419
6678
|
e.currentTarget?.blur();
|
|
6420
6679
|
}
|
|
6421
6680
|
};
|
|
6422
|
-
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder:
|
|
6423
|
-
}
|
|
6681
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder: labels?.placeholder ?? 'hh:mm AM/PM', onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsx(Combobox.IndicatorGroup, { children: jsx(Combobox.Trigger, {}) })] }), jsx(Portal, { disabled: !portalled, children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [jsx(Combobox.Empty, { children: labels?.emptyMessage ?? 'No time found' }), collection.items.map((item) => (jsxs(Combobox.Item, { item: item, children: [jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsx(Text, { flex: 1, children: item.label }), item.durationText && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: item.durationText }) }))] }), jsx(Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: durationDiff }) })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(Icon, { children: jsx(MdCancel, {}) }) })] }) }));
|
|
6682
|
+
};
|
|
6424
6683
|
|
|
6425
6684
|
dayjs.extend(timezone);
|
|
6426
6685
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
6427
6686
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
6428
|
-
const { timezone, insideDialog } = useSchemaContext();
|
|
6687
|
+
const { timezone, insideDialog, timePickerLabels } = useSchemaContext();
|
|
6429
6688
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
|
|
6430
6689
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6431
6690
|
const colLabel = `${prefix}${column}`;
|
|
6432
|
-
const formI18n = useFormI18n
|
|
6691
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6433
6692
|
const [open, setOpen] = useState(false);
|
|
6434
6693
|
const value = watch(colLabel);
|
|
6435
6694
|
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
@@ -6487,7 +6746,7 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
6487
6746
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6488
6747
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], 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: () => {
|
|
6489
6748
|
setOpen(true);
|
|
6490
|
-
}, justifyContent: 'start', children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), insideDialog ? (jsx(Popover.Positioner, { children: jsx(Popover.Content, { maxH: "70vh", overflowY: "auto", children: jsx(Popover.Body, { overflow: "visible", children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange }) }) }) })) : (jsx(Portal, { children: 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 }) }) }) }) }))] }) }));
|
|
6749
|
+
}, justifyContent: 'start', children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), insideDialog ? (jsx(Popover.Positioner, { children: jsx(Popover.Content, { maxH: "70vh", overflowY: "auto", children: jsx(Popover.Body, { overflow: "visible", children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, labels: timePickerLabels }) }) }) })) : (jsx(Portal, { children: 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, labels: timePickerLabels }) }) }) }) }))] }) }));
|
|
6491
6750
|
};
|
|
6492
6751
|
|
|
6493
6752
|
dayjs.extend(utc);
|
|
@@ -6621,7 +6880,10 @@ dayjs.extend(utc);
|
|
|
6621
6880
|
dayjs.extend(timezone);
|
|
6622
6881
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
|
|
6623
6882
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6624
|
-
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true,
|
|
6883
|
+
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6884
|
+
placeholder: 'HH:mm:ss',
|
|
6885
|
+
emptyMessage: 'No time found',
|
|
6886
|
+
}, }) {
|
|
6625
6887
|
// Generate time options (every 15 minutes, seconds always 0)
|
|
6626
6888
|
const timeOptions = useMemo(() => {
|
|
6627
6889
|
const options = [];
|
|
@@ -6884,7 +7146,7 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6884
7146
|
e.currentTarget?.blur();
|
|
6885
7147
|
}
|
|
6886
7148
|
};
|
|
6887
|
-
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder:
|
|
7149
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder: labels.placeholder, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsx(Combobox.IndicatorGroup, { children: jsx(Combobox.Trigger, {}) })] }), jsx(Portal, { disabled: !portalled, children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [jsx(Combobox.Empty, { children: labels.emptyMessage }), collection.items.map((item) => (jsxs(Combobox.Item, { item: item, children: [jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsx(Text, { flex: 1, children: item.label }), item.durationText && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: item.durationText }) }))] }), jsx(Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: durationDiff }) })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(Icon, { children: jsx(MdCancel, {}) }) })] }) }));
|
|
6888
7150
|
}
|
|
6889
7151
|
|
|
6890
7152
|
dayjs.extend(utc);
|
|
@@ -6907,7 +7169,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6907
7169
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
6908
7170
|
backButtonLabel: 'Back',
|
|
6909
7171
|
forwardButtonLabel: 'Next',
|
|
6910
|
-
}, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
7172
|
+
}, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
6911
7173
|
console.log('[DateTimePicker] Component initialized with props:', {
|
|
6912
7174
|
value,
|
|
6913
7175
|
format,
|
|
@@ -7353,7 +7615,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7353
7615
|
const dateObj = dayjs.tz(selectedDate, timezone);
|
|
7354
7616
|
return dateObj.isValid() ? dateObj.format('Z') : null;
|
|
7355
7617
|
}, [selectedDate, timezone]);
|
|
7356
|
-
return (jsxs(Flex, { direction: "column", gap: 4,
|
|
7618
|
+
return (jsxs(Flex, { direction: "column", gap: 4, children: [jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
|
|
7357
7619
|
if (date) {
|
|
7358
7620
|
handleDateChange(date);
|
|
7359
7621
|
}
|
|
@@ -7361,15 +7623,15 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7361
7623
|
setSelectedDate('');
|
|
7362
7624
|
onChange?.(undefined);
|
|
7363
7625
|
}
|
|
7364
|
-
}, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: showSeconds ? second : null, setSecond: showSeconds ? setSecond : () => { }, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled })) : (jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), displayText && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
|
|
7626
|
+
}, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: showSeconds ? second : null, setSecond: showSeconds ? setSecond : () => { }, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled, labels: timePickerLabels })) : (jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled, labels: timePickerLabels })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), displayText && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
|
|
7365
7627
|
}
|
|
7366
7628
|
|
|
7367
7629
|
dayjs.extend(utc);
|
|
7368
7630
|
dayjs.extend(timezone);
|
|
7369
7631
|
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
7370
7632
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
7371
|
-
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
7372
|
-
const formI18n = useFormI18n
|
|
7633
|
+
const { timezone, dateTimePickerLabels, timePickerLabels, insideDialog } = useSchemaContext();
|
|
7634
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7373
7635
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
|
|
7374
7636
|
// with timezone
|
|
7375
7637
|
dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
|
|
@@ -7382,74 +7644,30 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7382
7644
|
: '';
|
|
7383
7645
|
const dateTimePickerLabelsConfig = {
|
|
7384
7646
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
formI18n.translate.t(`common.month_5`, {
|
|
7398
|
-
defaultValue: 'May',
|
|
7399
|
-
}),
|
|
7400
|
-
formI18n.translate.t(`common.month_6`, {
|
|
7401
|
-
defaultValue: 'June',
|
|
7402
|
-
}),
|
|
7403
|
-
formI18n.translate.t(`common.month_7`, {
|
|
7404
|
-
defaultValue: 'July',
|
|
7405
|
-
}),
|
|
7406
|
-
formI18n.translate.t(`common.month_8`, {
|
|
7407
|
-
defaultValue: 'August',
|
|
7408
|
-
}),
|
|
7409
|
-
formI18n.translate.t(`common.month_9`, {
|
|
7410
|
-
defaultValue: 'September',
|
|
7411
|
-
}),
|
|
7412
|
-
formI18n.translate.t(`common.month_10`, {
|
|
7413
|
-
defaultValue: 'October',
|
|
7414
|
-
}),
|
|
7415
|
-
formI18n.translate.t(`common.month_11`, {
|
|
7416
|
-
defaultValue: 'November',
|
|
7417
|
-
}),
|
|
7418
|
-
formI18n.translate.t(`common.month_12`, {
|
|
7419
|
-
defaultValue: 'December',
|
|
7420
|
-
}),
|
|
7647
|
+
'January',
|
|
7648
|
+
'February',
|
|
7649
|
+
'March',
|
|
7650
|
+
'April',
|
|
7651
|
+
'May',
|
|
7652
|
+
'June',
|
|
7653
|
+
'July',
|
|
7654
|
+
'August',
|
|
7655
|
+
'September',
|
|
7656
|
+
'October',
|
|
7657
|
+
'November',
|
|
7658
|
+
'December',
|
|
7421
7659
|
],
|
|
7422
7660
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
defaultValue: 'Tue',
|
|
7431
|
-
}),
|
|
7432
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
7433
|
-
defaultValue: 'Wed',
|
|
7434
|
-
}),
|
|
7435
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
7436
|
-
defaultValue: 'Thu',
|
|
7437
|
-
}),
|
|
7438
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
7439
|
-
defaultValue: 'Fri',
|
|
7440
|
-
}),
|
|
7441
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
7442
|
-
defaultValue: 'Sat',
|
|
7443
|
-
}),
|
|
7661
|
+
'Sun',
|
|
7662
|
+
'Mon',
|
|
7663
|
+
'Tue',
|
|
7664
|
+
'Wed',
|
|
7665
|
+
'Thu',
|
|
7666
|
+
'Fri',
|
|
7667
|
+
'Sat',
|
|
7444
7668
|
],
|
|
7445
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
7446
|
-
|
|
7447
|
-
defaultValue: 'Back',
|
|
7448
|
-
}),
|
|
7449
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
7450
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
7451
|
-
defaultValue: 'Forward',
|
|
7452
|
-
}),
|
|
7669
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
7670
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
7453
7671
|
};
|
|
7454
7672
|
const dateTimePickerContent = (jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
7455
7673
|
if (!date || date === null || date === undefined) {
|
|
@@ -7463,7 +7681,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7463
7681
|
else {
|
|
7464
7682
|
setValue(colLabel, undefined);
|
|
7465
7683
|
}
|
|
7466
|
-
}, timezone: timezone, labels: dateTimePickerLabelsConfig }));
|
|
7684
|
+
}, timezone: timezone, labels: dateTimePickerLabelsConfig, timePickerLabels: timePickerLabels }));
|
|
7467
7685
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7468
7686
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, autoFocus: false, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
7469
7687
|
setOpen(true);
|
|
@@ -7482,7 +7700,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7482
7700
|
}
|
|
7483
7701
|
if (variant === 'id-picker') {
|
|
7484
7702
|
idPickerSanityCheck(column, foreign_key);
|
|
7485
|
-
return jsx(
|
|
7703
|
+
return jsx(IdPickerSingle, { schema: colSchema, prefix, column });
|
|
7486
7704
|
}
|
|
7487
7705
|
if (format === 'date') {
|
|
7488
7706
|
return jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
@@ -7516,7 +7734,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7516
7734
|
if (type === 'array') {
|
|
7517
7735
|
if (variant === 'id-picker') {
|
|
7518
7736
|
idPickerSanityCheck(column, foreign_key);
|
|
7519
|
-
return
|
|
7737
|
+
return jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
|
|
7520
7738
|
}
|
|
7521
7739
|
if (variant === 'tag-picker') {
|
|
7522
7740
|
return jsx(TagPicker, { schema: colSchema, prefix, column });
|
|
@@ -7568,7 +7786,7 @@ const ArrayViewer = ({ schema, column, prefix }) => {
|
|
|
7568
7786
|
const { gridColumn = 'span 12', gridRow = 'span 1', required, items, } = schema;
|
|
7569
7787
|
const colLabel = `${prefix}${column}`;
|
|
7570
7788
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7571
|
-
const formI18n = useFormI18n
|
|
7789
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7572
7790
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7573
7791
|
const values = watch(colLabel) ?? [];
|
|
7574
7792
|
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: '1/span12', children: [formI18n.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: {
|
|
@@ -7586,7 +7804,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
7586
7804
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7587
7805
|
const colLabel = `${prefix}${column}`;
|
|
7588
7806
|
const value = watch(colLabel);
|
|
7589
|
-
const formI18n = useFormI18n
|
|
7807
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7590
7808
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7591
7809
|
gridRow, children: [jsx(Text, { children: value ? formI18n.t('true') : formI18n.t('false') }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
7592
7810
|
};
|
|
@@ -7610,7 +7828,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7610
7828
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7611
7829
|
const colLabel = `${prefix}${column}`;
|
|
7612
7830
|
const selectedDate = watch(colLabel);
|
|
7613
|
-
const formI18n = useFormI18n
|
|
7831
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7614
7832
|
const displayDate = dayjs(selectedDate)
|
|
7615
7833
|
.tz(timezone)
|
|
7616
7834
|
.format(displayDateFormat);
|
|
@@ -7620,7 +7838,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7620
7838
|
|
|
7621
7839
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
7622
7840
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7623
|
-
const formI18n = useFormI18n
|
|
7841
|
+
const formI18n = useFormI18n(column, prefix);
|
|
7624
7842
|
const { required } = schema;
|
|
7625
7843
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7626
7844
|
const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
|
|
@@ -7644,7 +7862,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7644
7862
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
|
|
7645
7863
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7646
7864
|
const currentFiles = (watch(column) ?? []);
|
|
7647
|
-
const formI18n = useFormI18n
|
|
7865
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7648
7866
|
return (jsx(Field, { label: formI18n.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) => {
|
|
7649
7867
|
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));
|
|
7650
7868
|
}) }) }));
|
|
@@ -7652,7 +7870,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7652
7870
|
|
|
7653
7871
|
const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
7654
7872
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7655
|
-
const { idMap,
|
|
7873
|
+
const { idMap, idPickerLabels, formButtonLabels } = useSchemaContext();
|
|
7656
7874
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
7657
7875
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7658
7876
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
@@ -7676,12 +7894,12 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
7676
7894
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: 'wrap', gap: 1, children: watchIds.map((id) => {
|
|
7677
7895
|
const item = idMap[id];
|
|
7678
7896
|
if (item === undefined) {
|
|
7679
|
-
return (jsx(Text, { children:
|
|
7897
|
+
return (jsx(Text, { children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
7680
7898
|
}
|
|
7681
7899
|
return (jsx(Tag, { closable: true, children: renderDisplay
|
|
7682
7900
|
? renderDisplay(item)
|
|
7683
7901
|
: defaultRenderDisplay(item) }, id));
|
|
7684
|
-
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children:
|
|
7902
|
+
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children: formButtonLabels?.fieldRequired ?? formI18n.required() }))] }));
|
|
7685
7903
|
};
|
|
7686
7904
|
|
|
7687
7905
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
@@ -7690,7 +7908,7 @@ const NumberViewer = ({ schema, column, prefix, }) => {
|
|
|
7690
7908
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7691
7909
|
const colLabel = `${prefix}${column}`;
|
|
7692
7910
|
const value = watch(colLabel);
|
|
7693
|
-
const formI18n = useFormI18n
|
|
7911
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7694
7912
|
// Format the value for display if formatOptions are provided
|
|
7695
7913
|
const formatValue = (val) => {
|
|
7696
7914
|
if (val === undefined || val === null || val === '')
|
|
@@ -7716,7 +7934,7 @@ const ObjectViewer = ({ schema, column, prefix }) => {
|
|
|
7716
7934
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
7717
7935
|
const colLabel = `${prefix}${column}`;
|
|
7718
7936
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7719
|
-
const formI18n = useFormI18n
|
|
7937
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7720
7938
|
const { formState: { errors }, } = useFormContext();
|
|
7721
7939
|
if (properties === undefined) {
|
|
7722
7940
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -7738,7 +7956,7 @@ const RecordViewer = ({ column, schema, prefix }) => {
|
|
|
7738
7956
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
7739
7957
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7740
7958
|
const entries = Object.entries(getValues(column) ?? {});
|
|
7741
|
-
const formI18n = useFormI18n
|
|
7959
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7742
7960
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn, gridRow, children: [entries.length === 0 ? (jsx(Text, { color: "gray.500", children: "No entries" })) : (jsx(Grid, { templateColumns: '1fr 1fr', gap: 2, children: entries.map(([key, value]) => {
|
|
7743
7961
|
return (jsxs(Grid, { templateColumns: '1fr 1fr', gap: 2, children: [jsxs(Text, { fontWeight: "medium", children: [key, ":"] }), jsx(Text, { children: String(value ?? '') })] }, key));
|
|
7744
7962
|
}) })), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
@@ -7750,7 +7968,7 @@ const StringViewer = ({ column, schema, prefix, }) => {
|
|
|
7750
7968
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7751
7969
|
const colLabel = `${prefix}${column}`;
|
|
7752
7970
|
const value = watch(colLabel);
|
|
7753
|
-
const formI18n = useFormI18n
|
|
7971
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7754
7972
|
return (jsx(Fragment, { children: jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', children: [jsx(Text, { children: value }), errors[colLabel] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }) }));
|
|
7755
7973
|
};
|
|
7756
7974
|
|
|
@@ -7845,7 +8063,7 @@ const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
|
7845
8063
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7846
8064
|
const colLabel = `${prefix}${column}`;
|
|
7847
8065
|
const value = watch(colLabel);
|
|
7848
|
-
const formI18n = useFormI18n
|
|
8066
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7849
8067
|
return (jsx(Fragment, { children: jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Text, { whiteSpace: "pre-wrap", children: value }), ' ', errors[colLabel] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }) }));
|
|
7850
8068
|
};
|
|
7851
8069
|
|
|
@@ -7856,7 +8074,7 @@ const TimeViewer = ({ column, schema, prefix }) => {
|
|
|
7856
8074
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7857
8075
|
const colLabel = `${prefix}${column}`;
|
|
7858
8076
|
const selectedDate = watch(colLabel);
|
|
7859
|
-
const formI18n = useFormI18n
|
|
8077
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7860
8078
|
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
7861
8079
|
.tz(timezone)
|
|
7862
8080
|
.isValid()
|
|
@@ -7873,7 +8091,7 @@ const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
|
7873
8091
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7874
8092
|
const colLabel = `${prefix}${column}`;
|
|
7875
8093
|
const selectedDate = watch(colLabel);
|
|
7876
|
-
const formI18n = useFormI18n
|
|
8094
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7877
8095
|
const displayDate = dayjs(selectedDate)
|
|
7878
8096
|
.tz(timezone)
|
|
7879
8097
|
.format(displayDateFormat);
|
|
@@ -7967,7 +8185,7 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
7967
8185
|
};
|
|
7968
8186
|
|
|
7969
8187
|
const SubmitButton = () => {
|
|
7970
|
-
const {
|
|
8188
|
+
const { setValidatedData, setIsError, setIsConfirming, requireConfirmation, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
7971
8189
|
const methods = useFormContext();
|
|
7972
8190
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7973
8191
|
const onValid = (data) => {
|
|
@@ -7996,11 +8214,11 @@ const SubmitButton = () => {
|
|
|
7996
8214
|
};
|
|
7997
8215
|
return (jsx(Button$1, { onClick: () => {
|
|
7998
8216
|
methods.handleSubmit(onValid)();
|
|
7999
|
-
}, formNoValidate: true, children: formButtonLabels?.submit ??
|
|
8217
|
+
}, formNoValidate: true, children: formButtonLabels?.submit ?? 'Submit' }));
|
|
8000
8218
|
};
|
|
8001
8219
|
|
|
8002
8220
|
const FormBody = () => {
|
|
8003
|
-
const { schema, order, ignore, include,
|
|
8221
|
+
const { schema, order, ignore, include, isError, isSubmiting, isConfirming, setIsConfirming, validatedData, error, customErrorRenderer, displayConfig, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
8004
8222
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
8005
8223
|
const methods = useFormContext();
|
|
8006
8224
|
const { properties } = schema;
|
|
@@ -8017,21 +8235,6 @@ const FormBody = () => {
|
|
|
8017
8235
|
ignore,
|
|
8018
8236
|
include,
|
|
8019
8237
|
});
|
|
8020
|
-
if (isSuccess) {
|
|
8021
|
-
const resetHandler = async () => {
|
|
8022
|
-
setIsError(false);
|
|
8023
|
-
setIsSubmiting(false);
|
|
8024
|
-
setIsSuccess(false);
|
|
8025
|
-
setIsConfirming(false);
|
|
8026
|
-
setValidatedData(undefined);
|
|
8027
|
-
const data = await getUpdatedData();
|
|
8028
|
-
methods.reset(data);
|
|
8029
|
-
};
|
|
8030
|
-
if (customSuccessRenderer) {
|
|
8031
|
-
return customSuccessRenderer(resetHandler);
|
|
8032
|
-
}
|
|
8033
|
-
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: resetHandler, formNoValidate: true, children: formButtonLabels?.submitAgain ?? translate.t('submit_again') }) })] }));
|
|
8034
|
-
}
|
|
8035
8238
|
if (isConfirming) {
|
|
8036
8239
|
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) => {
|
|
8037
8240
|
return (jsx(ColumnViewer
|
|
@@ -8041,9 +8244,9 @@ const FormBody = () => {
|
|
|
8041
8244
|
properties: properties, prefix: ``, column }, `form-viewer-${column}`));
|
|
8042
8245
|
}) }), jsxs(Flex, { justifyContent: 'end', gap: '2', children: [jsx(Button$1, { onClick: () => {
|
|
8043
8246
|
setIsConfirming(false);
|
|
8044
|
-
}, variant: 'subtle', children: formButtonLabels?.cancel ??
|
|
8247
|
+
}, variant: 'subtle', children: formButtonLabels?.cancel ?? 'Cancel' }), jsx(Button$1, { onClick: () => {
|
|
8045
8248
|
onFormSubmit(validatedData);
|
|
8046
|
-
}, children: formButtonLabels?.confirm ??
|
|
8249
|
+
}, children: formButtonLabels?.confirm ?? 'Confirm' })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8047
8250
|
}
|
|
8048
8251
|
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
|
|
8049
8252
|
return (jsx(ColumnRenderer
|
|
@@ -8053,12 +8256,12 @@ const FormBody = () => {
|
|
|
8053
8256
|
properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
|
|
8054
8257
|
}) }), jsxs(Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
|
|
8055
8258
|
methods.reset();
|
|
8056
|
-
}, variant: 'subtle', children: formButtonLabels?.reset ??
|
|
8259
|
+
}, variant: 'subtle', children: formButtonLabels?.reset ?? 'Reset' })), showSubmitButton && jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8057
8260
|
};
|
|
8058
8261
|
|
|
8059
8262
|
const FormTitle = () => {
|
|
8060
|
-
const {
|
|
8061
|
-
return jsx(Heading, { children:
|
|
8263
|
+
const { schema } = useSchemaContext();
|
|
8264
|
+
return jsx(Heading, { children: schema.title ?? 'Form' });
|
|
8062
8265
|
};
|
|
8063
8266
|
|
|
8064
8267
|
const DefaultForm = ({ formConfig, }) => {
|
|
@@ -8066,7 +8269,9 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
8066
8269
|
return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
|
|
8067
8270
|
};
|
|
8068
8271
|
|
|
8069
|
-
const useForm = ({ preLoadedValues, keyPrefix
|
|
8272
|
+
const useForm = ({ preLoadedValues, keyPrefix: _keyPrefix, // Deprecated: kept for backward compatibility
|
|
8273
|
+
namespace: _namespace, // Deprecated: kept for backward compatibility
|
|
8274
|
+
schema, }) => {
|
|
8070
8275
|
const form = useForm$1({
|
|
8071
8276
|
values: preLoadedValues,
|
|
8072
8277
|
resolver: schema ? ajvResolver(schema) : undefined,
|
|
@@ -8074,12 +8279,16 @@ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
|
|
|
8074
8279
|
reValidateMode: 'onBlur',
|
|
8075
8280
|
});
|
|
8076
8281
|
const [idMap, setIdMap] = useState({});
|
|
8077
|
-
|
|
8282
|
+
// Fallback translate object - returns key as-is (no i18n required)
|
|
8283
|
+
const translate = {
|
|
8284
|
+
t: (key) => key,
|
|
8285
|
+
ready: true,
|
|
8286
|
+
};
|
|
8078
8287
|
return {
|
|
8079
8288
|
form,
|
|
8080
8289
|
idMap,
|
|
8081
8290
|
setIdMap,
|
|
8082
|
-
translate,
|
|
8291
|
+
translate, // Components prefer label objects over translate
|
|
8083
8292
|
};
|
|
8084
8293
|
};
|
|
8085
8294
|
|
|
@@ -8407,6 +8616,21 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
|
8407
8616
|
})] }));
|
|
8408
8617
|
};
|
|
8409
8618
|
|
|
8619
|
+
const MobileTableControls = ({ 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 = {}, }) => {
|
|
8620
|
+
const { tableLabel, table } = useDataTableContext();
|
|
8621
|
+
const { hasErrorText } = tableLabel;
|
|
8622
|
+
return (jsxs(Grid, { templateRows: 'auto 1fr auto', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: 2, padding: 2, ...gridProps, children: [jsxs(Stack, { gap: 2, children: [jsxs(Flex, { justifyContent: 'space-between', alignItems: 'center', gap: 2, children: [jsxs(Flex, { gap: 1, alignItems: 'center', children: [showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }), loading && jsx(Spinner, { size: 'sm' }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: 'red.400' }) }))] }), jsxs(Flex, { gap: 1, alignItems: 'center', children: [showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsx(Stack, { gap: 2, children: filterTagsOptions.map((option) => {
|
|
8623
|
+
const { column, options } = option;
|
|
8624
|
+
const tableColumn = table.getColumn(column);
|
|
8625
|
+
return (jsxs(Flex, { flexFlow: 'column', gap: 1, width: '100%', children: [tableColumn?.columnDef.meta?.displayName && (jsx(Text, { fontSize: 'sm', fontWeight: 'medium', children: tableColumn?.columnDef.meta?.displayName })), jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
|
|
8626
|
+
if (tags.length === 0) {
|
|
8627
|
+
return tableColumn?.setFilterValue(undefined);
|
|
8628
|
+
}
|
|
8629
|
+
tableColumn?.setFilterValue(tags);
|
|
8630
|
+
} })] }, column));
|
|
8631
|
+
}) })), showFilterTags && (jsx(Box, { width: '100%', children: jsx(TableFilterTags, {}) }))] }), jsx(Box, { overflow: 'auto', width: '100%', bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, borderRadius: 'md', padding: 1, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Stack, { gap: 2, width: '100%', children: [(showPageSizeControl || showPageCountText) && (jsxs(Flex, { justifyContent: 'space-between', alignItems: 'center', gap: 2, flexWrap: 'wrap', children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && jsx(RowCountText, {})] })), showPagination && (jsx(Flex, { justifyContent: 'center', width: '100%', children: jsx(Pagination, {}) }))] }))] }));
|
|
8632
|
+
};
|
|
8633
|
+
|
|
8410
8634
|
const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
|
|
8411
8635
|
'use no memo';
|
|
8412
8636
|
const { table } = useDataTableContext();
|
|
@@ -8466,7 +8690,68 @@ const TableRowSelectorSkeleton = () => {
|
|
|
8466
8690
|
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsx(Skeleton, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }) }));
|
|
8467
8691
|
};
|
|
8468
8692
|
|
|
8693
|
+
const MobileTableDisplay = ({ showSelector = false, isLoading = false, }) => {
|
|
8694
|
+
const { table, rowSelection, setRowSelection } = useDataTableContext();
|
|
8695
|
+
if (isLoading) {
|
|
8696
|
+
return jsx(MobileTableSkeleton, { showSelector: showSelector });
|
|
8697
|
+
}
|
|
8698
|
+
return (jsx(Stack, { gap: 4, padding: 2, children: table.getRowModel().rows.map((row) => {
|
|
8699
|
+
return (jsx(Card.Root, { width: "100%", children: jsxs(Card.Body, { padding: 4, children: [showSelector && (jsx(Flex, { marginBottom: 3, children: jsx(Checkbox, { checked: isRowSelected(row.id, rowSelection),
|
|
8700
|
+
disabled: !canRowSelect(row),
|
|
8701
|
+
onCheckedChange: createRowToggleHandler(row, rowSelection, setRowSelection) }) })), jsx(Stack, { gap: 3, children: row.getVisibleCells().map((cell) => {
|
|
8702
|
+
const displayName = cell.column.columnDef.meta?.displayName ?? cell.column.id;
|
|
8703
|
+
return (jsxs(Box, { children: [jsx(Text, { fontSize: "sm", fontWeight: "bold", color: { base: 'gray.600', _dark: 'gray.400' }, marginBottom: 1, children: displayName }), jsx(Box, { color: { base: 'gray.900', _dark: 'gray.100' }, fontSize: "sm", children: flexRender(cell.column.columnDef.cell, cell.getContext()) })] }, `mobile-table-cell-${cell.id}`));
|
|
8704
|
+
}) })] }) }, `mobile-table-card-${row.id}`));
|
|
8705
|
+
}) }));
|
|
8706
|
+
};
|
|
8707
|
+
const MobileTableSkeleton = ({ showSelector = false, }) => {
|
|
8708
|
+
const { table } = useDataTableContext();
|
|
8709
|
+
const pageSize = table.getState().pagination.pageSize;
|
|
8710
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
8711
|
+
return (jsx(Stack, { gap: 4, padding: 2, children: Array.from({ length: pageSize }).map((_, rowIndex) => {
|
|
8712
|
+
return (jsx(Card.Root, { width: "100%", children: jsxs(Card.Body, { padding: 4, children: [showSelector && (jsx(Flex, { marginBottom: 3, children: jsx(Box, { width: "20px", height: "20px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "md" }) })), jsx(Stack, { gap: 3, children: visibleColumns.map((column) => {
|
|
8713
|
+
return (jsxs(Box, { children: [jsx(Box, { width: "40%", height: "16px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "sm", marginBottom: 2 }), jsx(Box, { width: "80%", height: "20px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "sm" })] }, `mobile-skeleton-cell-${column.id}`));
|
|
8714
|
+
}) })] }) }, `mobile-skeleton-${rowIndex}`));
|
|
8715
|
+
}) }));
|
|
8716
|
+
};
|
|
8717
|
+
|
|
8718
|
+
/**
|
|
8719
|
+
* Hook to detect if the current window width is mobile (< 768px)
|
|
8720
|
+
* @param breakpoint - The breakpoint in pixels to consider as mobile (default: 768)
|
|
8721
|
+
* @returns boolean indicating if the window is mobile
|
|
8722
|
+
*/
|
|
8723
|
+
const useIsMobile = (breakpoint = 768) => {
|
|
8724
|
+
const [isMobile, setIsMobile] = useState(() => {
|
|
8725
|
+
if (typeof window === 'undefined')
|
|
8726
|
+
return false;
|
|
8727
|
+
return window.innerWidth < breakpoint;
|
|
8728
|
+
});
|
|
8729
|
+
useEffect(() => {
|
|
8730
|
+
if (typeof window === 'undefined')
|
|
8731
|
+
return;
|
|
8732
|
+
const handleResize = () => {
|
|
8733
|
+
setIsMobile(window.innerWidth < breakpoint);
|
|
8734
|
+
};
|
|
8735
|
+
// Set initial value
|
|
8736
|
+
handleResize();
|
|
8737
|
+
// Add event listener
|
|
8738
|
+
window.addEventListener('resize', handleResize);
|
|
8739
|
+
// Cleanup
|
|
8740
|
+
return () => {
|
|
8741
|
+
window.removeEventListener('resize', handleResize);
|
|
8742
|
+
};
|
|
8743
|
+
}, [breakpoint]);
|
|
8744
|
+
return isMobile;
|
|
8745
|
+
};
|
|
8746
|
+
|
|
8469
8747
|
const DefaultTable = ({ showFooter = false, showHeader = true, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = 'greedy', isLoading = false, }) => {
|
|
8748
|
+
const isMobile = useIsMobile();
|
|
8749
|
+
// Early return for mobile display
|
|
8750
|
+
if (isMobile) {
|
|
8751
|
+
return (jsx(MobileTableControls, { ...controlProps, children: jsx(MobileTableDisplay, { showSelector: tableHeaderProps.showSelector ??
|
|
8752
|
+
tableBodyProps.showSelector ??
|
|
8753
|
+
false, isLoading: isLoading }) }));
|
|
8754
|
+
}
|
|
8470
8755
|
const isGreedy = variant === 'greedy';
|
|
8471
8756
|
const canResize = !isGreedy;
|
|
8472
8757
|
const bodyComponent = isLoading ? (jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: canResize })) : (jsx(TableBody, { ...tableBodyProps, canResize: canResize }));
|
|
@@ -8567,6 +8852,290 @@ const DataDisplay = ({ variant = '' }) => {
|
|
|
8567
8852
|
}) }));
|
|
8568
8853
|
};
|
|
8569
8854
|
|
|
8855
|
+
// Helper function to normalize date
|
|
8856
|
+
function normalizeDate(value) {
|
|
8857
|
+
if (!value)
|
|
8858
|
+
return null;
|
|
8859
|
+
if (value instanceof Date)
|
|
8860
|
+
return value;
|
|
8861
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
8862
|
+
const date = dayjs(value).toDate();
|
|
8863
|
+
return isNaN(date.getTime()) ? null : date;
|
|
8864
|
+
}
|
|
8865
|
+
return null;
|
|
8866
|
+
}
|
|
8867
|
+
// Component to conditionally render event title based on available width
|
|
8868
|
+
function ResponsiveEventTitle({ title, placeholder, minWidth, minChars, cellRef, }) {
|
|
8869
|
+
const [truncatedText, setTruncatedText] = useState('');
|
|
8870
|
+
const measureRef = useRef(null);
|
|
8871
|
+
useEffect(() => {
|
|
8872
|
+
const calculateTruncatedText = () => {
|
|
8873
|
+
if (!cellRef.current || !measureRef.current || !title) {
|
|
8874
|
+
setTruncatedText(title || 'Event');
|
|
8875
|
+
return;
|
|
8876
|
+
}
|
|
8877
|
+
const cellWidth = cellRef.current.clientWidth;
|
|
8878
|
+
// Account for padding (approximately 8px on each side)
|
|
8879
|
+
const availableWidth = cellWidth - 16;
|
|
8880
|
+
// If cell is too narrow, calculate how many characters can fit
|
|
8881
|
+
if (availableWidth < minWidth) {
|
|
8882
|
+
// Measure text width using canvas
|
|
8883
|
+
const canvas = document.createElement('canvas');
|
|
8884
|
+
const context = canvas.getContext('2d');
|
|
8885
|
+
if (!context) {
|
|
8886
|
+
setTruncatedText(placeholder);
|
|
8887
|
+
return;
|
|
8888
|
+
}
|
|
8889
|
+
// Get computed font style from the element
|
|
8890
|
+
const computedStyle = window.getComputedStyle(measureRef.current);
|
|
8891
|
+
context.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;
|
|
8892
|
+
const ellipsisWidth = context.measureText('...').width;
|
|
8893
|
+
const maxWidth = availableWidth - ellipsisWidth;
|
|
8894
|
+
// Try to show at least minChars characters before ellipsis
|
|
8895
|
+
let truncated = '';
|
|
8896
|
+
let charCount = 0;
|
|
8897
|
+
// Calculate how many characters can fit
|
|
8898
|
+
for (let i = 0; i < Math.min(title.length, 50); i++) {
|
|
8899
|
+
const testText = title.substring(0, i + 1);
|
|
8900
|
+
const textWidth = context.measureText(testText).width;
|
|
8901
|
+
if (textWidth <= maxWidth) {
|
|
8902
|
+
truncated = testText;
|
|
8903
|
+
charCount = i + 1;
|
|
8904
|
+
}
|
|
8905
|
+
else {
|
|
8906
|
+
break;
|
|
8907
|
+
}
|
|
8908
|
+
}
|
|
8909
|
+
// Ensure we show at least minChars characters if possible
|
|
8910
|
+
if (charCount < minChars && title.length >= minChars) {
|
|
8911
|
+
truncated = title.substring(0, minChars);
|
|
8912
|
+
}
|
|
8913
|
+
else if (charCount === 0 && title.length >= 1) {
|
|
8914
|
+
truncated = title.substring(0, 1);
|
|
8915
|
+
}
|
|
8916
|
+
// Only show ellipsis if we have at least minChars characters
|
|
8917
|
+
if (truncated && truncated.length >= minChars) {
|
|
8918
|
+
setTruncatedText(`${truncated}...`);
|
|
8919
|
+
}
|
|
8920
|
+
else {
|
|
8921
|
+
setTruncatedText(placeholder);
|
|
8922
|
+
}
|
|
8923
|
+
}
|
|
8924
|
+
else {
|
|
8925
|
+
// Full width available, show full title
|
|
8926
|
+
setTruncatedText(title);
|
|
8927
|
+
}
|
|
8928
|
+
};
|
|
8929
|
+
calculateTruncatedText();
|
|
8930
|
+
const resizeObserver = new ResizeObserver(calculateTruncatedText);
|
|
8931
|
+
if (cellRef.current) {
|
|
8932
|
+
resizeObserver.observe(cellRef.current);
|
|
8933
|
+
}
|
|
8934
|
+
// Also check on window resize
|
|
8935
|
+
window.addEventListener('resize', calculateTruncatedText);
|
|
8936
|
+
return () => {
|
|
8937
|
+
resizeObserver.disconnect();
|
|
8938
|
+
window.removeEventListener('resize', calculateTruncatedText);
|
|
8939
|
+
};
|
|
8940
|
+
}, [cellRef, minWidth, title, placeholder]);
|
|
8941
|
+
return (jsxs(Fragment, { children: [jsx("span", { ref: measureRef, style: {
|
|
8942
|
+
visibility: 'hidden',
|
|
8943
|
+
position: 'absolute',
|
|
8944
|
+
whiteSpace: 'nowrap',
|
|
8945
|
+
}, children: title || 'Event' }), truncatedText || title || 'Event'] }));
|
|
8946
|
+
}
|
|
8947
|
+
function CalendarDisplay({ dateColumn, getDate, getEventTitle, getEventColor, renderEvent, firstDayOfWeek = 0, showOutsideDays = true, monthsToDisplay = 1, labels = {
|
|
8948
|
+
monthNamesShort: [
|
|
8949
|
+
'Jan',
|
|
8950
|
+
'Feb',
|
|
8951
|
+
'Mar',
|
|
8952
|
+
'Apr',
|
|
8953
|
+
'May',
|
|
8954
|
+
'Jun',
|
|
8955
|
+
'Jul',
|
|
8956
|
+
'Aug',
|
|
8957
|
+
'Sep',
|
|
8958
|
+
'Oct',
|
|
8959
|
+
'Nov',
|
|
8960
|
+
'Dec',
|
|
8961
|
+
],
|
|
8962
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
8963
|
+
backButtonLabel: 'Back',
|
|
8964
|
+
forwardButtonLabel: 'Next',
|
|
8965
|
+
}, onDateClick, onEventClick, maxEventsPerDay = 3, colorPalette = 'blue', eventPlaceholder = '...', minEventWidth = 80, minCharsBeforeEllipsis = 2, }) {
|
|
8966
|
+
const { data, table } = useDataTableContext();
|
|
8967
|
+
// Map table data to events
|
|
8968
|
+
const events = useMemo(() => {
|
|
8969
|
+
return data
|
|
8970
|
+
.map((row) => {
|
|
8971
|
+
let dateValue;
|
|
8972
|
+
if (getDate) {
|
|
8973
|
+
dateValue = getDate(row);
|
|
8974
|
+
}
|
|
8975
|
+
else {
|
|
8976
|
+
// Try to get date from column
|
|
8977
|
+
const rowData = table
|
|
8978
|
+
.getRowModel()
|
|
8979
|
+
.rows.find((r) => r.original === row);
|
|
8980
|
+
if (rowData) {
|
|
8981
|
+
const cell = rowData.getAllCells().find((c) => {
|
|
8982
|
+
const colId = c.column.id;
|
|
8983
|
+
const accessorKey = c.column.columnDef.accessorKey;
|
|
8984
|
+
return colId === dateColumn || accessorKey === dateColumn;
|
|
8985
|
+
});
|
|
8986
|
+
dateValue = cell?.getValue();
|
|
8987
|
+
}
|
|
8988
|
+
}
|
|
8989
|
+
const date = normalizeDate(dateValue);
|
|
8990
|
+
if (!date)
|
|
8991
|
+
return null;
|
|
8992
|
+
let title;
|
|
8993
|
+
if (getEventTitle) {
|
|
8994
|
+
title = getEventTitle(row);
|
|
8995
|
+
}
|
|
8996
|
+
else {
|
|
8997
|
+
// Use first column's value as title
|
|
8998
|
+
const rowData = table
|
|
8999
|
+
.getRowModel()
|
|
9000
|
+
.rows.find((r) => r.original === row);
|
|
9001
|
+
if (rowData) {
|
|
9002
|
+
const firstCell = rowData.getAllCells()[0];
|
|
9003
|
+
title = String(firstCell?.getValue() ?? '');
|
|
9004
|
+
}
|
|
9005
|
+
}
|
|
9006
|
+
const color = getEventColor?.(row);
|
|
9007
|
+
return {
|
|
9008
|
+
data: row,
|
|
9009
|
+
date,
|
|
9010
|
+
title,
|
|
9011
|
+
color,
|
|
9012
|
+
};
|
|
9013
|
+
})
|
|
9014
|
+
.filter((event) => event !== null);
|
|
9015
|
+
}, [data, table, dateColumn, getDate, getEventTitle, getEventColor]);
|
|
9016
|
+
// Group events by date
|
|
9017
|
+
const eventsByDate = useMemo(() => {
|
|
9018
|
+
const map = new Map();
|
|
9019
|
+
events.forEach((event) => {
|
|
9020
|
+
const dateKey = `${event.date.getFullYear()}-${event.date.getMonth()}-${event.date.getDate()}`;
|
|
9021
|
+
if (!map.has(dateKey)) {
|
|
9022
|
+
map.set(dateKey, []);
|
|
9023
|
+
}
|
|
9024
|
+
map.get(dateKey).push(event);
|
|
9025
|
+
});
|
|
9026
|
+
return map;
|
|
9027
|
+
}, [events]);
|
|
9028
|
+
// Get events for a specific date
|
|
9029
|
+
const getEventsForDate = useCallback((date) => {
|
|
9030
|
+
const dateKey = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
|
9031
|
+
return eventsByDate.get(dateKey) ?? [];
|
|
9032
|
+
}, [eventsByDate]);
|
|
9033
|
+
const calendarData = useCalendar({
|
|
9034
|
+
firstDayOfWeek,
|
|
9035
|
+
showOutsideDays,
|
|
9036
|
+
monthsToDisplay,
|
|
9037
|
+
});
|
|
9038
|
+
const getDateProps = useCallback((props) => {
|
|
9039
|
+
const dateEvents = getEventsForDate(props.dateObj.date);
|
|
9040
|
+
const baseProps = calendarData.getDateProps({ dateObj: props.dateObj });
|
|
9041
|
+
return {
|
|
9042
|
+
...baseProps,
|
|
9043
|
+
onClick: () => {
|
|
9044
|
+
baseProps.onClick?.();
|
|
9045
|
+
if (onDateClick) {
|
|
9046
|
+
onDateClick(props.dateObj.date, dateEvents);
|
|
9047
|
+
}
|
|
9048
|
+
},
|
|
9049
|
+
};
|
|
9050
|
+
}, [calendarData, getEventsForDate, onDateClick]);
|
|
9051
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
9052
|
+
if (!calendarData.calendars.length) {
|
|
9053
|
+
return null;
|
|
9054
|
+
}
|
|
9055
|
+
return (jsxs(VStack, { gap: 4, width: "100%", children: [jsxs(HStack, { gap: 2, justifyContent: "center", children: [jsx(Button$1, { variant: "ghost", ...calendarData.getBackProps({
|
|
9056
|
+
calendars: calendarData.calendars,
|
|
9057
|
+
offset: 12,
|
|
9058
|
+
}), children: '<<' }), jsx(Button$1, { variant: "ghost", ...calendarData.getBackProps({ calendars: calendarData.calendars }), children: backButtonLabel }), jsx(Button$1, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9059
|
+
calendars: calendarData.calendars,
|
|
9060
|
+
}), children: forwardButtonLabel }), jsx(Button$1, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9061
|
+
calendars: calendarData.calendars,
|
|
9062
|
+
offset: 12,
|
|
9063
|
+
}), children: '>>' })] }), jsx(Grid, { templateColumns: {
|
|
9064
|
+
base: '1fr',
|
|
9065
|
+
md: monthsToDisplay >= 2 ? 'repeat(2, 1fr)' : '1fr',
|
|
9066
|
+
lg: monthsToDisplay >= 3
|
|
9067
|
+
? 'repeat(3, 1fr)'
|
|
9068
|
+
: monthsToDisplay === 2
|
|
9069
|
+
? 'repeat(2, 1fr)'
|
|
9070
|
+
: '1fr',
|
|
9071
|
+
xl: `repeat(${Math.min(monthsToDisplay, 4)}, 1fr)`,
|
|
9072
|
+
}, gap: { base: 4, md: 6 }, width: "100%", justifyContent: "center", children: calendarData.calendars.map((calendar) => (jsxs(VStack, { gap: 2, alignItems: "stretch", children: [jsxs(Text, { textAlign: "center", fontSize: { base: 'md', md: 'lg' }, fontWeight: "semibold", children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsx(Grid, { templateColumns: "repeat(7, 1fr)", gap: { base: 0.5, md: 1 }, children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
9073
|
+
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
9074
|
+
return (jsx(Text, { textAlign: "center", fontSize: { base: 'xs', md: 'sm' }, fontWeight: "medium", color: { base: 'gray.600', _dark: 'gray.400' }, children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
9075
|
+
}) }), jsx(Grid, { templateColumns: "repeat(7, 1fr)", gap: { base: 0.5, md: 1 }, children: calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
9076
|
+
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
9077
|
+
if (!dateObj) {
|
|
9078
|
+
return jsx(Box, {}, key);
|
|
9079
|
+
}
|
|
9080
|
+
const { date, today, isCurrentMonth } = dateObj;
|
|
9081
|
+
const dateEvents = getEventsForDate(date);
|
|
9082
|
+
const cellRef = useRef(null);
|
|
9083
|
+
return (jsxs(VStack, { ref: cellRef, gap: { base: 0.25, md: 0.5 }, alignItems: "stretch", minHeight: { base: '60px', md: '80px', lg: '100px' }, borderWidth: "1px", borderColor: {
|
|
9084
|
+
base: today ? `${colorPalette}.300` : 'gray.200',
|
|
9085
|
+
_dark: today ? `${colorPalette}.700` : 'gray.700',
|
|
9086
|
+
}, borderRadius: { base: 'sm', md: 'md' }, padding: { base: 0.5, md: 1 }, bgColor: {
|
|
9087
|
+
base: today ? `${colorPalette}.50` : 'white',
|
|
9088
|
+
_dark: today ? `${colorPalette}.950` : 'gray.900',
|
|
9089
|
+
}, opacity: isCurrentMonth ? 1 : 0.5, ...getDateProps({ dateObj }), cursor: onDateClick ? 'pointer' : 'default', _hover: onDateClick
|
|
9090
|
+
? {
|
|
9091
|
+
bgColor: {
|
|
9092
|
+
base: `${colorPalette}.100`,
|
|
9093
|
+
_dark: `${colorPalette}.900`,
|
|
9094
|
+
},
|
|
9095
|
+
}
|
|
9096
|
+
: {}, children: [jsx(Text, { fontSize: { base: 'xs', md: 'sm' }, fontWeight: today ? 'bold' : 'normal', color: {
|
|
9097
|
+
base: today ? `${colorPalette}.700` : 'gray.700',
|
|
9098
|
+
_dark: today ? `${colorPalette}.300` : 'gray.300',
|
|
9099
|
+
}, textAlign: "right", paddingRight: { base: 0.5, md: 1 }, children: date.getDate() }), jsxs(VStack, { gap: { base: 0.25, md: 0.5 }, alignItems: "stretch", flex: 1, overflow: "hidden", children: [dateEvents
|
|
9100
|
+
.slice(0, maxEventsPerDay)
|
|
9101
|
+
.map((event, eventIndex) => {
|
|
9102
|
+
const eventContent = renderEvent ? (renderEvent(event)) : (jsx(Box, { fontSize: { base: '2xs', md: 'xs' }, paddingX: { base: 0.5, md: 1 }, paddingY: { base: 0.25, md: 0.5 }, borderRadius: { base: 'xs', md: 'sm' }, bgColor: {
|
|
9103
|
+
base: event.color
|
|
9104
|
+
? `${event.color}.100`
|
|
9105
|
+
: `${colorPalette}.100`,
|
|
9106
|
+
_dark: event.color
|
|
9107
|
+
? `${event.color}.900`
|
|
9108
|
+
: `${colorPalette}.900`,
|
|
9109
|
+
}, color: {
|
|
9110
|
+
base: event.color
|
|
9111
|
+
? `${event.color}.800`
|
|
9112
|
+
: `${colorPalette}.800`,
|
|
9113
|
+
_dark: event.color
|
|
9114
|
+
? `${event.color}.200`
|
|
9115
|
+
: `${colorPalette}.200`,
|
|
9116
|
+
}, onClick: (e) => {
|
|
9117
|
+
e.stopPropagation();
|
|
9118
|
+
if (onEventClick) {
|
|
9119
|
+
onEventClick(event);
|
|
9120
|
+
}
|
|
9121
|
+
}, cursor: onEventClick ? 'pointer' : 'default', _hover: onEventClick
|
|
9122
|
+
? {
|
|
9123
|
+
opacity: 0.8,
|
|
9124
|
+
}
|
|
9125
|
+
: {}, children: jsx(ResponsiveEventTitle, { title: event.title, placeholder: eventPlaceholder, minWidth: minEventWidth, minChars: minCharsBeforeEllipsis, cellRef: cellRef }) }, eventIndex));
|
|
9126
|
+
return (jsx(Box, { onClick: (e) => e.stopPropagation(), children: eventContent }, eventIndex));
|
|
9127
|
+
}), dateEvents.length > maxEventsPerDay && (jsxs(Text, { fontSize: "xs", color: {
|
|
9128
|
+
base: `${colorPalette}.600`,
|
|
9129
|
+
_dark: `${colorPalette}.400`,
|
|
9130
|
+
}, paddingX: 1, onClick: (e) => {
|
|
9131
|
+
e.stopPropagation();
|
|
9132
|
+
if (onDateClick) {
|
|
9133
|
+
onDateClick(date, dateEvents);
|
|
9134
|
+
}
|
|
9135
|
+
}, cursor: onDateClick ? 'pointer' : 'default', children: ["+", dateEvents.length - maxEventsPerDay, " more"] }))] })] }, key));
|
|
9136
|
+
})) })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
9137
|
+
}
|
|
9138
|
+
|
|
8570
9139
|
// Reference: https://tanstack.com/table/latest/docs/framework/react/examples/custom-features
|
|
8571
9140
|
// TypeScript setup for our new feature with all of the same type-safety as stock TanStack Table features
|
|
8572
9141
|
// end of TS setup!
|
|
@@ -8667,7 +9236,7 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
|
|
|
8667
9236
|
*
|
|
8668
9237
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8669
9238
|
*/
|
|
8670
|
-
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,
|
|
9239
|
+
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, children, tableLabel = {
|
|
8671
9240
|
view: 'View',
|
|
8672
9241
|
edit: 'Edit',
|
|
8673
9242
|
filterButtonText: 'Filter',
|
|
@@ -8678,7 +9247,7 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8678
9247
|
reloadButtonText: 'Reload',
|
|
8679
9248
|
resetSelection: 'Reset Selection',
|
|
8680
9249
|
resetSorting: 'Reset Sorting',
|
|
8681
|
-
rowCountText: '
|
|
9250
|
+
rowCountText: '',
|
|
8682
9251
|
hasErrorText: 'Has Error',
|
|
8683
9252
|
globalFilterPlaceholder: 'Search',
|
|
8684
9253
|
trueLabel: 'True',
|
|
@@ -8735,7 +9304,6 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8735
9304
|
globalFilter,
|
|
8736
9305
|
setGlobalFilter,
|
|
8737
9306
|
type: 'client',
|
|
8738
|
-
translate,
|
|
8739
9307
|
columns: columns,
|
|
8740
9308
|
sorting,
|
|
8741
9309
|
setSorting,
|
|
@@ -8767,22 +9335,22 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8767
9335
|
*
|
|
8768
9336
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8769
9337
|
*/
|
|
8770
|
-
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,
|
|
8771
|
-
view:
|
|
8772
|
-
edit:
|
|
8773
|
-
filterButtonText:
|
|
8774
|
-
filterTitle:
|
|
8775
|
-
filterReset:
|
|
8776
|
-
filterClose:
|
|
8777
|
-
reloadTooltip:
|
|
8778
|
-
reloadButtonText:
|
|
8779
|
-
resetSelection:
|
|
8780
|
-
resetSorting:
|
|
8781
|
-
rowCountText:
|
|
8782
|
-
hasErrorText:
|
|
8783
|
-
globalFilterPlaceholder:
|
|
8784
|
-
trueLabel:
|
|
8785
|
-
falseLabel:
|
|
9338
|
+
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, children, tableLabel = {
|
|
9339
|
+
view: 'View',
|
|
9340
|
+
edit: 'Edit',
|
|
9341
|
+
filterButtonText: 'Filter',
|
|
9342
|
+
filterTitle: 'Filter',
|
|
9343
|
+
filterReset: 'Reset',
|
|
9344
|
+
filterClose: 'Close',
|
|
9345
|
+
reloadTooltip: 'Reload',
|
|
9346
|
+
reloadButtonText: 'Reload',
|
|
9347
|
+
resetSelection: 'Reset Selection',
|
|
9348
|
+
resetSorting: 'Reset Sorting',
|
|
9349
|
+
rowCountText: '',
|
|
9350
|
+
hasErrorText: 'Has Error',
|
|
9351
|
+
globalFilterPlaceholder: 'Search',
|
|
9352
|
+
trueLabel: 'True',
|
|
9353
|
+
falseLabel: 'False',
|
|
8786
9354
|
}, }) {
|
|
8787
9355
|
const table = useReactTable({
|
|
8788
9356
|
_features: [DensityFeature],
|
|
@@ -8792,7 +9360,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8792
9360
|
getCoreRowModel: getCoreRowModel(),
|
|
8793
9361
|
manualPagination: true,
|
|
8794
9362
|
manualSorting: true,
|
|
8795
|
-
columnResizeMode:
|
|
9363
|
+
columnResizeMode: 'onChange',
|
|
8796
9364
|
defaultColumn: {
|
|
8797
9365
|
size: 150, //starting column size
|
|
8798
9366
|
minSize: 10, //enforced during column resizing
|
|
@@ -8835,8 +9403,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8835
9403
|
table: table,
|
|
8836
9404
|
globalFilter,
|
|
8837
9405
|
setGlobalFilter,
|
|
8838
|
-
type:
|
|
8839
|
-
translate,
|
|
9406
|
+
type: 'server',
|
|
8840
9407
|
columns: columns,
|
|
8841
9408
|
sorting,
|
|
8842
9409
|
setSorting,
|
|
@@ -8854,7 +9421,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8854
9421
|
setColumnVisibility,
|
|
8855
9422
|
data: query.data?.data ?? [],
|
|
8856
9423
|
tableLabel,
|
|
8857
|
-
}, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
9424
|
+
}, children: jsx(DataTableServerContext.Provider, { value: { url: url ?? '', query }, children: children }) }));
|
|
8858
9425
|
}
|
|
8859
9426
|
|
|
8860
|
-
export { CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|
|
9427
|
+
export { CalendarDisplay, CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|