@bsol-oss/react-datatable5 12.0.0-beta.80 → 12.0.0-beta.82
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/dist/index.d.ts +387 -348
- package/dist/index.js +1286 -966
- package/dist/index.mjs +1289 -970
- package/dist/types/components/DataTable/display/Table.d.ts +2 -1
- package/dist/types/components/DataTable/hooks/useResponsiveColumnVisibility.d.ts +13 -0
- package/dist/types/components/Form/components/MediaLibraryBrowser.d.ts +22 -0
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +16 -0
- package/dist/types/components/Form/components/fields/FormMediaLibraryBrowser.d.ts +2 -0
- package/dist/types/components/Form/components/fields/StringInputField.d.ts +4 -0
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +6 -0
- package/dist/types/components/Form/components/viewers/SchemaViewer.d.ts +1 -1
- package/dist/types/index.d.ts +65 -57
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1,
|
|
2
|
+
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, 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, Image, Alert, Field as Field$1, Popover, Tabs, NumberInput, Show, RadioCard, CheckboxGroup, Center, Heading, Skeleton } from '@chakra-ui/react';
|
|
3
3
|
import { AiOutlineColumnWidth } from 'react-icons/ai';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import React__default, { createContext, useContext, useState, useEffect, useRef, forwardRef } from 'react';
|
|
6
|
-
import { LuX, LuCheck, LuChevronRight, LuImage, LuFile
|
|
7
|
-
import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel,
|
|
6
|
+
import { LuX, LuCheck, LuChevronRight, LuSearch, LuImage, LuFile } from 'react-icons/lu';
|
|
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';
|
|
@@ -17,13 +17,12 @@ import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
|
17
17
|
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
|
|
18
18
|
import rafSchd from 'raf-schd';
|
|
19
19
|
import invariant from 'tiny-invariant';
|
|
20
|
-
import { HiColorSwatch, HiOutlineInformationCircle } from 'react-icons/hi';
|
|
21
|
-
import { flexRender, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel, createColumnHelper } from '@tanstack/react-table';
|
|
22
|
-
import { rankItem } from '@tanstack/match-sorter-utils';
|
|
23
|
-
import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
|
|
24
|
-
import { useDebounce } from '@uidotdev/usehooks';
|
|
25
20
|
import { useQueryClient, useQuery } from '@tanstack/react-query';
|
|
26
21
|
import { IoReload } from 'react-icons/io5';
|
|
22
|
+
import { useDebounce } from '@uidotdev/usehooks';
|
|
23
|
+
import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
|
|
24
|
+
import { HiColorSwatch, HiOutlineInformationCircle } from 'react-icons/hi';
|
|
25
|
+
import { flexRender, createColumnHelper, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel } from '@tanstack/react-table';
|
|
27
26
|
import { GrAscend, GrDescend } from 'react-icons/gr';
|
|
28
27
|
import { useTranslation } from 'react-i18next';
|
|
29
28
|
import axios from 'axios';
|
|
@@ -34,6 +33,7 @@ import dayjs from 'dayjs';
|
|
|
34
33
|
import utc from 'dayjs/plugin/utc';
|
|
35
34
|
import timezone from 'dayjs/plugin/timezone';
|
|
36
35
|
import { TiDeleteOutline } from 'react-icons/ti';
|
|
36
|
+
import { rankItem } from '@tanstack/match-sorter-utils';
|
|
37
37
|
|
|
38
38
|
const DataTableContext = createContext({
|
|
39
39
|
table: {},
|
|
@@ -2602,13 +2602,12 @@ const ViewDialog = ({ icon = jsx(IoMdEye, {}) }) => {
|
|
|
2602
2602
|
return (jsxs(DialogRoot, { children: [jsx(DialogBackdrop, {}), jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: viewModel.onOpen, children: [icon, " ", view] }) }), jsxs(DialogContent, { children: [jsx(DialogCloseTrigger, {}), jsx(DialogHeader, { children: jsx(DialogTitle, { children: view }) }), jsx(DialogBody, { children: jsx(TableViewer, {}) }), jsx(DialogFooter, {})] })] }));
|
|
2603
2603
|
};
|
|
2604
2604
|
|
|
2605
|
-
const
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
};
|
|
2605
|
+
const Tooltip = React.forwardRef(function Tooltip(props, ref) {
|
|
2606
|
+
const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
|
|
2607
|
+
if (disabled)
|
|
2608
|
+
return children;
|
|
2609
|
+
return (jsxs(Tooltip$1.Root, { ...rest, children: [jsx(Tooltip$1.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Tooltip$1.Positioner, { children: jsxs(Tooltip$1.Content, { ref: ref, ...contentProps, children: [showArrow && (jsx(Tooltip$1.Arrow, { children: jsx(Tooltip$1.ArrowTip, {}) })), content] }) }) })] }));
|
|
2610
|
+
});
|
|
2612
2611
|
|
|
2613
2612
|
const DataTableServerContext = createContext({
|
|
2614
2613
|
url: "",
|
|
@@ -2621,697 +2620,435 @@ const useDataTableServerContext = () => {
|
|
|
2621
2620
|
return { ...context, isEmpty };
|
|
2622
2621
|
};
|
|
2623
2622
|
|
|
2624
|
-
const
|
|
2625
|
-
const {
|
|
2626
|
-
|
|
2623
|
+
const ReloadButton = ({ variant = "icon", }) => {
|
|
2624
|
+
const { url } = useDataTableServerContext();
|
|
2625
|
+
const queryClient = useQueryClient();
|
|
2626
|
+
const { tableLabel } = useDataTableContext();
|
|
2627
|
+
const { reloadTooltip, reloadButtonText } = tableLabel;
|
|
2628
|
+
if (variant === "icon") {
|
|
2629
|
+
return (jsx(Tooltip, { showArrow: true, content: reloadTooltip, children: jsx(Button, { variant: "ghost", onClick: () => {
|
|
2630
|
+
queryClient.invalidateQueries({ queryKey: [url] });
|
|
2631
|
+
}, "aria-label": "refresh", children: jsx(IoReload, {}) }) }));
|
|
2632
|
+
}
|
|
2633
|
+
return (jsxs(Button, { variant: "ghost", onClick: () => {
|
|
2634
|
+
queryClient.invalidateQueries({ queryKey: [url] });
|
|
2635
|
+
}, children: [jsx(IoReload, {}), " ", reloadButtonText] }));
|
|
2627
2636
|
};
|
|
2628
2637
|
|
|
2629
|
-
const
|
|
2630
|
-
const {
|
|
2631
|
-
|
|
2632
|
-
|
|
2638
|
+
const InputGroup = React.forwardRef(function InputGroup(props, ref) {
|
|
2639
|
+
const { startElement, startElementProps, endElement, endElementProps, children, startOffset = "6px", endOffset = "6px", ...rest } = props;
|
|
2640
|
+
return (jsxs(Group, { ref: ref, ...rest, children: [startElement && (jsx(InputElement, { pointerEvents: "none", ...startElementProps, children: startElement })), React.cloneElement(children, {
|
|
2641
|
+
...(startElement && {
|
|
2642
|
+
ps: `calc(var(--input-height) - ${startOffset})`,
|
|
2643
|
+
}),
|
|
2644
|
+
...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
|
|
2645
|
+
// @ts-expect-error chakra generated files
|
|
2646
|
+
...children.props,
|
|
2647
|
+
}), endElement && (jsx(InputElement, { placement: "end", ...endElementProps, children: endElement }))] }));
|
|
2648
|
+
});
|
|
2649
|
+
|
|
2650
|
+
const GlobalFilter = () => {
|
|
2651
|
+
const { table, tableLabel } = useDataTableContext();
|
|
2652
|
+
const { globalFilterPlaceholder } = tableLabel;
|
|
2653
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
2654
|
+
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
2655
|
+
useEffect(() => {
|
|
2656
|
+
const searchHN = async () => {
|
|
2657
|
+
table.setGlobalFilter(debouncedSearchTerm);
|
|
2658
|
+
};
|
|
2659
|
+
searchHN();
|
|
2660
|
+
}, [debouncedSearchTerm]);
|
|
2661
|
+
return (jsx(Fragment, { children: jsx(InputGroup, { flex: "1", startElement: jsx(MdSearch, {}), children: jsx(Input, { placeholder: globalFilterPlaceholder, variant: "outline", onChange: (e) => {
|
|
2662
|
+
setSearchTerm(e.target.value);
|
|
2663
|
+
} }) }) }));
|
|
2633
2664
|
};
|
|
2634
2665
|
|
|
2635
|
-
const
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2666
|
+
const SelectAllRowsToggle = ({ selectAllIcon = jsx(MdOutlineChecklist, {}), clearAllIcon = jsx(MdClear, {}), selectAllText = "", clearAllText = "", }) => {
|
|
2667
|
+
const { table } = useDataTableContext();
|
|
2668
|
+
return (jsxs(Fragment, { children: [!!selectAllText === false && (jsx(IconButton, { variant: "ghost", "aria-label": table.getIsAllRowsSelected() ? clearAllText : selectAllText, onClick: (event) => {
|
|
2669
|
+
table.getToggleAllRowsSelectedHandler()(event);
|
|
2670
|
+
}, children: table.getIsAllRowsSelected() ? clearAllIcon : selectAllIcon })), !!selectAllText !== false && (jsxs(Button$1, { variant: "ghost", onClick: (event) => {
|
|
2671
|
+
table.getToggleAllRowsSelectedHandler()(event);
|
|
2672
|
+
}, children: [table.getIsAllRowsSelected() ? clearAllIcon : selectAllIcon, table.getIsAllRowsSelected() ? clearAllText : selectAllText] }))] }));
|
|
2640
2673
|
};
|
|
2641
2674
|
|
|
2642
|
-
const
|
|
2643
|
-
const
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
return snakeToLabel(field);
|
|
2648
|
-
};
|
|
2649
|
-
if (object === null) {
|
|
2650
|
-
return jsx(Fragment, { children: "null" });
|
|
2651
|
-
}
|
|
2652
|
-
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
|
|
2653
|
-
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "colorPalette.400", children: getColumn({ field }) }), typeof value === "object" ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsx(Text, { children: JSON.stringify(value) }))] }, field));
|
|
2654
|
-
}) }));
|
|
2675
|
+
const TableSelector = () => {
|
|
2676
|
+
const { table } = useDataTableContext();
|
|
2677
|
+
return (jsxs(Fragment, { children: [table.getSelectedRowModel().rows.length > 0 && (jsxs(Button$1, { onClick: () => { }, variant: "ghost", display: "flex", gap: "0.25rem", children: [jsx(Box, { fontSize: "sm", children: `${table.getSelectedRowModel().rows.length}` }), jsx(IoMdCheckbox, {})] })), !table.getIsAllPageRowsSelected() && jsx(SelectAllRowsToggle, {}), table.getSelectedRowModel().rows.length > 0 && (jsx(IconButton, { variant: "ghost", onClick: () => {
|
|
2678
|
+
table.resetRowSelection();
|
|
2679
|
+
}, "aria-label": "reset selection", children: jsx(MdClear, {}) }))] }));
|
|
2655
2680
|
};
|
|
2656
2681
|
|
|
2657
|
-
const
|
|
2658
|
-
const {
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
if (typeof value === "object") {
|
|
2667
|
-
return JSON.stringify(value);
|
|
2668
|
-
}
|
|
2669
|
-
if (typeof value === "string") {
|
|
2670
|
-
return value;
|
|
2671
|
-
}
|
|
2672
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
2673
|
-
return `${value}`;
|
|
2674
|
-
}
|
|
2675
|
-
if (value === undefined) {
|
|
2676
|
-
if (translate !== undefined) {
|
|
2677
|
-
return translate.t(`undefined`);
|
|
2678
|
-
}
|
|
2679
|
-
return `undefined`;
|
|
2680
|
-
}
|
|
2681
|
-
throw new Error(`value is unknown, ${typeof value}`);
|
|
2682
|
-
};
|
|
2683
|
-
const showCustomDataDisplay = cell.column.columnDef.meta?.showCustomDisplay ?? false;
|
|
2684
|
-
const gridColumn = cell.column.columnDef.meta?.gridColumn ?? [
|
|
2685
|
-
"span 12",
|
|
2686
|
-
"span 6",
|
|
2687
|
-
"span 3",
|
|
2688
|
-
];
|
|
2689
|
-
const gridRow = cell.column.columnDef.meta?.gridRow ?? {};
|
|
2690
|
-
if (showCustomDataDisplay) {
|
|
2691
|
-
return (jsx(Flex, { gridColumn, gridRow, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
|
|
2692
|
-
}
|
|
2693
|
-
const value = cell.getValue();
|
|
2694
|
-
if (typeof value === "object") {
|
|
2695
|
-
return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { children: getLabel({ columnId: cell.column.id }) }), jsx(RecordDisplay, { boxProps: {
|
|
2696
|
-
borderWidth: 1,
|
|
2697
|
-
borderRadius: 4,
|
|
2698
|
-
borderColor: "gray.400",
|
|
2699
|
-
paddingX: 4,
|
|
2700
|
-
paddingY: 2,
|
|
2701
|
-
}, object: value })] }, cell.id));
|
|
2702
|
-
}
|
|
2703
|
-
return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { color: "colorPalette.400", children: getLabel({ columnId: cell.column.id }) }), jsx(Box, { wordBreak: "break-word", textOverflow: "ellipsis", overflow: "hidden", children: `${formatValue(cell.getValue())}` })] }, cell.id));
|
|
2682
|
+
const TableFilterTags = () => {
|
|
2683
|
+
const { table } = useDataTableContext();
|
|
2684
|
+
return (jsx(Flex, { gap: "0.5rem", flexFlow: "wrap", children: table.getState().columnFilters.map(({ id, value }) => {
|
|
2685
|
+
return (jsx(Tag, { gap: "0.5rem", closable: true, cursor: "pointer", onClick: () => {
|
|
2686
|
+
table.setColumnFilters(table.getState().columnFilters.filter((filter) => {
|
|
2687
|
+
return filter.value != value;
|
|
2688
|
+
}));
|
|
2689
|
+
}, children: `${id}: ${value}` }, `${id}-${value}`));
|
|
2690
|
+
}) }));
|
|
2704
2691
|
};
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
if (!column.getIsVisible()) {
|
|
2716
|
-
return jsx(Fragment, {});
|
|
2692
|
+
|
|
2693
|
+
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 = {}, }) => {
|
|
2694
|
+
const { tableLabel, table } = useDataTableContext();
|
|
2695
|
+
const { rowCountText, hasErrorText } = tableLabel;
|
|
2696
|
+
return (jsxs(Grid, { templateRows: "auto 1fr", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", gap: "0.5rem", ...gridProps, children: [jsxs(Flex, { flexFlow: "column", gap: 2, children: [jsxs(Flex, { justifyContent: "space-between", children: [jsx(Box, { children: showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }) }), jsxs(Flex, { gap: "0.5rem", alignItems: "center", justifySelf: "end", children: [loading && jsx(Spinner, { size: "sm" }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: "red.400" }) })), showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsx(Flex, { flexFlow: "column", gap: "0.5rem", children: filterTagsOptions.map((option) => {
|
|
2697
|
+
const { column, options } = option;
|
|
2698
|
+
const tableColumn = table.getColumn(column);
|
|
2699
|
+
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) => {
|
|
2700
|
+
if (tags.length === 0) {
|
|
2701
|
+
return tableColumn?.setFilterValue(undefined);
|
|
2717
2702
|
}
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
return cell.id === `${rowId}_${column.id}`;
|
|
2722
|
-
});
|
|
2723
|
-
return jsx(CellRenderer, { cell: foundCell });
|
|
2724
|
-
}) })] }, `chakra-table-card-${childCell?.id}`));
|
|
2725
|
-
}
|
|
2726
|
-
return jsx(CellRenderer, { cell: childCell });
|
|
2727
|
-
}) }) }, `chakra-table-card-${rowId}`));
|
|
2728
|
-
}) }));
|
|
2703
|
+
tableColumn?.setFilterValue(tags);
|
|
2704
|
+
} })] }, column));
|
|
2705
|
+
}) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, { overflow: "auto", bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Flex, { justifyContent: "space-between", children: [jsxs(Flex, { gap: "1rem", alignItems: "center", children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && (jsxs(Flex, { children: [jsx(Text, { paddingRight: "0.5rem", children: rowCountText }), jsx(RowCountText, {})] }))] }), jsx(Box, { justifySelf: "end", children: showPagination && jsx(Pagination, {}) })] }))] }));
|
|
2729
2706
|
};
|
|
2730
2707
|
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
}
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2708
|
+
const EmptyState$1 = React.forwardRef(function EmptyState(props, ref) {
|
|
2709
|
+
const { title, description, icon, children, ...rest } = props;
|
|
2710
|
+
return (jsx(EmptyState$2.Root, { ref: ref, ...rest, children: jsxs(EmptyState$2.Content, { children: [icon && (jsx(EmptyState$2.Indicator, { children: icon })), description ? (jsxs(VStack, { textAlign: "center", children: [jsx(EmptyState$2.Title, { children: title }), jsx(EmptyState$2.Description, { children: description })] })) : (jsx(EmptyState$2.Title, { children: title })), children] }) }));
|
|
2711
|
+
});
|
|
2712
|
+
|
|
2713
|
+
/**
|
|
2714
|
+
* Hook to automatically hide/show columns based on container width.
|
|
2715
|
+
* Columns are hidden based on their responsivePriority (lower = hide first).
|
|
2716
|
+
* Only activates when canResize={false}.
|
|
2717
|
+
*/
|
|
2718
|
+
const useResponsiveColumnVisibility = ({ containerRef, enabled, showSelector = false, }) => {
|
|
2719
|
+
const { table, setColumnVisibility } = useDataTableContext();
|
|
2720
|
+
const autoHiddenRef = useRef(new Set());
|
|
2721
|
+
const userBaselineRef = useRef(null);
|
|
2722
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
2723
|
+
useEffect(() => {
|
|
2724
|
+
if (!enabled || !containerRef.current) {
|
|
2725
|
+
// Reset when disabled
|
|
2726
|
+
if (!enabled) {
|
|
2727
|
+
userBaselineRef.current = null;
|
|
2728
|
+
autoHiddenRef.current = new Set();
|
|
2729
|
+
}
|
|
2730
|
+
return;
|
|
2731
|
+
}
|
|
2732
|
+
// Capture baseline visibility when hook is first enabled
|
|
2733
|
+
if (userBaselineRef.current === null) {
|
|
2734
|
+
userBaselineRef.current = { ...table.getState().columnVisibility };
|
|
2735
|
+
}
|
|
2736
|
+
const updateColumnVisibility = () => {
|
|
2737
|
+
const container = containerRef.current;
|
|
2738
|
+
if (!container || !userBaselineRef.current)
|
|
2739
|
+
return;
|
|
2740
|
+
const containerWidth = container.clientWidth;
|
|
2741
|
+
// Get all columns
|
|
2742
|
+
const allColumns = table.getAllLeafColumns();
|
|
2743
|
+
// Get current visibility state
|
|
2744
|
+
const currentVisibility = table.getState().columnVisibility;
|
|
2745
|
+
// Determine user-hidden columns based on baseline
|
|
2746
|
+
// Columns that are hidden in baseline are considered user-hidden
|
|
2747
|
+
const userBaseline = userBaselineRef.current;
|
|
2748
|
+
const userHiddenColumns = new Set();
|
|
2749
|
+
for (const col of allColumns) {
|
|
2750
|
+
// If column was hidden in baseline, it's user-hidden
|
|
2751
|
+
if (userBaseline[col.id] === false) {
|
|
2752
|
+
userHiddenColumns.add(col.id);
|
|
2769
2753
|
}
|
|
2770
|
-
|
|
2771
|
-
|
|
2754
|
+
}
|
|
2755
|
+
// Consider all columns except those hidden by user in baseline
|
|
2756
|
+
const columnsToConsider = allColumns.filter((col) => {
|
|
2757
|
+
return !userHiddenColumns.has(col.id);
|
|
2758
|
+
});
|
|
2759
|
+
// Calculate priority for each column
|
|
2760
|
+
// Lower priority = hide first, Infinity = never auto-hide
|
|
2761
|
+
const columnsWithPriority = columnsToConsider.map((col, index) => {
|
|
2762
|
+
const priority = col.columnDef.meta?.responsivePriority ?? Infinity;
|
|
2763
|
+
return {
|
|
2764
|
+
column: col,
|
|
2765
|
+
priority,
|
|
2766
|
+
size: col.getSize(),
|
|
2767
|
+
index,
|
|
2768
|
+
};
|
|
2769
|
+
});
|
|
2770
|
+
// Sort by priority (ascending), then by index for stable ordering
|
|
2771
|
+
columnsWithPriority.sort((a, b) => {
|
|
2772
|
+
if (a.priority !== b.priority) {
|
|
2773
|
+
return a.priority - b.priority;
|
|
2772
2774
|
}
|
|
2773
|
-
return
|
|
2775
|
+
return a.index - b.index;
|
|
2774
2776
|
});
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2777
|
+
// Calculate available width (account for selector column if present)
|
|
2778
|
+
const availableWidth = showSelector
|
|
2779
|
+
? containerWidth - SELECTION_BOX_WIDTH
|
|
2780
|
+
: containerWidth;
|
|
2781
|
+
// Calculate which columns can fit
|
|
2782
|
+
let totalWidth = 0;
|
|
2783
|
+
const columnsToShow = new Set();
|
|
2784
|
+
// Always keep at least one column visible
|
|
2785
|
+
let minColumnsShown = 0;
|
|
2786
|
+
for (const { column, priority } of columnsWithPriority) {
|
|
2787
|
+
// If this is the first column and we haven't shown any, always show it
|
|
2788
|
+
if (minColumnsShown === 0) {
|
|
2789
|
+
columnsToShow.add(column.id);
|
|
2790
|
+
totalWidth += column.getSize();
|
|
2791
|
+
minColumnsShown = 1;
|
|
2792
|
+
continue;
|
|
2793
|
+
}
|
|
2794
|
+
// Check if adding this column would exceed available width
|
|
2795
|
+
const newTotalWidth = totalWidth + column.getSize();
|
|
2796
|
+
// If priority is Infinity, always show (never auto-hide)
|
|
2797
|
+
if (priority === Infinity) {
|
|
2798
|
+
columnsToShow.add(column.id);
|
|
2799
|
+
totalWidth = newTotalWidth;
|
|
2800
|
+
}
|
|
2801
|
+
else if (newTotalWidth <= availableWidth) {
|
|
2802
|
+
// Column fits, show it
|
|
2803
|
+
columnsToShow.add(column.id);
|
|
2804
|
+
totalWidth = newTotalWidth;
|
|
2805
|
+
}
|
|
2806
|
+
else ;
|
|
2783
2807
|
}
|
|
2784
|
-
|
|
2785
|
-
|
|
2808
|
+
// Update auto-hidden columns
|
|
2809
|
+
const newAutoHidden = new Set();
|
|
2810
|
+
const newVisibility = { ...currentVisibility };
|
|
2811
|
+
// Update visibility for all columns
|
|
2812
|
+
for (const col of allColumns) {
|
|
2813
|
+
const isUserHidden = userHiddenColumns.has(col.id);
|
|
2814
|
+
if (isUserHidden) {
|
|
2815
|
+
// Respect user preference to hide
|
|
2816
|
+
newVisibility[col.id] = false;
|
|
2817
|
+
}
|
|
2818
|
+
else {
|
|
2819
|
+
const shouldBeVisible = columnsToShow.has(col.id);
|
|
2820
|
+
if (!shouldBeVisible) {
|
|
2821
|
+
// Column should be auto-hidden
|
|
2822
|
+
newAutoHidden.add(col.id);
|
|
2823
|
+
newVisibility[col.id] = false;
|
|
2824
|
+
}
|
|
2825
|
+
else {
|
|
2826
|
+
// Column should be visible
|
|
2827
|
+
newVisibility[col.id] = true;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2786
2830
|
}
|
|
2787
|
-
|
|
2788
|
-
|
|
2831
|
+
// Update auto-hidden ref
|
|
2832
|
+
autoHiddenRef.current = newAutoHidden;
|
|
2833
|
+
// Only update if visibility actually changed
|
|
2834
|
+
const visibilityChanged = Object.keys(newVisibility).some((key) => newVisibility[key] !== currentVisibility[key]) ||
|
|
2835
|
+
Object.keys(currentVisibility).some((key) => newVisibility[key] !== currentVisibility[key]);
|
|
2836
|
+
if (visibilityChanged) {
|
|
2837
|
+
setColumnVisibility(newVisibility);
|
|
2789
2838
|
}
|
|
2790
|
-
return 32;
|
|
2791
2839
|
};
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2840
|
+
// Initial calculation
|
|
2841
|
+
updateColumnVisibility();
|
|
2842
|
+
// Set up ResizeObserver
|
|
2843
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
2844
|
+
updateColumnVisibility();
|
|
2845
|
+
});
|
|
2846
|
+
resizeObserver.observe(containerRef.current);
|
|
2847
|
+
return () => {
|
|
2848
|
+
resizeObserver.disconnect();
|
|
2849
|
+
};
|
|
2850
|
+
}, [enabled, containerRef, table, setColumnVisibility, showSelector]);
|
|
2801
2851
|
};
|
|
2802
|
-
//end of custom feature code
|
|
2803
2852
|
|
|
2804
|
-
|
|
2805
|
-
const
|
|
2806
|
-
|
|
2807
|
-
const
|
|
2808
|
-
//
|
|
2809
|
-
|
|
2810
|
-
|
|
2853
|
+
const EmptyResult = (jsx(EmptyState$1, { icon: jsx(HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxs(List.Root, { variant: "marker", children: [jsx(List.Item, { children: "Try removing filters" }), jsx(List.Item, { children: "Try different keywords" })] }) }));
|
|
2854
|
+
const Table = ({ children, emptyComponent = EmptyResult, canResize = true, showLoading = false, showSelector = false, ...props }) => {
|
|
2855
|
+
const { table } = useDataTableContext();
|
|
2856
|
+
const containerRef = useRef(null);
|
|
2857
|
+
// Enable responsive column hiding when canResize is false
|
|
2858
|
+
useResponsiveColumnVisibility({
|
|
2859
|
+
containerRef,
|
|
2860
|
+
enabled: !canResize,
|
|
2861
|
+
showSelector,
|
|
2811
2862
|
});
|
|
2812
|
-
//
|
|
2813
|
-
|
|
2863
|
+
// Skip empty check when loading to allow skeleton to render
|
|
2864
|
+
if (!showLoading && table.getRowModel().rows.length <= 0) {
|
|
2865
|
+
return emptyComponent;
|
|
2866
|
+
}
|
|
2867
|
+
return (jsx(Box, { ref: containerRef, width: "100%", overflow: "auto", children: jsx(Table$1.Root, { stickyHeader: true, variant: 'outline', width: canResize ? table.getCenterTotalSize() : undefined, display: 'grid', alignContent: 'start', overflowY: 'auto', bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...props, children: children }) }));
|
|
2868
|
+
};
|
|
2869
|
+
|
|
2870
|
+
const Checkbox = React.forwardRef(function Checkbox(props, ref) {
|
|
2871
|
+
const { icon, children, inputProps, rootRef, ...rest } = props;
|
|
2872
|
+
return (jsxs(Checkbox$1.Root, { ref: rootRef, ...rest, children: [jsx(Checkbox$1.HiddenInput, { ref: ref, ...inputProps }), jsx(Checkbox$1.Control, { children: icon || jsx(Checkbox$1.Indicator, {}) }), children != null && (jsx(Checkbox$1.Label, { children: children }))] }));
|
|
2873
|
+
});
|
|
2874
|
+
|
|
2875
|
+
const TableBody = ({ showSelector = false, canResize = true, }) => {
|
|
2876
|
+
"use no memo";
|
|
2877
|
+
const { table } = useDataTableContext();
|
|
2878
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
2879
|
+
const [hoveredRow, setHoveredRow] = useState(-1);
|
|
2880
|
+
const handleRowHover = (index) => {
|
|
2881
|
+
setHoveredRow(index);
|
|
2882
|
+
};
|
|
2883
|
+
const getTdProps = (cell) => {
|
|
2884
|
+
const tdProps = cell.column.getIsPinned()
|
|
2885
|
+
? {
|
|
2886
|
+
left: showSelector
|
|
2887
|
+
? `${cell.column.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
2888
|
+
: `${cell.column.getStart("left")}px`,
|
|
2889
|
+
position: "relative",
|
|
2890
|
+
}
|
|
2891
|
+
: {};
|
|
2892
|
+
return tdProps;
|
|
2893
|
+
};
|
|
2894
|
+
const getTrProps = ({ hoveredRow, index, }) => {
|
|
2895
|
+
if (hoveredRow === -1) {
|
|
2896
|
+
return {};
|
|
2897
|
+
}
|
|
2898
|
+
if (hoveredRow === index) {
|
|
2899
|
+
return {
|
|
2900
|
+
opacity: "1",
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2903
|
+
return {
|
|
2904
|
+
opacity: "0.8",
|
|
2905
|
+
};
|
|
2906
|
+
};
|
|
2907
|
+
return (jsx(Table$1.Body, { children: table.getRowModel().rows.map((row, index) => {
|
|
2908
|
+
return (jsxs(Table$1.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow })), row.getVisibleCells().map((cell, index) => {
|
|
2909
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
|
|
2910
|
+
// styling resize and pinning start
|
|
2911
|
+
flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`,
|
|
2912
|
+
// this is to avoid the cell from being too wide
|
|
2913
|
+
minWidth: `0`, color: {
|
|
2914
|
+
base: "colorPalette.900",
|
|
2915
|
+
_dark: "colorPalette.100",
|
|
2916
|
+
},
|
|
2917
|
+
bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, ...getTdProps(cell), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
2918
|
+
})] }, `chakra-table-row-${row.id}`));
|
|
2919
|
+
}) }));
|
|
2920
|
+
};
|
|
2921
|
+
const TableRowSelector = ({ row, }) => {
|
|
2922
|
+
const { table } = useDataTableContext();
|
|
2923
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
2924
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
|
|
2925
|
+
base: "colorPalette.900",
|
|
2926
|
+
_dark: "colorPalette.100",
|
|
2927
|
+
},
|
|
2928
|
+
bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: row.getIsSelected(),
|
|
2929
|
+
disabled: !row.getCanSelect(),
|
|
2930
|
+
onCheckedChange: row.getToggleSelectedHandler() }) }));
|
|
2931
|
+
};
|
|
2932
|
+
|
|
2933
|
+
const TableCardContainer = ({ children, variant = "", gap = "1rem", gridTemplateColumns = "repeat(auto-fit, minmax(20rem, 1fr))", direction = "row", ...props }) => {
|
|
2934
|
+
if (variant === "carousel") {
|
|
2935
|
+
return (jsx(Flex, { overflow: "auto", gap: gap, direction: direction, ...props, children: children }));
|
|
2936
|
+
}
|
|
2937
|
+
return (jsx(Grid, { gridTemplateColumns: gridTemplateColumns, gap: gap, ...props, children: children }));
|
|
2938
|
+
};
|
|
2939
|
+
|
|
2940
|
+
const DefaultCardTitle = () => {
|
|
2941
|
+
return jsx(Fragment, {});
|
|
2942
|
+
};
|
|
2943
|
+
const TableCards = ({ isSelectable = false, showDisplayNameOnly = false, renderTitle = DefaultCardTitle, cardBodyProps = {}, }) => {
|
|
2944
|
+
const { table } = useDataTableContext();
|
|
2945
|
+
return (jsx(Fragment, { children: table.getRowModel().rows.map((row) => {
|
|
2946
|
+
return (jsx(Card.Root, { flex: "1 0 20rem", children: jsxs(Card.Body, { display: "flex", flexFlow: "column", gap: "0.5rem", ...cardBodyProps, children: [isSelectable && (jsx(Checkbox, { isChecked: row.getIsSelected(),
|
|
2947
|
+
disabled: !row.getCanSelect(),
|
|
2948
|
+
// indeterminate: row.getIsSomeSelected(),
|
|
2949
|
+
onChange: row.getToggleSelectedHandler() })), renderTitle(row), jsx(Grid, { templateColumns: "auto 1fr", gap: "1rem", children: row.getVisibleCells().map((cell) => {
|
|
2950
|
+
return (jsxs(Fragment, { children: [jsxs(Box, { children: [showDisplayNameOnly && (jsx(Text, { fontWeight: "bold", children: cell.column.columnDef.meta?.displayName ??
|
|
2951
|
+
cell.column.id })), !showDisplayNameOnly && (jsx(Fragment, { children: flexRender(cell.column.columnDef.header,
|
|
2952
|
+
// @ts-expect-error Assuming the CellContext interface is the same as HeaderContext
|
|
2953
|
+
cell.getContext()) }))] }, `chakra-table-cardcolumnid-${row.id}`), jsx(Box, { justifySelf: "end", children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-cardcolumn-${row.id}`)] }));
|
|
2954
|
+
}) })] }) }, `chakra-table-card-${row.id}`));
|
|
2955
|
+
}) }));
|
|
2956
|
+
};
|
|
2957
|
+
|
|
2958
|
+
const TableComponent = ({ render = () => {
|
|
2959
|
+
throw Error("Not Implemented");
|
|
2960
|
+
}, }) => {
|
|
2961
|
+
const { table } = useDataTableContext();
|
|
2962
|
+
return render(table);
|
|
2963
|
+
};
|
|
2964
|
+
|
|
2965
|
+
const TableFooter = ({ showSelector = false, alwaysShowSelector = true, }) => {
|
|
2966
|
+
const table = useDataTableContext().table;
|
|
2967
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
2968
|
+
const [hoveredCheckBox, setHoveredCheckBox] = useState(false);
|
|
2969
|
+
const handleRowHover = (isHovered) => {
|
|
2970
|
+
setHoveredCheckBox(isHovered);
|
|
2971
|
+
};
|
|
2972
|
+
const isCheckBoxVisible = () => {
|
|
2973
|
+
if (alwaysShowSelector) {
|
|
2974
|
+
return true;
|
|
2975
|
+
}
|
|
2976
|
+
if (table.getIsAllRowsSelected()) {
|
|
2977
|
+
return true;
|
|
2978
|
+
}
|
|
2979
|
+
if (hoveredCheckBox) {
|
|
2980
|
+
return true;
|
|
2981
|
+
}
|
|
2982
|
+
return false;
|
|
2983
|
+
};
|
|
2984
|
+
return (jsx(Table$1.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxs(Table$1.Row, { display: "flex", children: [showSelector && (jsxs(Table$1.Header, { padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
|
|
2985
|
+
// indeterminate: table.getIsSomeRowsSelected(),
|
|
2986
|
+
onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsx(Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }))] })), footerGroup.headers.map((header) => (jsx(Table$1.Cell, { padding: "0", columnSpan: `${header.colSpan}`,
|
|
2987
|
+
// styling resize and pinning start
|
|
2988
|
+
maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid", children: jsx(MenuRoot$1, { children: jsx(MenuTrigger$1, { asChild: true, children: jsx(Box, { padding: `${table.getDensityValue()}px`, display: "flex", alignItems: "center", justifyContent: "start", borderRadius: "0rem", children: jsxs(Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
|
|
2989
|
+
? null
|
|
2990
|
+
: flexRender(header.column.columnDef.footer, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && jsx(Fragment, {}), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
|
|
2991
|
+
};
|
|
2992
|
+
|
|
2993
|
+
// Default text values
|
|
2994
|
+
const DEFAULT_HEADER_TEXTS = {
|
|
2995
|
+
pinColumn: "Pin Column",
|
|
2996
|
+
cancelPin: "Cancel Pin",
|
|
2997
|
+
sortAscending: "Sort Ascending",
|
|
2998
|
+
sortDescending: "Sort Descending",
|
|
2999
|
+
clearSorting: "Clear Sorting",
|
|
2814
3000
|
};
|
|
2815
3001
|
/**
|
|
2816
|
-
*
|
|
2817
|
-
* help the render of the DataTable in serverside
|
|
3002
|
+
* TableHeader component with configurable text strings.
|
|
2818
3003
|
*
|
|
3004
|
+
* @example
|
|
3005
|
+
* // Using default texts
|
|
3006
|
+
* <TableHeader />
|
|
2819
3007
|
*
|
|
2820
|
-
*
|
|
2821
|
-
*
|
|
3008
|
+
* @example
|
|
3009
|
+
* // Customizing default texts for all columns
|
|
3010
|
+
* <TableHeader
|
|
3011
|
+
* defaultTexts={{
|
|
3012
|
+
* pinColumn: "Pin This Column",
|
|
3013
|
+
* sortAscending: "Sort A-Z"
|
|
3014
|
+
* }}
|
|
3015
|
+
* />
|
|
2822
3016
|
*
|
|
2823
|
-
* @
|
|
3017
|
+
* @example
|
|
3018
|
+
* // Customizing texts per column via meta
|
|
3019
|
+
* const columns = [
|
|
3020
|
+
* columnHelper.accessor("name", {
|
|
3021
|
+
* header: "Name",
|
|
3022
|
+
* meta: {
|
|
3023
|
+
* headerTexts: {
|
|
3024
|
+
* pinColumn: "Pin Name Column",
|
|
3025
|
+
* sortAscending: "Sort Names A-Z"
|
|
3026
|
+
* }
|
|
3027
|
+
* }
|
|
3028
|
+
* })
|
|
3029
|
+
* ];
|
|
2824
3030
|
*/
|
|
2825
|
-
|
|
2826
|
-
view: 'View',
|
|
2827
|
-
edit: 'Edit',
|
|
2828
|
-
filterButtonText: 'Filter',
|
|
2829
|
-
filterTitle: 'Filter',
|
|
2830
|
-
filterReset: 'Reset',
|
|
2831
|
-
filterClose: 'Close',
|
|
2832
|
-
reloadTooltip: 'Reload',
|
|
2833
|
-
reloadButtonText: 'Reload',
|
|
2834
|
-
resetSelection: 'Reset Selection',
|
|
2835
|
-
resetSorting: 'Reset Sorting',
|
|
2836
|
-
rowCountText: 'Row Count',
|
|
2837
|
-
hasErrorText: 'Has Error',
|
|
2838
|
-
globalFilterPlaceholder: 'Search',
|
|
2839
|
-
trueLabel: 'True',
|
|
2840
|
-
falseLabel: 'False',
|
|
2841
|
-
}, }) {
|
|
2842
|
-
const table = useReactTable({
|
|
2843
|
-
_features: [DensityFeature],
|
|
2844
|
-
data: data,
|
|
2845
|
-
rowCount: data.length,
|
|
2846
|
-
columns: columns,
|
|
2847
|
-
getCoreRowModel: getCoreRowModel(),
|
|
2848
|
-
getFilteredRowModel: getFilteredRowModel(),
|
|
2849
|
-
getSortedRowModel: getSortedRowModel(),
|
|
2850
|
-
getPaginationRowModel: getPaginationRowModel(),
|
|
2851
|
-
defaultColumn: {
|
|
2852
|
-
size: 150, //starting column size
|
|
2853
|
-
minSize: 10, //enforced during column resizing
|
|
2854
|
-
maxSize: 10000, //enforced during column resizing
|
|
2855
|
-
},
|
|
2856
|
-
enableRowSelection: enableRowSelection,
|
|
2857
|
-
enableMultiRowSelection: enableMultiRowSelection,
|
|
2858
|
-
enableSubRowSelection: enableSubRowSelection,
|
|
2859
|
-
columnResizeMode: 'onChange',
|
|
2860
|
-
// global filter start
|
|
2861
|
-
filterFns: {
|
|
2862
|
-
fuzzy: fuzzyFilter,
|
|
2863
|
-
},
|
|
2864
|
-
globalFilterFn: 'fuzzy',
|
|
2865
|
-
state: {
|
|
2866
|
-
pagination,
|
|
2867
|
-
sorting,
|
|
2868
|
-
columnFilters,
|
|
2869
|
-
rowSelection,
|
|
2870
|
-
columnOrder,
|
|
2871
|
-
globalFilter,
|
|
2872
|
-
density,
|
|
2873
|
-
columnVisibility,
|
|
2874
|
-
},
|
|
2875
|
-
onPaginationChange: setPagination,
|
|
2876
|
-
onSortingChange: setSorting,
|
|
2877
|
-
onColumnFiltersChange: setColumnFilters,
|
|
2878
|
-
onRowSelectionChange: setRowSelection,
|
|
2879
|
-
onColumnOrderChange: (state) => {
|
|
2880
|
-
setColumnOrder(state);
|
|
2881
|
-
},
|
|
2882
|
-
onGlobalFilterChange: (state) => {
|
|
2883
|
-
setGlobalFilter(state);
|
|
2884
|
-
},
|
|
2885
|
-
onDensityChange: setDensity,
|
|
2886
|
-
onColumnVisibilityChange: setColumnVisibility,
|
|
2887
|
-
});
|
|
2888
|
-
return (jsx(DataTableContext.Provider, { value: {
|
|
2889
|
-
table: table,
|
|
2890
|
-
globalFilter,
|
|
2891
|
-
setGlobalFilter,
|
|
2892
|
-
type: 'client',
|
|
2893
|
-
translate,
|
|
2894
|
-
columns: columns,
|
|
2895
|
-
sorting,
|
|
2896
|
-
setSorting,
|
|
2897
|
-
columnFilters,
|
|
2898
|
-
setColumnFilters,
|
|
2899
|
-
pagination,
|
|
2900
|
-
setPagination,
|
|
2901
|
-
rowSelection,
|
|
2902
|
-
setRowSelection,
|
|
2903
|
-
columnOrder,
|
|
2904
|
-
setColumnOrder,
|
|
2905
|
-
density,
|
|
2906
|
-
setDensity,
|
|
2907
|
-
columnVisibility,
|
|
2908
|
-
setColumnVisibility,
|
|
2909
|
-
data,
|
|
2910
|
-
tableLabel,
|
|
2911
|
-
}, children: children }));
|
|
2912
|
-
}
|
|
2913
|
-
|
|
2914
|
-
/**
|
|
2915
|
-
* DataTableServer will create a context to hold all values to
|
|
2916
|
-
* help the render of the DataTable in serverside
|
|
2917
|
-
*
|
|
2918
|
-
* The query is required to be a GET request that can receive
|
|
2919
|
-
* specified params and return a specified response
|
|
2920
|
-
*
|
|
2921
|
-
* The `useDataTableServer` can help to create the specified request and response
|
|
2922
|
-
*
|
|
2923
|
-
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
2924
|
-
*/
|
|
2925
|
-
function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url, translate, children, tableLabel = {
|
|
2926
|
-
view: "View",
|
|
2927
|
-
edit: "Edit",
|
|
2928
|
-
filterButtonText: "Filter",
|
|
2929
|
-
filterTitle: "Filter",
|
|
2930
|
-
filterReset: "Reset",
|
|
2931
|
-
filterClose: "Close",
|
|
2932
|
-
reloadTooltip: "Reload",
|
|
2933
|
-
reloadButtonText: "Reload",
|
|
2934
|
-
resetSelection: "Reset Selection",
|
|
2935
|
-
resetSorting: "Reset Sorting",
|
|
2936
|
-
rowCountText: "Row Count",
|
|
2937
|
-
hasErrorText: "Has Error",
|
|
2938
|
-
globalFilterPlaceholder: "Search",
|
|
2939
|
-
trueLabel: "True",
|
|
2940
|
-
falseLabel: "False",
|
|
2941
|
-
}, }) {
|
|
2942
|
-
const table = useReactTable({
|
|
2943
|
-
_features: [DensityFeature],
|
|
2944
|
-
data: (query.data?.data ?? []),
|
|
2945
|
-
rowCount: query.data?.count ?? 0,
|
|
2946
|
-
columns: columns,
|
|
2947
|
-
getCoreRowModel: getCoreRowModel(),
|
|
2948
|
-
manualPagination: true,
|
|
2949
|
-
manualSorting: true,
|
|
2950
|
-
columnResizeMode: "onChange",
|
|
2951
|
-
defaultColumn: {
|
|
2952
|
-
size: 150, //starting column size
|
|
2953
|
-
minSize: 10, //enforced during column resizing
|
|
2954
|
-
maxSize: 10000, //enforced during column resizing
|
|
2955
|
-
},
|
|
2956
|
-
enableRowSelection: enableRowSelection,
|
|
2957
|
-
enableMultiRowSelection: enableMultiRowSelection,
|
|
2958
|
-
enableSubRowSelection: enableSubRowSelection,
|
|
2959
|
-
state: {
|
|
2960
|
-
pagination,
|
|
2961
|
-
sorting,
|
|
2962
|
-
columnFilters,
|
|
2963
|
-
rowSelection,
|
|
2964
|
-
columnOrder,
|
|
2965
|
-
globalFilter,
|
|
2966
|
-
density,
|
|
2967
|
-
columnVisibility,
|
|
2968
|
-
},
|
|
2969
|
-
onPaginationChange: setPagination,
|
|
2970
|
-
onSortingChange: setSorting,
|
|
2971
|
-
onColumnFiltersChange: setColumnFilters,
|
|
2972
|
-
onRowSelectionChange: setRowSelection,
|
|
2973
|
-
onColumnOrderChange: (state) => {
|
|
2974
|
-
setColumnOrder(state);
|
|
2975
|
-
},
|
|
2976
|
-
onGlobalFilterChange: (state) => {
|
|
2977
|
-
setGlobalFilter(state);
|
|
2978
|
-
},
|
|
2979
|
-
onDensityChange: setDensity,
|
|
2980
|
-
onColumnVisibilityChange: setColumnVisibility,
|
|
2981
|
-
// for tanstack-table ts bug start
|
|
2982
|
-
filterFns: {
|
|
2983
|
-
fuzzy: () => {
|
|
2984
|
-
return false;
|
|
2985
|
-
},
|
|
2986
|
-
},
|
|
2987
|
-
// for tanstack-table ts bug end
|
|
2988
|
-
});
|
|
2989
|
-
return (jsx(DataTableContext.Provider, { value: {
|
|
2990
|
-
table: table,
|
|
2991
|
-
globalFilter,
|
|
2992
|
-
setGlobalFilter,
|
|
2993
|
-
type: "server",
|
|
2994
|
-
translate,
|
|
2995
|
-
columns: columns,
|
|
2996
|
-
sorting,
|
|
2997
|
-
setSorting,
|
|
2998
|
-
columnFilters,
|
|
2999
|
-
setColumnFilters,
|
|
3000
|
-
pagination,
|
|
3001
|
-
setPagination,
|
|
3002
|
-
rowSelection,
|
|
3003
|
-
setRowSelection,
|
|
3004
|
-
columnOrder,
|
|
3005
|
-
setColumnOrder,
|
|
3006
|
-
density,
|
|
3007
|
-
setDensity,
|
|
3008
|
-
columnVisibility,
|
|
3009
|
-
setColumnVisibility,
|
|
3010
|
-
data: query.data?.data ?? [],
|
|
3011
|
-
tableLabel,
|
|
3012
|
-
}, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
3013
|
-
}
|
|
3014
|
-
|
|
3015
|
-
const InputGroup = React.forwardRef(function InputGroup(props, ref) {
|
|
3016
|
-
const { startElement, startElementProps, endElement, endElementProps, children, startOffset = "6px", endOffset = "6px", ...rest } = props;
|
|
3017
|
-
return (jsxs(Group, { ref: ref, ...rest, children: [startElement && (jsx(InputElement, { pointerEvents: "none", ...startElementProps, children: startElement })), React.cloneElement(children, {
|
|
3018
|
-
...(startElement && {
|
|
3019
|
-
ps: `calc(var(--input-height) - ${startOffset})`,
|
|
3020
|
-
}),
|
|
3021
|
-
...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
|
|
3022
|
-
// @ts-expect-error chakra generated files
|
|
3023
|
-
...children.props,
|
|
3024
|
-
}), endElement && (jsx(InputElement, { placement: "end", ...endElementProps, children: endElement }))] }));
|
|
3025
|
-
});
|
|
3026
|
-
|
|
3027
|
-
const GlobalFilter = () => {
|
|
3028
|
-
const { table, tableLabel } = useDataTableContext();
|
|
3029
|
-
const { globalFilterPlaceholder } = tableLabel;
|
|
3030
|
-
const [searchTerm, setSearchTerm] = useState("");
|
|
3031
|
-
const debouncedSearchTerm = useDebounce(searchTerm, 500);
|
|
3032
|
-
useEffect(() => {
|
|
3033
|
-
const searchHN = async () => {
|
|
3034
|
-
table.setGlobalFilter(debouncedSearchTerm);
|
|
3035
|
-
};
|
|
3036
|
-
searchHN();
|
|
3037
|
-
}, [debouncedSearchTerm]);
|
|
3038
|
-
return (jsx(Fragment, { children: jsx(InputGroup, { flex: "1", startElement: jsx(MdSearch, {}), children: jsx(Input, { placeholder: globalFilterPlaceholder, variant: "outline", onChange: (e) => {
|
|
3039
|
-
setSearchTerm(e.target.value);
|
|
3040
|
-
} }) }) }));
|
|
3041
|
-
};
|
|
3042
|
-
|
|
3043
|
-
const Tooltip = React.forwardRef(function Tooltip(props, ref) {
|
|
3044
|
-
const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
|
|
3045
|
-
if (disabled)
|
|
3046
|
-
return children;
|
|
3047
|
-
return (jsxs(Tooltip$1.Root, { ...rest, children: [jsx(Tooltip$1.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Tooltip$1.Positioner, { children: jsxs(Tooltip$1.Content, { ref: ref, ...contentProps, children: [showArrow && (jsx(Tooltip$1.Arrow, { children: jsx(Tooltip$1.ArrowTip, {}) })), content] }) }) })] }));
|
|
3048
|
-
});
|
|
3049
|
-
|
|
3050
|
-
const ReloadButton = ({ variant = "icon", }) => {
|
|
3051
|
-
const { url } = useDataTableServerContext();
|
|
3052
|
-
const queryClient = useQueryClient();
|
|
3053
|
-
const { tableLabel } = useDataTableContext();
|
|
3054
|
-
const { reloadTooltip, reloadButtonText } = tableLabel;
|
|
3055
|
-
if (variant === "icon") {
|
|
3056
|
-
return (jsx(Tooltip, { showArrow: true, content: reloadTooltip, children: jsx(Button, { variant: "ghost", onClick: () => {
|
|
3057
|
-
queryClient.invalidateQueries({ queryKey: [url] });
|
|
3058
|
-
}, "aria-label": "refresh", children: jsx(IoReload, {}) }) }));
|
|
3059
|
-
}
|
|
3060
|
-
return (jsxs(Button, { variant: "ghost", onClick: () => {
|
|
3061
|
-
queryClient.invalidateQueries({ queryKey: [url] });
|
|
3062
|
-
}, children: [jsx(IoReload, {}), " ", reloadButtonText] }));
|
|
3063
|
-
};
|
|
3064
|
-
|
|
3065
|
-
const TableFilterTags = () => {
|
|
3066
|
-
const { table } = useDataTableContext();
|
|
3067
|
-
return (jsx(Flex, { gap: "0.5rem", flexFlow: "wrap", children: table.getState().columnFilters.map(({ id, value }) => {
|
|
3068
|
-
return (jsx(Tag, { gap: "0.5rem", closable: true, cursor: "pointer", onClick: () => {
|
|
3069
|
-
table.setColumnFilters(table.getState().columnFilters.filter((filter) => {
|
|
3070
|
-
return filter.value != value;
|
|
3071
|
-
}));
|
|
3072
|
-
}, children: `${id}: ${value}` }, `${id}-${value}`));
|
|
3073
|
-
}) }));
|
|
3074
|
-
};
|
|
3075
|
-
|
|
3076
|
-
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 = {}, }) => {
|
|
3077
|
-
const { tableLabel, table } = useDataTableContext();
|
|
3078
|
-
const { rowCountText, hasErrorText } = tableLabel;
|
|
3079
|
-
return (jsxs(Grid, { templateRows: "auto 1fr", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", gap: "0.5rem", ...gridProps, children: [jsxs(Flex, { flexFlow: "column", gap: 2, children: [jsxs(Flex, { justifyContent: "space-between", children: [jsx(Box, { children: showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }) }), jsxs(Flex, { gap: "0.5rem", alignItems: "center", justifySelf: "end", children: [loading && jsx(Spinner, { size: "sm" }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: "red.400" }) })), showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsx(Flex, { flexFlow: "column", gap: "0.5rem", children: filterTagsOptions.map((option) => {
|
|
3080
|
-
const { column, options } = option;
|
|
3081
|
-
const tableColumn = table.getColumn(column);
|
|
3082
|
-
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) => {
|
|
3083
|
-
if (tags.length === 0) {
|
|
3084
|
-
return tableColumn?.setFilterValue(undefined);
|
|
3085
|
-
}
|
|
3086
|
-
tableColumn?.setFilterValue(tags);
|
|
3087
|
-
} })] }, column));
|
|
3088
|
-
}) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, { overflow: "auto", bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Flex, { justifyContent: "space-between", children: [jsxs(Flex, { gap: "1rem", alignItems: "center", children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && (jsxs(Flex, { children: [jsx(Text, { paddingRight: "0.5rem", children: rowCountText }), jsx(RowCountText, {})] }))] }), jsx(Box, { justifySelf: "end", children: showPagination && jsx(Pagination, {}) })] }))] }));
|
|
3089
|
-
};
|
|
3090
|
-
|
|
3091
|
-
const EmptyState = React.forwardRef(function EmptyState(props, ref) {
|
|
3092
|
-
const { title, description, icon, children, ...rest } = props;
|
|
3093
|
-
return (jsx(EmptyState$2.Root, { ref: ref, ...rest, children: jsxs(EmptyState$2.Content, { children: [icon && (jsx(EmptyState$2.Indicator, { children: icon })), description ? (jsxs(VStack, { textAlign: "center", children: [jsx(EmptyState$2.Title, { children: title }), jsx(EmptyState$2.Description, { children: description })] })) : (jsx(EmptyState$2.Title, { children: title })), children] }) }));
|
|
3094
|
-
});
|
|
3095
|
-
|
|
3096
|
-
const EmptyResult = (jsx(EmptyState, { icon: jsx(HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxs(List.Root, { variant: "marker", children: [jsx(List.Item, { children: "Try removing filters" }), jsx(List.Item, { children: "Try different keywords" })] }) }));
|
|
3097
|
-
const Table = ({ children, emptyComponent = EmptyResult, canResize = true, showLoading = false, ...props }) => {
|
|
3098
|
-
const { table } = useDataTableContext();
|
|
3099
|
-
// Skip empty check when loading to allow skeleton to render
|
|
3100
|
-
if (!showLoading && table.getRowModel().rows.length <= 0) {
|
|
3101
|
-
return emptyComponent;
|
|
3102
|
-
}
|
|
3103
|
-
return (jsx(Table$1.Root, { stickyHeader: true, variant: 'outline', width: canResize ? table.getCenterTotalSize() : undefined, display: 'grid', alignContent: 'start', overflowY: 'auto', bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...props, children: children }));
|
|
3104
|
-
};
|
|
3105
|
-
|
|
3106
|
-
const Checkbox = React.forwardRef(function Checkbox(props, ref) {
|
|
3107
|
-
const { icon, children, inputProps, rootRef, ...rest } = props;
|
|
3108
|
-
return (jsxs(Checkbox$1.Root, { ref: rootRef, ...rest, children: [jsx(Checkbox$1.HiddenInput, { ref: ref, ...inputProps }), jsx(Checkbox$1.Control, { children: icon || jsx(Checkbox$1.Indicator, {}) }), children != null && (jsx(Checkbox$1.Label, { children: children }))] }));
|
|
3109
|
-
});
|
|
3110
|
-
|
|
3111
|
-
const TableBody = ({ showSelector = false, canResize = true, }) => {
|
|
3112
|
-
"use no memo";
|
|
3031
|
+
const TableHeader = ({ canResize = true, showSelector = false, isSticky = true, tableHeaderProps = {}, tableRowProps = {}, defaultTexts = {}, }) => {
|
|
3113
3032
|
const { table } = useDataTableContext();
|
|
3114
3033
|
const SELECTION_BOX_WIDTH = 20;
|
|
3115
|
-
|
|
3116
|
-
const
|
|
3117
|
-
|
|
3034
|
+
// Merge default texts with provided defaults
|
|
3035
|
+
const mergedDefaultTexts = { ...DEFAULT_HEADER_TEXTS, ...defaultTexts };
|
|
3036
|
+
// Helper function to get text for a specific header
|
|
3037
|
+
const getHeaderText = (header, key) => {
|
|
3038
|
+
const columnMeta = header.column.columnDef.meta;
|
|
3039
|
+
return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
|
|
3118
3040
|
};
|
|
3119
|
-
const
|
|
3120
|
-
const
|
|
3041
|
+
const getThProps = (header) => {
|
|
3042
|
+
const thProps = header.column.getIsPinned()
|
|
3121
3043
|
? {
|
|
3122
3044
|
left: showSelector
|
|
3123
|
-
? `${
|
|
3124
|
-
: `${
|
|
3125
|
-
position: "
|
|
3045
|
+
? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3046
|
+
: `${header.getStart("left")}px`,
|
|
3047
|
+
position: "sticky",
|
|
3048
|
+
zIndex: 100 + 1,
|
|
3126
3049
|
}
|
|
3127
3050
|
: {};
|
|
3128
|
-
return
|
|
3129
|
-
};
|
|
3130
|
-
const getTrProps = ({ hoveredRow, index, }) => {
|
|
3131
|
-
if (hoveredRow === -1) {
|
|
3132
|
-
return {};
|
|
3133
|
-
}
|
|
3134
|
-
if (hoveredRow === index) {
|
|
3135
|
-
return {
|
|
3136
|
-
opacity: "1",
|
|
3137
|
-
};
|
|
3138
|
-
}
|
|
3139
|
-
return {
|
|
3140
|
-
opacity: "0.8",
|
|
3141
|
-
};
|
|
3142
|
-
};
|
|
3143
|
-
return (jsx(Table$1.Body, { children: table.getRowModel().rows.map((row, index) => {
|
|
3144
|
-
return (jsxs(Table$1.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow })), row.getVisibleCells().map((cell, index) => {
|
|
3145
|
-
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
|
|
3146
|
-
// styling resize and pinning start
|
|
3147
|
-
flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`,
|
|
3148
|
-
// this is to avoid the cell from being too wide
|
|
3149
|
-
minWidth: `0`, color: {
|
|
3150
|
-
base: "colorPalette.900",
|
|
3151
|
-
_dark: "colorPalette.100",
|
|
3152
|
-
},
|
|
3153
|
-
bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, ...getTdProps(cell), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
3154
|
-
})] }, `chakra-table-row-${row.id}`));
|
|
3155
|
-
}) }));
|
|
3156
|
-
};
|
|
3157
|
-
const TableRowSelector = ({ row, }) => {
|
|
3158
|
-
const { table } = useDataTableContext();
|
|
3159
|
-
const SELECTION_BOX_WIDTH = 20;
|
|
3160
|
-
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
|
|
3161
|
-
base: "colorPalette.900",
|
|
3162
|
-
_dark: "colorPalette.100",
|
|
3163
|
-
},
|
|
3164
|
-
bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: row.getIsSelected(),
|
|
3165
|
-
disabled: !row.getCanSelect(),
|
|
3166
|
-
onCheckedChange: row.getToggleSelectedHandler() }) }));
|
|
3167
|
-
};
|
|
3168
|
-
|
|
3169
|
-
const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
|
|
3170
|
-
'use no memo';
|
|
3171
|
-
const { table } = useDataTableContext();
|
|
3172
|
-
const SELECTION_BOX_WIDTH = 20;
|
|
3173
|
-
const [hoveredRow, setHoveredRow] = useState(-1);
|
|
3174
|
-
const handleRowHover = (index) => {
|
|
3175
|
-
setHoveredRow(index);
|
|
3176
|
-
};
|
|
3177
|
-
const getTdProps = (column) => {
|
|
3178
|
-
const tdProps = column.getIsPinned()
|
|
3179
|
-
? {
|
|
3180
|
-
left: showSelector
|
|
3181
|
-
? `${column.getStart('left') + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3182
|
-
: `${column.getStart('left')}px`,
|
|
3183
|
-
position: 'relative',
|
|
3184
|
-
}
|
|
3185
|
-
: {};
|
|
3186
|
-
return tdProps;
|
|
3187
|
-
};
|
|
3188
|
-
const getTrProps = ({ hoveredRow, index, }) => {
|
|
3189
|
-
if (hoveredRow === -1) {
|
|
3190
|
-
return {};
|
|
3191
|
-
}
|
|
3192
|
-
if (hoveredRow === index) {
|
|
3193
|
-
return {
|
|
3194
|
-
opacity: '1',
|
|
3195
|
-
};
|
|
3196
|
-
}
|
|
3197
|
-
return {
|
|
3198
|
-
opacity: '0.8',
|
|
3199
|
-
};
|
|
3200
|
-
};
|
|
3201
|
-
// Get the number of skeleton rows based on current pageSize
|
|
3202
|
-
const pageSize = table.getState().pagination.pageSize;
|
|
3203
|
-
const visibleColumns = table.getVisibleLeafColumns();
|
|
3204
|
-
return (jsx(Table$1.Body, { children: Array.from({ length: pageSize }).map((_, rowIndex) => {
|
|
3205
|
-
return (jsxs(Table$1.Row, { display: 'flex', zIndex: 1, onMouseEnter: () => handleRowHover(rowIndex), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index: rowIndex }), children: [showSelector && jsx(TableRowSelectorSkeleton, {}), visibleColumns.map((column, colIndex) => {
|
|
3206
|
-
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
|
|
3207
|
-
// styling resize and pinning start
|
|
3208
|
-
flex: `${canResize ? '0' : '1'} 0 ${column.getSize()}px`,
|
|
3209
|
-
// this is to avoid the cell from being too wide
|
|
3210
|
-
minWidth: `0`, color: {
|
|
3211
|
-
base: 'colorPalette.900',
|
|
3212
|
-
_dark: 'colorPalette.100',
|
|
3213
|
-
},
|
|
3214
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...getTdProps(column), children: jsx(Skeleton, { height: "20px", width: "80%" }) }, `chakra-table-skeleton-cell-${rowIndex}-${colIndex}`));
|
|
3215
|
-
})] }, `chakra-table-skeleton-row-${rowIndex}`));
|
|
3216
|
-
}) }));
|
|
3217
|
-
};
|
|
3218
|
-
const TableRowSelectorSkeleton = () => {
|
|
3219
|
-
const { table } = useDataTableContext();
|
|
3220
|
-
const SELECTION_BOX_WIDTH = 20;
|
|
3221
|
-
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid', color: {
|
|
3222
|
-
base: 'colorPalette.900',
|
|
3223
|
-
_dark: 'colorPalette.100',
|
|
3224
|
-
},
|
|
3225
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsx(Skeleton, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }) }));
|
|
3226
|
-
};
|
|
3227
|
-
|
|
3228
|
-
const TableFooter = ({ showSelector = false, alwaysShowSelector = true, }) => {
|
|
3229
|
-
const table = useDataTableContext().table;
|
|
3230
|
-
const SELECTION_BOX_WIDTH = 20;
|
|
3231
|
-
const [hoveredCheckBox, setHoveredCheckBox] = useState(false);
|
|
3232
|
-
const handleRowHover = (isHovered) => {
|
|
3233
|
-
setHoveredCheckBox(isHovered);
|
|
3234
|
-
};
|
|
3235
|
-
const isCheckBoxVisible = () => {
|
|
3236
|
-
if (alwaysShowSelector) {
|
|
3237
|
-
return true;
|
|
3238
|
-
}
|
|
3239
|
-
if (table.getIsAllRowsSelected()) {
|
|
3240
|
-
return true;
|
|
3241
|
-
}
|
|
3242
|
-
if (hoveredCheckBox) {
|
|
3243
|
-
return true;
|
|
3244
|
-
}
|
|
3245
|
-
return false;
|
|
3246
|
-
};
|
|
3247
|
-
return (jsx(Table$1.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxs(Table$1.Row, { display: "flex", children: [showSelector && (jsxs(Table$1.Header, { padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
|
|
3248
|
-
// indeterminate: table.getIsSomeRowsSelected(),
|
|
3249
|
-
onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsx(Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }))] })), footerGroup.headers.map((header) => (jsx(Table$1.Cell, { padding: "0", columnSpan: `${header.colSpan}`,
|
|
3250
|
-
// styling resize and pinning start
|
|
3251
|
-
maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid", children: jsx(MenuRoot$1, { children: jsx(MenuTrigger$1, { asChild: true, children: jsx(Box, { padding: `${table.getDensityValue()}px`, display: "flex", alignItems: "center", justifyContent: "start", borderRadius: "0rem", children: jsxs(Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
|
|
3252
|
-
? null
|
|
3253
|
-
: flexRender(header.column.columnDef.footer, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && jsx(Fragment, {}), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
|
|
3254
|
-
};
|
|
3255
|
-
|
|
3256
|
-
// Default text values
|
|
3257
|
-
const DEFAULT_HEADER_TEXTS = {
|
|
3258
|
-
pinColumn: "Pin Column",
|
|
3259
|
-
cancelPin: "Cancel Pin",
|
|
3260
|
-
sortAscending: "Sort Ascending",
|
|
3261
|
-
sortDescending: "Sort Descending",
|
|
3262
|
-
clearSorting: "Clear Sorting",
|
|
3263
|
-
};
|
|
3264
|
-
/**
|
|
3265
|
-
* TableHeader component with configurable text strings.
|
|
3266
|
-
*
|
|
3267
|
-
* @example
|
|
3268
|
-
* // Using default texts
|
|
3269
|
-
* <TableHeader />
|
|
3270
|
-
*
|
|
3271
|
-
* @example
|
|
3272
|
-
* // Customizing default texts for all columns
|
|
3273
|
-
* <TableHeader
|
|
3274
|
-
* defaultTexts={{
|
|
3275
|
-
* pinColumn: "Pin This Column",
|
|
3276
|
-
* sortAscending: "Sort A-Z"
|
|
3277
|
-
* }}
|
|
3278
|
-
* />
|
|
3279
|
-
*
|
|
3280
|
-
* @example
|
|
3281
|
-
* // Customizing texts per column via meta
|
|
3282
|
-
* const columns = [
|
|
3283
|
-
* columnHelper.accessor("name", {
|
|
3284
|
-
* header: "Name",
|
|
3285
|
-
* meta: {
|
|
3286
|
-
* headerTexts: {
|
|
3287
|
-
* pinColumn: "Pin Name Column",
|
|
3288
|
-
* sortAscending: "Sort Names A-Z"
|
|
3289
|
-
* }
|
|
3290
|
-
* }
|
|
3291
|
-
* })
|
|
3292
|
-
* ];
|
|
3293
|
-
*/
|
|
3294
|
-
const TableHeader = ({ canResize = true, showSelector = false, isSticky = true, tableHeaderProps = {}, tableRowProps = {}, defaultTexts = {}, }) => {
|
|
3295
|
-
const { table } = useDataTableContext();
|
|
3296
|
-
const SELECTION_BOX_WIDTH = 20;
|
|
3297
|
-
// Merge default texts with provided defaults
|
|
3298
|
-
const mergedDefaultTexts = { ...DEFAULT_HEADER_TEXTS, ...defaultTexts };
|
|
3299
|
-
// Helper function to get text for a specific header
|
|
3300
|
-
const getHeaderText = (header, key) => {
|
|
3301
|
-
const columnMeta = header.column.columnDef.meta;
|
|
3302
|
-
return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
|
|
3303
|
-
};
|
|
3304
|
-
const getThProps = (header) => {
|
|
3305
|
-
const thProps = header.column.getIsPinned()
|
|
3306
|
-
? {
|
|
3307
|
-
left: showSelector
|
|
3308
|
-
? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3309
|
-
: `${header.getStart("left")}px`,
|
|
3310
|
-
position: "sticky",
|
|
3311
|
-
zIndex: 100 + 1,
|
|
3312
|
-
}
|
|
3313
|
-
: {};
|
|
3314
|
-
return thProps;
|
|
3051
|
+
return thProps;
|
|
3315
3052
|
};
|
|
3316
3053
|
const stickyProps = {
|
|
3317
3054
|
position: "sticky",
|
|
@@ -3386,89 +3123,11 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3386
3123
|
})] }, `chakra-table-headergroup-${headerGroup.id}`))) }));
|
|
3387
3124
|
};
|
|
3388
3125
|
|
|
3389
|
-
const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = '', isLoading = false, }) => {
|
|
3390
|
-
if (variant === 'greedy') {
|
|
3391
|
-
const bodyComponent = isLoading ? (jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: false })) : (jsx(TableBody, { ...tableBodyProps, canResize: false, ...tableBodyProps }));
|
|
3392
|
-
return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { canResize: false, showLoading: isLoading, ...tableProps, children: [jsx(TableHeader, { canResize: false, ...tableHeaderProps }), bodyComponent, showFooter && (jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
|
|
3393
|
-
}
|
|
3394
|
-
const bodyComponent = isLoading ? (jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: tableBodyProps.canResize })) : (jsx(TableBody, { ...tableBodyProps }));
|
|
3395
|
-
return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { showLoading: isLoading, ...tableProps, children: [jsx(TableHeader, { ...tableHeaderProps }), bodyComponent, showFooter && jsx(TableFooter, { ...tableFooterProps })] }) }));
|
|
3396
|
-
};
|
|
3397
|
-
|
|
3398
|
-
/**
|
|
3399
|
-
* DefaultTableServer is a wrapper around DefaultTable that automatically
|
|
3400
|
-
* detects server-side loading state from DataTableServerContext.
|
|
3401
|
-
*
|
|
3402
|
-
* Use this component when working with DataTableServer to automatically
|
|
3403
|
-
* show skeleton loading state during data fetching.
|
|
3404
|
-
*
|
|
3405
|
-
* @example
|
|
3406
|
-
* ```tsx
|
|
3407
|
-
* <DataTableServer columns={columns} {...datatableServer}>
|
|
3408
|
-
* <DefaultTableServer />
|
|
3409
|
-
* </DataTableServer>
|
|
3410
|
-
* ```
|
|
3411
|
-
*/
|
|
3412
|
-
const DefaultTableServer = ({ isLoading: isLoadingOverride, ...props }) => {
|
|
3413
|
-
// Automatically detect loading state from server context
|
|
3414
|
-
const serverContext = useDataTableServerContext();
|
|
3415
|
-
const isLoading = isLoadingOverride ?? serverContext?.query?.isLoading ?? false;
|
|
3416
|
-
return jsx(DefaultTable, { ...props, isLoading: isLoading });
|
|
3417
|
-
};
|
|
3418
|
-
|
|
3419
|
-
const TableCardContainer = ({ children, variant = "", gap = "1rem", gridTemplateColumns = "repeat(auto-fit, minmax(20rem, 1fr))", direction = "row", ...props }) => {
|
|
3420
|
-
if (variant === "carousel") {
|
|
3421
|
-
return (jsx(Flex, { overflow: "auto", gap: gap, direction: direction, ...props, children: children }));
|
|
3422
|
-
}
|
|
3423
|
-
return (jsx(Grid, { gridTemplateColumns: gridTemplateColumns, gap: gap, ...props, children: children }));
|
|
3424
|
-
};
|
|
3425
|
-
|
|
3426
|
-
const DefaultCardTitle = () => {
|
|
3427
|
-
return jsx(Fragment, {});
|
|
3428
|
-
};
|
|
3429
|
-
const TableCards = ({ isSelectable = false, showDisplayNameOnly = false, renderTitle = DefaultCardTitle, cardBodyProps = {}, }) => {
|
|
3430
|
-
const { table } = useDataTableContext();
|
|
3431
|
-
return (jsx(Fragment, { children: table.getRowModel().rows.map((row) => {
|
|
3432
|
-
return (jsx(Card.Root, { flex: "1 0 20rem", children: jsxs(Card.Body, { display: "flex", flexFlow: "column", gap: "0.5rem", ...cardBodyProps, children: [isSelectable && (jsx(Checkbox, { isChecked: row.getIsSelected(),
|
|
3433
|
-
disabled: !row.getCanSelect(),
|
|
3434
|
-
// indeterminate: row.getIsSomeSelected(),
|
|
3435
|
-
onChange: row.getToggleSelectedHandler() })), renderTitle(row), jsx(Grid, { templateColumns: "auto 1fr", gap: "1rem", children: row.getVisibleCells().map((cell) => {
|
|
3436
|
-
return (jsxs(Fragment, { children: [jsxs(Box, { children: [showDisplayNameOnly && (jsx(Text, { fontWeight: "bold", children: cell.column.columnDef.meta?.displayName ??
|
|
3437
|
-
cell.column.id })), !showDisplayNameOnly && (jsx(Fragment, { children: flexRender(cell.column.columnDef.header,
|
|
3438
|
-
// @ts-expect-error Assuming the CellContext interface is the same as HeaderContext
|
|
3439
|
-
cell.getContext()) }))] }, `chakra-table-cardcolumnid-${row.id}`), jsx(Box, { justifySelf: "end", children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-cardcolumn-${row.id}`)] }));
|
|
3440
|
-
}) })] }) }, `chakra-table-card-${row.id}`));
|
|
3441
|
-
}) }));
|
|
3442
|
-
};
|
|
3443
|
-
|
|
3444
|
-
const TableComponent = ({ render = () => {
|
|
3445
|
-
throw Error("Not Implemented");
|
|
3446
|
-
}, }) => {
|
|
3447
|
-
const { table } = useDataTableContext();
|
|
3448
|
-
return render(table);
|
|
3449
|
-
};
|
|
3450
|
-
|
|
3451
3126
|
const TableLoadingComponent = ({ render, }) => {
|
|
3452
3127
|
const { query } = useDataTableServerContext();
|
|
3453
3128
|
return jsx(Fragment, { children: render(query.isLoading) });
|
|
3454
3129
|
};
|
|
3455
3130
|
|
|
3456
|
-
const SelectAllRowsToggle = ({ selectAllIcon = jsx(MdOutlineChecklist, {}), clearAllIcon = jsx(MdClear, {}), selectAllText = "", clearAllText = "", }) => {
|
|
3457
|
-
const { table } = useDataTableContext();
|
|
3458
|
-
return (jsxs(Fragment, { children: [!!selectAllText === false && (jsx(IconButton, { variant: "ghost", "aria-label": table.getIsAllRowsSelected() ? clearAllText : selectAllText, onClick: (event) => {
|
|
3459
|
-
table.getToggleAllRowsSelectedHandler()(event);
|
|
3460
|
-
}, children: table.getIsAllRowsSelected() ? clearAllIcon : selectAllIcon })), !!selectAllText !== false && (jsxs(Button$1, { variant: "ghost", onClick: (event) => {
|
|
3461
|
-
table.getToggleAllRowsSelectedHandler()(event);
|
|
3462
|
-
}, children: [table.getIsAllRowsSelected() ? clearAllIcon : selectAllIcon, table.getIsAllRowsSelected() ? clearAllText : selectAllText] }))] }));
|
|
3463
|
-
};
|
|
3464
|
-
|
|
3465
|
-
const TableSelector = () => {
|
|
3466
|
-
const { table } = useDataTableContext();
|
|
3467
|
-
return (jsxs(Fragment, { children: [table.getSelectedRowModel().rows.length > 0 && (jsxs(Button$1, { onClick: () => { }, variant: "ghost", display: "flex", gap: "0.25rem", children: [jsx(Box, { fontSize: "sm", children: `${table.getSelectedRowModel().rows.length}` }), jsx(IoMdCheckbox, {})] })), !table.getIsAllPageRowsSelected() && jsx(SelectAllRowsToggle, {}), table.getSelectedRowModel().rows.length > 0 && (jsx(IconButton, { variant: "ghost", onClick: () => {
|
|
3468
|
-
table.resetRowSelection();
|
|
3469
|
-
}, "aria-label": "reset selection", children: jsx(MdClear, {}) }))] }));
|
|
3470
|
-
};
|
|
3471
|
-
|
|
3472
3131
|
const TextCell = ({ label, containerProps = {}, textProps = {}, children, }) => {
|
|
3473
3132
|
if (label) {
|
|
3474
3133
|
return (jsx(Flex, { alignItems: "center", height: "100%", ...containerProps, children: jsx(Tooltip, { content: jsx(Text, { as: "span", overflow: "hidden", textOverflow: "ellipsis", children: label }), children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: "ellipsis", wordBreak: "break-all", ...textProps, children: children }) }) }));
|
|
@@ -3476,7 +3135,26 @@ const TextCell = ({ label, containerProps = {}, textProps = {}, children, }) =>
|
|
|
3476
3135
|
return (jsx(Flex, { alignItems: "center", height: "100%", ...containerProps, children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: "ellipsis", wordBreak: "break-all", ...textProps, children: children }) }));
|
|
3477
3136
|
};
|
|
3478
3137
|
|
|
3479
|
-
const
|
|
3138
|
+
const CardHeader = ({ row, imageColumnId = undefined, titleColumnId = undefined, tagColumnId = undefined, tagIcon = undefined, showTag = true, imageProps = {}, }) => {
|
|
3139
|
+
if (!!row.original === false) {
|
|
3140
|
+
return jsx(Fragment, {});
|
|
3141
|
+
}
|
|
3142
|
+
const isShowFirstColumn = !!titleColumnId || showTag;
|
|
3143
|
+
return (jsxs(Grid, { templateRows: "auto auto", gap: "1rem", children: [!!imageColumnId && (jsx(Image, { width: "100%", src: row.original[imageColumnId], ...imageProps })), isShowFirstColumn && (jsxs(Flex, { gap: "0.5rem", flexFlow: "wrap", children: [!!titleColumnId && (jsx(Text, { fontWeight: "bold", fontSize: "large", children: row.original[titleColumnId] })), showTag && (jsx(Tag, { fontSize: "large", startElement: tagIcon && tagIcon({}), children: row.original[tagColumnId] }))] }))] }));
|
|
3144
|
+
};
|
|
3145
|
+
|
|
3146
|
+
const EmptyState = ({ title = "No records", description = "Add a new events to get started or refine your search", }) => {
|
|
3147
|
+
const { isEmpty } = useDataTableServerContext();
|
|
3148
|
+
return (jsx(Fragment, { children: isEmpty && (jsx(EmptyState$2.Root, { children: jsxs(EmptyState$2.Content, { children: [jsx(EmptyState$2.Indicator, { children: jsx(HiColorSwatch, {}) }), jsxs(VStack, { textAlign: "center", children: [jsx(EmptyState$2.Title, { children: title }), jsx(EmptyState$2.Description, { children: description })] })] }) })) }));
|
|
3149
|
+
};
|
|
3150
|
+
|
|
3151
|
+
const ErrorAlert = ({ showMessage = true }) => {
|
|
3152
|
+
const { query } = useDataTableServerContext();
|
|
3153
|
+
const { isError, error } = query;
|
|
3154
|
+
return (jsx(Fragment, { children: isError && (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: error.name }), showMessage && (jsx(Alert.Description, { children: error.message }))] })] })) }));
|
|
3155
|
+
};
|
|
3156
|
+
|
|
3157
|
+
const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: defaultPagination = {
|
|
3480
3158
|
pageIndex: 0, //initial page index
|
|
3481
3159
|
pageSize: 10, //default page size
|
|
3482
3160
|
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = "", density: defaultDensity = "sm", } = {
|
|
@@ -3605,6 +3283,28 @@ const idListSanityCheck = (param, idList, properties) => {
|
|
|
3605
3283
|
}
|
|
3606
3284
|
};
|
|
3607
3285
|
|
|
3286
|
+
const snakeToLabel = (str) => {
|
|
3287
|
+
return str
|
|
3288
|
+
.split("_") // Split by underscore
|
|
3289
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
|
|
3290
|
+
.join(" "); // Join with space
|
|
3291
|
+
};
|
|
3292
|
+
|
|
3293
|
+
const RecordDisplay = ({ object, boxProps, translate, prefix = "", }) => {
|
|
3294
|
+
const getColumn = ({ field }) => {
|
|
3295
|
+
if (translate !== undefined) {
|
|
3296
|
+
return translate.t(`${prefix}${field}`);
|
|
3297
|
+
}
|
|
3298
|
+
return snakeToLabel(field);
|
|
3299
|
+
};
|
|
3300
|
+
if (object === null) {
|
|
3301
|
+
return jsx(Fragment, { children: "null" });
|
|
3302
|
+
}
|
|
3303
|
+
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
|
|
3304
|
+
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "colorPalette.400", children: getColumn({ field }) }), typeof value === "object" ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsx(Text, { children: JSON.stringify(value) }))] }, field));
|
|
3305
|
+
}) }));
|
|
3306
|
+
};
|
|
3307
|
+
|
|
3608
3308
|
const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
3609
3309
|
const widthListToolong = widthList.length > Object.keys(properties).length;
|
|
3610
3310
|
if (widthListToolong) {
|
|
@@ -3662,70 +3362,6 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
|
|
|
3662
3362
|
return columns;
|
|
3663
3363
|
};
|
|
3664
3364
|
|
|
3665
|
-
const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
3666
|
-
const { columns, translate, data } = useDataTableContext();
|
|
3667
|
-
const columnsMap = Object.fromEntries(columns.map((def) => {
|
|
3668
|
-
const { accessorKey, id } = def;
|
|
3669
|
-
if (accessorKey) {
|
|
3670
|
-
return [accessorKey, def];
|
|
3671
|
-
}
|
|
3672
|
-
return [id, def];
|
|
3673
|
-
}));
|
|
3674
|
-
const columnHeaders = Object.keys(columnsMap);
|
|
3675
|
-
const totalWidths = columns
|
|
3676
|
-
.map(({ size }) => {
|
|
3677
|
-
if (!!size === false) {
|
|
3678
|
-
return 0;
|
|
3679
|
-
}
|
|
3680
|
-
if (typeof size === "number") {
|
|
3681
|
-
return size;
|
|
3682
|
-
}
|
|
3683
|
-
return 0;
|
|
3684
|
-
})
|
|
3685
|
-
.reduce((previous, current) => previous + current, 0);
|
|
3686
|
-
const columnWidths = columns
|
|
3687
|
-
.map(({ size }) => {
|
|
3688
|
-
if (!!size === false) {
|
|
3689
|
-
return "1fr";
|
|
3690
|
-
}
|
|
3691
|
-
return `minmax(${size}px, ${(size / totalWidths) * 100}%)`;
|
|
3692
|
-
})
|
|
3693
|
-
.join(" ");
|
|
3694
|
-
console.log({ columnWidths }, "hadfg");
|
|
3695
|
-
const cellProps = {
|
|
3696
|
-
flex: "1 0 0%",
|
|
3697
|
-
overflow: "auto",
|
|
3698
|
-
paddingX: "2",
|
|
3699
|
-
py: "1",
|
|
3700
|
-
color: { base: "colorPalette.900", _dark: "colorPalette.100" },
|
|
3701
|
-
bgColor: { base: "colorPalette.50", _dark: "colorPalette.950" },
|
|
3702
|
-
borderBottomColor: { base: "colorPalette.200", _dark: "colorPalette.800" },
|
|
3703
|
-
borderBottomWidth: "1px",
|
|
3704
|
-
...{ colorPalette },
|
|
3705
|
-
};
|
|
3706
|
-
if (data.length <= 0) {
|
|
3707
|
-
return jsx(Fragment, { children: emptyComponent });
|
|
3708
|
-
}
|
|
3709
|
-
return (jsxs(Grid, { templateColumns: `${columnWidths}`, overflow: "auto", borderWidth: "1px", color: { base: "colorPalette.900", _dark: "colorPalette.100" }, borderColor: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: [jsx(Grid, { templateColumns: `${columnWidths}`, column: `1/span ${columns.length}`, bg: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: columnHeaders.map((header) => {
|
|
3710
|
-
return (jsx(Box, { flex: "1 0 0%", paddingX: "2", py: "1", overflow: "auto", textOverflow: "ellipsis", children: translate.t(`column_header.${header}`) }));
|
|
3711
|
-
}) }), data.map((record) => {
|
|
3712
|
-
return (jsx(Fragment, { children: columnHeaders.map((header) => {
|
|
3713
|
-
const { cell } = columnsMap[header];
|
|
3714
|
-
const value = record[header];
|
|
3715
|
-
if (!!record === false) {
|
|
3716
|
-
return (jsx(Box, { ...cellProps, children: translate.t(`column_cell.placeholder`) }));
|
|
3717
|
-
}
|
|
3718
|
-
if (cell) {
|
|
3719
|
-
return (jsx(Box, { ...cellProps, children: cell({ row: { original: record } }) }));
|
|
3720
|
-
}
|
|
3721
|
-
if (typeof value === "object") {
|
|
3722
|
-
return (jsx(Box, { ...cellProps, children: jsx(RecordDisplay, { object: value }) }));
|
|
3723
|
-
}
|
|
3724
|
-
return jsx(Box, { ...cellProps, children: value });
|
|
3725
|
-
}) }));
|
|
3726
|
-
})] }));
|
|
3727
|
-
};
|
|
3728
|
-
|
|
3729
3365
|
//@ts-expect-error TODO: find appropriate type
|
|
3730
3366
|
const SchemaFormContext = createContext({
|
|
3731
3367
|
schema: {},
|
|
@@ -4988,10 +4624,13 @@ function formatBytes(bytes) {
|
|
|
4988
4624
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
4989
4625
|
}
|
|
4990
4626
|
|
|
4991
|
-
|
|
4627
|
+
const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, enabled = true, multiple = false, onFileSelect, selectedFileId: controlledSelectedFileId, onSelectedFileIdChange, }) => {
|
|
4992
4628
|
const [searchTerm, setSearchTerm] = useState('');
|
|
4993
|
-
const [
|
|
4629
|
+
const [internalSelectedFileId, setInternalSelectedFileId] = useState(multiple ? [] : '');
|
|
4994
4630
|
const [failedImageIds, setFailedImageIds] = useState(new Set());
|
|
4631
|
+
// Use controlled or internal state for selectedFileId
|
|
4632
|
+
const selectedFileId = controlledSelectedFileId ?? internalSelectedFileId;
|
|
4633
|
+
const setSelectedFileId = onSelectedFileIdChange ?? setInternalSelectedFileId;
|
|
4995
4634
|
const { data: filesData, isLoading, isError, } = useQuery({
|
|
4996
4635
|
queryKey: ['file-picker-library', searchTerm],
|
|
4997
4636
|
queryFn: async () => {
|
|
@@ -5000,91 +4639,176 @@ function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = fa
|
|
|
5000
4639
|
const files = await onFetchFiles(searchTerm.trim() || '');
|
|
5001
4640
|
return { data: files };
|
|
5002
4641
|
},
|
|
5003
|
-
enabled:
|
|
4642
|
+
enabled: enabled && !!onFetchFiles,
|
|
5004
4643
|
});
|
|
5005
4644
|
const files = (filesData?.data || []);
|
|
5006
4645
|
const filteredFiles = filterImageOnly
|
|
5007
4646
|
? files.filter((file) => /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name))
|
|
5008
4647
|
: files;
|
|
4648
|
+
const handleFileClick = (fileId) => {
|
|
4649
|
+
if (multiple) {
|
|
4650
|
+
const currentSelection = Array.isArray(selectedFileId)
|
|
4651
|
+
? selectedFileId
|
|
4652
|
+
: [];
|
|
4653
|
+
const newSelection = currentSelection.includes(fileId)
|
|
4654
|
+
? currentSelection.filter((id) => id !== fileId)
|
|
4655
|
+
: [...currentSelection, fileId];
|
|
4656
|
+
setSelectedFileId(newSelection);
|
|
4657
|
+
if (onFileSelect) {
|
|
4658
|
+
onFileSelect(newSelection);
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
else {
|
|
4662
|
+
setSelectedFileId(fileId);
|
|
4663
|
+
if (onFileSelect) {
|
|
4664
|
+
onFileSelect(fileId);
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
};
|
|
4668
|
+
const handleImageError = (fileId) => {
|
|
4669
|
+
setFailedImageIds((prev) => new Set(prev).add(fileId));
|
|
4670
|
+
};
|
|
4671
|
+
if (!onFetchFiles)
|
|
4672
|
+
return null;
|
|
4673
|
+
return (jsxs(VStack, { align: "stretch", gap: 4, children: [jsxs(Box, { position: "relative", children: [jsx(Input, { placeholder: labels?.searchPlaceholder ?? 'Search files...', value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), bg: "bg.panel", border: "1px solid", borderColor: "border.default", colorPalette: "blue", _focus: {
|
|
4674
|
+
borderColor: 'colorPalette.500',
|
|
4675
|
+
_dark: {
|
|
4676
|
+
borderColor: 'colorPalette.400',
|
|
4677
|
+
},
|
|
4678
|
+
boxShadow: {
|
|
4679
|
+
base: '0 0 0 1px var(--chakra-colors-blue-500)',
|
|
4680
|
+
_dark: '0 0 0 1px var(--chakra-colors-blue-400)',
|
|
4681
|
+
},
|
|
4682
|
+
}, pl: 10 }), jsx(Icon, { as: LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxs(Box, { textAlign: "center", py: 8, children: [jsx(Spinner, { size: "lg", colorPalette: "blue" }), jsx(Text, { mt: 4, color: "fg.muted", children: labels?.loading ?? 'Loading files...' })] })), isError && (jsx(Box, { bg: { base: 'colorPalette.50', _dark: 'colorPalette.900/20' }, border: "1px solid", borderColor: {
|
|
4683
|
+
base: 'colorPalette.200',
|
|
4684
|
+
_dark: 'colorPalette.800',
|
|
4685
|
+
}, colorPalette: "red", borderRadius: "md", p: 4, children: jsx(Text, { color: {
|
|
4686
|
+
base: 'colorPalette.600',
|
|
4687
|
+
_dark: 'colorPalette.300',
|
|
4688
|
+
}, children: labels?.loadingFailed ?? 'Failed to load files' }) })), !isLoading && !isError && (jsx(Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsx(Box, { textAlign: "center", py: 8, children: jsx(Text, { color: "fg.muted", children: labels?.noFilesFound ?? 'No files found' }) })) : (jsx(VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
|
|
4689
|
+
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
|
|
4690
|
+
const isSelected = multiple
|
|
4691
|
+
? Array.isArray(selectedFileId) &&
|
|
4692
|
+
selectedFileId.includes(file.id)
|
|
4693
|
+
: selectedFileId === file.id;
|
|
4694
|
+
const imageFailed = failedImageIds.has(file.id);
|
|
4695
|
+
return (jsx(Box, { p: 3, border: "2px solid", borderColor: isSelected
|
|
4696
|
+
? {
|
|
4697
|
+
base: 'colorPalette.500',
|
|
4698
|
+
_dark: 'colorPalette.400',
|
|
4699
|
+
}
|
|
4700
|
+
: 'border.default', borderRadius: "md", bg: isSelected
|
|
4701
|
+
? {
|
|
4702
|
+
base: 'colorPalette.50',
|
|
4703
|
+
_dark: 'colorPalette.900/20',
|
|
4704
|
+
}
|
|
4705
|
+
: 'bg.panel', colorPalette: "blue", cursor: "pointer", onClick: () => handleFileClick(file.id), _hover: {
|
|
4706
|
+
borderColor: isSelected
|
|
4707
|
+
? {
|
|
4708
|
+
base: 'colorPalette.600',
|
|
4709
|
+
_dark: 'colorPalette.400',
|
|
4710
|
+
}
|
|
4711
|
+
: {
|
|
4712
|
+
base: 'colorPalette.300',
|
|
4713
|
+
_dark: 'colorPalette.400',
|
|
4714
|
+
},
|
|
4715
|
+
bg: isSelected
|
|
4716
|
+
? {
|
|
4717
|
+
base: 'colorPalette.100',
|
|
4718
|
+
_dark: 'colorPalette.800/30',
|
|
4719
|
+
}
|
|
4720
|
+
: 'bg.muted',
|
|
4721
|
+
}, transition: "all 0.2s", children: jsxs(HStack, { gap: 3, children: [jsx(Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url && !imageFailed ? (jsx(Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md", onError: () => handleImageError(file.id) })) : isImage && (imageFailed || !file.url) ? (jsx(Icon, { as: LuImage, boxSize: 6, color: "fg.muted" })) : (jsx(Icon, { as: LuFile, boxSize: 6, color: "fg.muted" })) }), jsxs(VStack, { align: "start", flex: 1, gap: 1, children: [jsx(Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxs(HStack, { gap: 2, children: [file.size && (jsx(Fragment, { children: jsx(Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
|
|
4722
|
+
? formatBytes(file.size)
|
|
4723
|
+
: file.size }) })), file.comment && (jsxs(Fragment, { children: [file.size && (jsx(Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsx(Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsx(Box, { width: "24px", height: "24px", borderRadius: "full", bg: {
|
|
4724
|
+
base: 'colorPalette.500',
|
|
4725
|
+
_dark: 'colorPalette.400',
|
|
4726
|
+
}, colorPalette: "blue", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsx(Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
|
|
4727
|
+
}) })) }))] }));
|
|
4728
|
+
};
|
|
4729
|
+
|
|
4730
|
+
function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, translate, colLabel, }) {
|
|
4731
|
+
const [selectedFileId, setSelectedFileId] = useState('');
|
|
4732
|
+
const [activeTab, setActiveTab] = useState('browse');
|
|
4733
|
+
const [uploadingFiles, setUploadingFiles] = useState(new Set());
|
|
4734
|
+
const [uploadErrors, setUploadErrors] = useState(new Map());
|
|
5009
4735
|
const handleSelect = () => {
|
|
5010
4736
|
if (selectedFileId) {
|
|
5011
4737
|
onSelect(selectedFileId);
|
|
5012
4738
|
onClose();
|
|
5013
4739
|
setSelectedFileId('');
|
|
5014
|
-
|
|
4740
|
+
setActiveTab('browse');
|
|
5015
4741
|
}
|
|
5016
4742
|
};
|
|
5017
4743
|
const handleClose = () => {
|
|
5018
4744
|
onClose();
|
|
5019
4745
|
setSelectedFileId('');
|
|
5020
|
-
|
|
5021
|
-
|
|
4746
|
+
setActiveTab('browse');
|
|
4747
|
+
setUploadingFiles(new Set());
|
|
4748
|
+
setUploadErrors(new Map());
|
|
5022
4749
|
};
|
|
5023
|
-
const
|
|
5024
|
-
|
|
4750
|
+
const handleFileUpload = async (files) => {
|
|
4751
|
+
if (!onUploadFile)
|
|
4752
|
+
return;
|
|
4753
|
+
for (const file of files) {
|
|
4754
|
+
const fileKey = `${file.name}-${file.size}`;
|
|
4755
|
+
setUploadingFiles((prev) => new Set(prev).add(fileKey));
|
|
4756
|
+
setUploadErrors((prev) => {
|
|
4757
|
+
const newMap = new Map(prev);
|
|
4758
|
+
newMap.delete(fileKey);
|
|
4759
|
+
return newMap;
|
|
4760
|
+
});
|
|
4761
|
+
try {
|
|
4762
|
+
const fileId = await onUploadFile(file);
|
|
4763
|
+
setSelectedFileId(fileId);
|
|
4764
|
+
setUploadingFiles((prev) => {
|
|
4765
|
+
const newSet = new Set(prev);
|
|
4766
|
+
newSet.delete(fileKey);
|
|
4767
|
+
return newSet;
|
|
4768
|
+
});
|
|
4769
|
+
// Auto-select and close in single-select mode
|
|
4770
|
+
onSelect(fileId);
|
|
4771
|
+
onClose();
|
|
4772
|
+
setSelectedFileId('');
|
|
4773
|
+
setActiveTab('browse');
|
|
4774
|
+
}
|
|
4775
|
+
catch (error) {
|
|
4776
|
+
setUploadingFiles((prev) => {
|
|
4777
|
+
const newSet = new Set(prev);
|
|
4778
|
+
newSet.delete(fileKey);
|
|
4779
|
+
return newSet;
|
|
4780
|
+
});
|
|
4781
|
+
setUploadErrors((prev) => {
|
|
4782
|
+
const newMap = new Map(prev);
|
|
4783
|
+
newMap.set(fileKey, error instanceof Error ? error.message : 'Upload failed');
|
|
4784
|
+
return newMap;
|
|
4785
|
+
});
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
5025
4788
|
};
|
|
5026
|
-
|
|
4789
|
+
const showTabs = enableUpload && !!onUploadFile && !!onFetchFiles;
|
|
4790
|
+
if (!onFetchFiles && !onUploadFile)
|
|
5027
4791
|
return null;
|
|
5028
|
-
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: jsxs(
|
|
5029
|
-
translate(removeIndex(`${colLabel}.
|
|
5030
|
-
'
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
_dark: '0 0 0 1px var(--chakra-colors-blue-400)',
|
|
5038
|
-
},
|
|
5039
|
-
}, pl: 10 }), jsx(Icon, { as: LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxs(Box, { textAlign: "center", py: 8, children: [jsx(Spinner, { size: "lg", colorPalette: "blue" }), jsx(Text, { mt: 4, color: "fg.muted", children: labels?.loading ??
|
|
5040
|
-
translate(removeIndex(`${colLabel}.loading`)) ??
|
|
5041
|
-
'Loading files...' })] })), isError && (jsx(Box, { bg: { base: 'colorPalette.50', _dark: 'colorPalette.900/20' }, border: "1px solid", borderColor: {
|
|
5042
|
-
base: 'colorPalette.200',
|
|
5043
|
-
_dark: 'colorPalette.800',
|
|
5044
|
-
}, colorPalette: "red", borderRadius: "md", p: 4, children: jsx(Text, { color: {
|
|
5045
|
-
base: 'colorPalette.600',
|
|
5046
|
-
_dark: 'colorPalette.300',
|
|
5047
|
-
}, children: labels?.loadingFailed ??
|
|
5048
|
-
translate(removeIndex(`${colLabel}.error.loading_failed`)) ??
|
|
5049
|
-
'Failed to load files' }) })), !isLoading && !isError && (jsx(Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsx(Box, { textAlign: "center", py: 8, children: jsx(Text, { color: "fg.muted", children: labels?.noFilesFound ??
|
|
5050
|
-
translate(removeIndex(`${colLabel}.no_files_found`)) ??
|
|
5051
|
-
'No files found' }) })) : (jsx(VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
|
|
5052
|
-
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
|
|
5053
|
-
const isSelected = selectedFileId === file.id;
|
|
5054
|
-
const imageFailed = failedImageIds.has(file.id);
|
|
5055
|
-
return (jsx(Box, { p: 3, border: "2px solid", borderColor: isSelected
|
|
5056
|
-
? {
|
|
5057
|
-
base: 'colorPalette.500',
|
|
5058
|
-
_dark: 'colorPalette.400',
|
|
5059
|
-
}
|
|
5060
|
-
: 'border.default', borderRadius: "md", bg: isSelected
|
|
5061
|
-
? {
|
|
4792
|
+
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 ??
|
|
4793
|
+
translate(removeIndex(`${colLabel}.browse_tab`)) ??
|
|
4794
|
+
'Browse Library' }), jsx(Tabs.Trigger, { value: "upload", children: labels?.uploadTab ??
|
|
4795
|
+
translate(removeIndex(`${colLabel}.upload_tab`)) ??
|
|
4796
|
+
'Upload Files' })] }), jsx(Tabs.Content, { value: "browse", children: onFetchFiles && (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFileId: selectedFileId, onSelectedFileIdChange: setSelectedFileId })) }), jsx(Tabs.Content, { value: "upload", children: jsxs(VStack, { align: "stretch", gap: 4, children: [jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
4797
|
+
translate(removeIndex(`${colLabel}.fileDropzone`)) ??
|
|
4798
|
+
'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 ??
|
|
4799
|
+
translate(removeIndex(`${colLabel}.uploading`)) ??
|
|
4800
|
+
'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: {
|
|
5062
4801
|
base: 'colorPalette.50',
|
|
5063
4802
|
_dark: 'colorPalette.900/20',
|
|
5064
|
-
}
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
4803
|
+
}, border: "1px solid", borderColor: {
|
|
4804
|
+
base: 'colorPalette.200',
|
|
4805
|
+
_dark: 'colorPalette.800',
|
|
4806
|
+
}, colorPalette: "red", borderRadius: "md", p: 3, children: jsxs(Text, { fontSize: "sm", color: {
|
|
5068
4807
|
base: 'colorPalette.600',
|
|
5069
|
-
_dark: 'colorPalette.
|
|
5070
|
-
}
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
_dark: 'colorPalette.400',
|
|
5074
|
-
},
|
|
5075
|
-
bg: isSelected
|
|
5076
|
-
? {
|
|
5077
|
-
base: 'colorPalette.100',
|
|
5078
|
-
_dark: 'colorPalette.800/30',
|
|
5079
|
-
}
|
|
5080
|
-
: 'bg.muted',
|
|
5081
|
-
}, transition: "all 0.2s", children: jsxs(HStack, { gap: 3, children: [jsx(Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url && !imageFailed ? (jsx(Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md", onError: () => handleImageError(file.id) })) : isImage && (imageFailed || !file.url) ? (jsx(Icon, { as: LuImage, boxSize: 6, color: "fg.muted" })) : (jsx(Icon, { as: LuFile, boxSize: 6, color: "fg.muted" })) }), jsxs(VStack, { align: "start", flex: 1, gap: 1, children: [jsx(Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxs(HStack, { gap: 2, children: [file.size && (jsx(Fragment, { children: jsx(Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
|
|
5082
|
-
? formatBytes(file.size)
|
|
5083
|
-
: file.size }) })), file.comment && (jsxs(Fragment, { children: [file.size && (jsx(Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsx(Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsx(Box, { width: "24px", height: "24px", borderRadius: "full", bg: {
|
|
5084
|
-
base: 'colorPalette.500',
|
|
5085
|
-
_dark: 'colorPalette.400',
|
|
5086
|
-
}, colorPalette: "blue", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsx(Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
|
|
5087
|
-
}) })) }))] }) }), 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 ??
|
|
4808
|
+
_dark: 'colorPalette.300',
|
|
4809
|
+
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ??
|
|
4810
|
+
translate(removeIndex(`${colLabel}.upload_failed`)) ??
|
|
4811
|
+
'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFileId: selectedFileId, onSelectedFileIdChange: setSelectedFileId })) : 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 ??
|
|
5088
4812
|
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
5089
4813
|
'Cancel' }), jsx(Button$1, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFileId, children: labels?.select ??
|
|
5090
4814
|
translate(removeIndex(`${colLabel}.select`)) ??
|
|
@@ -5094,84 +4818,71 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5094
4818
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5095
4819
|
const { filePickerLabels } = useSchemaContext();
|
|
5096
4820
|
const formI18n = useFormI18n(column, prefix);
|
|
5097
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1',
|
|
4821
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5098
4822
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5099
|
-
const
|
|
5100
|
-
const
|
|
5101
|
-
|
|
5102
|
-
|
|
4823
|
+
const isSingleSelect = type === 'string';
|
|
4824
|
+
const currentValue = watch(column) ?? (isSingleSelect ? '' : []);
|
|
4825
|
+
// Handle File objects only
|
|
4826
|
+
const currentFiles = isSingleSelect
|
|
4827
|
+
? currentValue && currentValue instanceof File
|
|
4828
|
+
? [currentValue]
|
|
4829
|
+
: []
|
|
4830
|
+
: Array.isArray(currentValue)
|
|
4831
|
+
? currentValue.filter((f) => f instanceof File)
|
|
4832
|
+
: [];
|
|
5103
4833
|
const colLabel = formI18n.colLabel;
|
|
5104
|
-
const [dialogOpen, setDialogOpen] = useState(false);
|
|
5105
4834
|
const [failedImageIds, setFailedImageIds] = useState(new Set());
|
|
5106
|
-
|
|
5107
|
-
const showMediaLibrary = enableMediaLibrary && !!onFetchFiles;
|
|
4835
|
+
// FilePicker variant: Only handle File objects, no media library browser
|
|
5108
4836
|
const handleImageError = (fileIdentifier) => {
|
|
5109
4837
|
setFailedImageIds((prev) => new Set(prev).add(fileIdentifier));
|
|
5110
4838
|
};
|
|
5111
|
-
const handleMediaLibrarySelect = (fileId) => {
|
|
5112
|
-
const newFiles = [...currentFiles, fileId];
|
|
5113
|
-
setValue(colLabel, newFiles);
|
|
5114
|
-
};
|
|
5115
4839
|
const handleRemove = (index) => {
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
4840
|
+
if (isSingleSelect) {
|
|
4841
|
+
setValue(colLabel, '');
|
|
4842
|
+
}
|
|
4843
|
+
else {
|
|
4844
|
+
const newFiles = currentFiles.filter((_, i) => i !== index);
|
|
4845
|
+
setValue(colLabel, newFiles);
|
|
4846
|
+
}
|
|
5121
4847
|
};
|
|
5122
4848
|
const getFileIdentifier = (file, index) => {
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
}
|
|
5126
|
-
return file;
|
|
4849
|
+
// file-picker: file is a File object, create identifier from name and size
|
|
4850
|
+
return `${file.name}-${file.size}-${index}`;
|
|
5127
4851
|
};
|
|
5128
4852
|
const getFileName = (file) => {
|
|
5129
|
-
|
|
5130
|
-
return file.name;
|
|
5131
|
-
}
|
|
5132
|
-
return typeof file === 'string' ? file : 'Unknown file';
|
|
4853
|
+
return file.name;
|
|
5133
4854
|
};
|
|
5134
4855
|
const getFileSize = (file) => {
|
|
5135
|
-
|
|
5136
|
-
return file.size;
|
|
5137
|
-
}
|
|
5138
|
-
return undefined;
|
|
4856
|
+
return file.size;
|
|
5139
4857
|
};
|
|
5140
4858
|
const isImageFile = (file) => {
|
|
5141
|
-
|
|
5142
|
-
return file.type.startsWith('image/');
|
|
5143
|
-
}
|
|
5144
|
-
if (typeof file === 'string') {
|
|
5145
|
-
return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file);
|
|
5146
|
-
}
|
|
5147
|
-
return false;
|
|
4859
|
+
return file.type.startsWith('image/');
|
|
5148
4860
|
};
|
|
5149
4861
|
const getImageUrl = (file) => {
|
|
5150
|
-
|
|
5151
|
-
return URL.createObjectURL(file);
|
|
5152
|
-
}
|
|
5153
|
-
return undefined;
|
|
4862
|
+
return URL.createObjectURL(file);
|
|
5154
4863
|
};
|
|
5155
4864
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5156
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
}
|
|
4865
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsx(VStack, { align: "stretch", gap: 2, children: jsx(FileDropzone, { onDrop: ({ files }) => {
|
|
4866
|
+
// file-picker variant: Store File objects directly (no ID conversion)
|
|
4867
|
+
if (isSingleSelect) {
|
|
4868
|
+
// In single-select mode, use the first file and replace any existing file
|
|
4869
|
+
if (files.length > 0) {
|
|
4870
|
+
setValue(colLabel, files[0]);
|
|
4871
|
+
}
|
|
4872
|
+
}
|
|
4873
|
+
else {
|
|
4874
|
+
// In multi-select mode, filter duplicates and append
|
|
4875
|
+
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
5163
4876
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
5164
|
-
}
|
|
5165
|
-
|
|
5166
|
-
'Browse from Library' }))] }), showMediaLibrary && (jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5167
|
-
formI18n.t('dialog_title') ??
|
|
5168
|
-
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel })), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
4877
|
+
}
|
|
4878
|
+
}, placeholder: filePickerLabels?.fileDropzone ?? formI18n.t('fileDropzone') }) }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
5169
4879
|
const fileIdentifier = getFileIdentifier(file, index);
|
|
5170
4880
|
const fileName = getFileName(file);
|
|
5171
4881
|
const fileSize = getFileSize(file);
|
|
5172
4882
|
const isImage = isImageFile(file);
|
|
5173
4883
|
const imageUrl = getImageUrl(file);
|
|
5174
4884
|
const imageFailed = failedImageIds.has(fileIdentifier);
|
|
4885
|
+
// File Viewer
|
|
5175
4886
|
return (jsx(Card.Root, { variant: 'subtle', colorPalette: "blue", children: jsxs(Card.Body, { gap: "2", cursor: 'pointer', onClick: () => handleRemove(index), display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', border: "2px solid", borderColor: "border.default", borderRadius: "md", _hover: {
|
|
5176
4887
|
borderColor: 'colorPalette.300',
|
|
5177
4888
|
bg: 'bg.muted',
|
|
@@ -5179,6 +4890,66 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5179
4890
|
}) })] }));
|
|
5180
4891
|
};
|
|
5181
4892
|
|
|
4893
|
+
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
4894
|
+
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
4895
|
+
const { filePickerLabels } = useSchemaContext();
|
|
4896
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4897
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
4898
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
4899
|
+
const isSingleSelect = type === 'string';
|
|
4900
|
+
const currentValue = watch(column) ?? (isSingleSelect ? '' : []);
|
|
4901
|
+
// Handle string IDs only
|
|
4902
|
+
const currentFileIds = isSingleSelect
|
|
4903
|
+
? currentValue
|
|
4904
|
+
? [currentValue]
|
|
4905
|
+
: []
|
|
4906
|
+
: Array.isArray(currentValue)
|
|
4907
|
+
? currentValue
|
|
4908
|
+
: [];
|
|
4909
|
+
const colLabel = formI18n.colLabel;
|
|
4910
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
4911
|
+
const [failedImageIds, setFailedImageIds] = useState(new Set());
|
|
4912
|
+
const { onFetchFiles, filterImageOnly = false, enableUpload = false, onUploadFile, } = filePicker || {};
|
|
4913
|
+
if (!onFetchFiles) {
|
|
4914
|
+
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4915
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsx(Text, { color: "fg.muted", children: "Media library browser requires onFetchFiles" }) }));
|
|
4916
|
+
}
|
|
4917
|
+
const handleMediaLibrarySelect = (fileId) => {
|
|
4918
|
+
if (isSingleSelect) {
|
|
4919
|
+
setValue(colLabel, fileId);
|
|
4920
|
+
}
|
|
4921
|
+
else {
|
|
4922
|
+
const newFileIds = [...currentFileIds, fileId];
|
|
4923
|
+
setValue(colLabel, newFileIds);
|
|
4924
|
+
}
|
|
4925
|
+
};
|
|
4926
|
+
const handleRemove = (index) => {
|
|
4927
|
+
if (isSingleSelect) {
|
|
4928
|
+
setValue(colLabel, '');
|
|
4929
|
+
}
|
|
4930
|
+
else {
|
|
4931
|
+
const newFileIds = currentFileIds.filter((_, i) => i !== index);
|
|
4932
|
+
setValue(colLabel, newFileIds);
|
|
4933
|
+
}
|
|
4934
|
+
};
|
|
4935
|
+
const isImageId = (fileId) => {
|
|
4936
|
+
return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(fileId);
|
|
4937
|
+
};
|
|
4938
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4939
|
+
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 ??
|
|
4940
|
+
formI18n.t('browse_library') ??
|
|
4941
|
+
'Browse from Library' }) }), jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
4942
|
+
formI18n.t('dialog_title') ??
|
|
4943
|
+
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
4944
|
+
const isImage = isImageId(fileId);
|
|
4945
|
+
const imageFailed = failedImageIds.has(fileId);
|
|
4946
|
+
return (jsx(Card.Root, { variant: 'subtle', colorPalette: "blue", children: jsxs(Card.Body, { gap: "2", cursor: 'pointer', onClick: () => handleRemove(index), display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', border: "2px solid", borderColor: "border.default", borderRadius: "md", _hover: {
|
|
4947
|
+
borderColor: 'colorPalette.300',
|
|
4948
|
+
bg: 'bg.muted',
|
|
4949
|
+
}, transition: "all 0.2s", children: [jsx(Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, marginRight: "2", children: isImage && !imageFailed ? (jsx(Icon, { as: LuImage, boxSize: 6, color: "fg.muted" })) : (jsx(Icon, { as: LuFile, boxSize: 6, color: "fg.muted" })) }), jsx(VStack, { align: "start", flex: 1, gap: 1, children: jsx(Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileId }) }), jsx(Icon, { as: TiDeleteOutline, boxSize: 5, color: "fg.muted" })] }) }, `${fileId}-${index}`));
|
|
4950
|
+
}) })] }));
|
|
4951
|
+
};
|
|
4952
|
+
|
|
5182
4953
|
const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
|
|
5183
4954
|
const { showArrow, children, portalled = true, content, portalRef, ...rest } = props;
|
|
5184
4955
|
return (jsxs(Popover.Root, { ...rest, positioning: { ...rest.positioning, gutter: 4 }, children: [jsx(Popover.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Popover.Positioner, { children: jsxs(Popover.Content, { width: "auto", px: "2", py: "1", textStyle: "xs", rounded: "sm", ref: ref, children: [showArrow && (jsx(Popover.Arrow, { children: jsx(Popover.ArrowTip, {}) })), content] }) }) })] }));
|
|
@@ -5217,7 +4988,7 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
|
|
|
5217
4988
|
};
|
|
5218
4989
|
|
|
5219
4990
|
const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
5220
|
-
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4991
|
+
const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
|
|
5221
4992
|
const { serverUrl, idMap, setIdMap, schema: parentSchema, idPickerLabels, } = useSchemaContext();
|
|
5222
4993
|
const formI18n = useFormI18n(column, prefix);
|
|
5223
4994
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
@@ -5229,8 +5000,26 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5229
5000
|
const [page, setPage] = useState(0);
|
|
5230
5001
|
const ref = useRef(null);
|
|
5231
5002
|
const colLabel = formI18n.colLabel;
|
|
5232
|
-
const
|
|
5233
|
-
const
|
|
5003
|
+
const watchedValue = watch(colLabel);
|
|
5004
|
+
const watchId = !isMultiple ? watchedValue : undefined;
|
|
5005
|
+
const watchIds = isMultiple
|
|
5006
|
+
? (Array.isArray(watchedValue) ? watchedValue : [])
|
|
5007
|
+
: [];
|
|
5008
|
+
// Get initial values immediately to ensure query can trigger on mount
|
|
5009
|
+
const initialValue = getValues(colLabel);
|
|
5010
|
+
const initialId = !isMultiple ? initialValue : undefined;
|
|
5011
|
+
const initialIds = isMultiple
|
|
5012
|
+
? (Array.isArray(initialValue) ? initialValue : [])
|
|
5013
|
+
: [];
|
|
5014
|
+
// Use watched values if they exist (including empty string for single select),
|
|
5015
|
+
// otherwise fall back to initial values from getValues()
|
|
5016
|
+
// This ensures the query can trigger on mount with initial values
|
|
5017
|
+
// For single: use watchId if it's not undefined/null, otherwise use initialId
|
|
5018
|
+
// For multiple: use watchIds if watchedValue is defined, otherwise use initialIds
|
|
5019
|
+
const currentId = watchId !== undefined && watchId !== null ? watchId : initialId;
|
|
5020
|
+
const currentIds = watchedValue !== undefined && watchedValue !== null && isMultiple
|
|
5021
|
+
? watchIds
|
|
5022
|
+
: initialIds;
|
|
5234
5023
|
// Query for search results
|
|
5235
5024
|
const query = useQuery({
|
|
5236
5025
|
queryKey: [`idpicker`, { column, searchText, limit, page }],
|
|
@@ -5270,33 +5059,43 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5270
5059
|
staleTime: 300000,
|
|
5271
5060
|
});
|
|
5272
5061
|
// Query for currently selected items (to display them properly)
|
|
5062
|
+
// Use currentId/currentIds in queryKey so it includes initial values and updates when watched values change
|
|
5273
5063
|
const queryDefault = useQuery({
|
|
5274
5064
|
queryKey: [
|
|
5275
5065
|
`idpicker-default`,
|
|
5276
|
-
{
|
|
5066
|
+
{
|
|
5067
|
+
form: parentSchema.title,
|
|
5068
|
+
column,
|
|
5069
|
+
id: isMultiple ? currentIds : currentId,
|
|
5070
|
+
},
|
|
5277
5071
|
],
|
|
5278
5072
|
queryFn: async () => {
|
|
5073
|
+
// Use current values (which include initial) for the query
|
|
5074
|
+
const queryId = currentId;
|
|
5075
|
+
const queryIds = currentIds;
|
|
5279
5076
|
if (customQueryFn) {
|
|
5077
|
+
// For customQueryFn, pass where clause to fetch specific IDs
|
|
5280
5078
|
const { data, idMap } = await customQueryFn({
|
|
5281
|
-
searching:
|
|
5282
|
-
limit: isMultiple ?
|
|
5079
|
+
searching: '',
|
|
5080
|
+
limit: isMultiple ? queryIds.length : 1,
|
|
5283
5081
|
offset: 0,
|
|
5082
|
+
where: [{ id: column_ref, value: isMultiple ? queryIds : queryId }],
|
|
5284
5083
|
});
|
|
5285
5084
|
setIdMap((state) => {
|
|
5286
5085
|
return { ...state, ...idMap };
|
|
5287
5086
|
});
|
|
5288
5087
|
return data;
|
|
5289
5088
|
}
|
|
5290
|
-
if (!
|
|
5089
|
+
if (!queryId && (!queryIds || queryIds.length === 0)) {
|
|
5291
5090
|
return { data: [] };
|
|
5292
5091
|
}
|
|
5293
|
-
const searchValue = isMultiple ?
|
|
5092
|
+
const searchValue = isMultiple ? queryIds.join(',') : queryId;
|
|
5294
5093
|
const data = await getTableData({
|
|
5295
5094
|
serverUrl,
|
|
5296
5095
|
searching: searchValue,
|
|
5297
5096
|
in_table: table,
|
|
5298
|
-
where: [{ id: column_ref, value: isMultiple ?
|
|
5299
|
-
limit: isMultiple ?
|
|
5097
|
+
where: [{ id: column_ref, value: isMultiple ? queryIds : queryId }],
|
|
5098
|
+
limit: isMultiple ? queryIds.length : 1,
|
|
5300
5099
|
offset: 0,
|
|
5301
5100
|
});
|
|
5302
5101
|
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
@@ -5313,16 +5112,9 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5313
5112
|
return data;
|
|
5314
5113
|
},
|
|
5315
5114
|
enabled: isMultiple
|
|
5316
|
-
? Array.isArray(
|
|
5317
|
-
: !!
|
|
5115
|
+
? Array.isArray(currentIds) && currentIds.length > 0
|
|
5116
|
+
: !!currentId,
|
|
5318
5117
|
});
|
|
5319
|
-
// Effect to load selected values when component mounts
|
|
5320
|
-
useEffect(() => {
|
|
5321
|
-
if (isMultiple ? watchIds.length > 0 : !!watchId) {
|
|
5322
|
-
queryDefault.refetch();
|
|
5323
|
-
}
|
|
5324
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5325
|
-
}, []);
|
|
5326
5118
|
// Effect to trigger initial data fetch when popover opens
|
|
5327
5119
|
useEffect(() => {
|
|
5328
5120
|
if (openSearchResult) {
|
|
@@ -5355,7 +5147,8 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5355
5147
|
if (Object.keys(idMap).length <= 0) {
|
|
5356
5148
|
return '';
|
|
5357
5149
|
}
|
|
5358
|
-
|
|
5150
|
+
// Use currentId which includes initial values
|
|
5151
|
+
const record = idMap[currentId];
|
|
5359
5152
|
if (record === undefined) {
|
|
5360
5153
|
return '';
|
|
5361
5154
|
}
|
|
@@ -6347,6 +6140,9 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
6347
6140
|
if (variant === 'file-picker') {
|
|
6348
6141
|
return jsx(FilePicker, { schema: colSchema, prefix, column });
|
|
6349
6142
|
}
|
|
6143
|
+
if (variant === 'media-library-browser') {
|
|
6144
|
+
return (jsx(FormMediaLibraryBrowser, { schema: colSchema, prefix, column }));
|
|
6145
|
+
}
|
|
6350
6146
|
if (variant === 'date-range') {
|
|
6351
6147
|
return jsx(DateRangePicker, { schema: colSchema, prefix, column });
|
|
6352
6148
|
}
|
|
@@ -6738,59 +6534,62 @@ const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
|
6738
6534
|
const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
6739
6535
|
const colSchema = schema;
|
|
6740
6536
|
const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
|
|
6741
|
-
if (variant ===
|
|
6537
|
+
if (variant === 'custom-input') {
|
|
6742
6538
|
return jsx(CustomViewer, { schema: colSchema, prefix, column });
|
|
6743
6539
|
}
|
|
6744
|
-
if (type ===
|
|
6540
|
+
if (type === 'string') {
|
|
6745
6541
|
if ((schema.enum ?? []).length > 0) {
|
|
6746
6542
|
return jsx(EnumViewer, { schema: colSchema, prefix, column });
|
|
6747
6543
|
}
|
|
6748
|
-
if (variant ===
|
|
6544
|
+
if (variant === 'id-picker') {
|
|
6749
6545
|
idPickerSanityCheck(column, foreign_key);
|
|
6750
6546
|
return jsx(IdViewer, { schema: colSchema, prefix, column });
|
|
6751
6547
|
}
|
|
6752
|
-
if (format ===
|
|
6548
|
+
if (format === 'time') {
|
|
6753
6549
|
return jsx(TimeViewer, { schema: colSchema, prefix, column });
|
|
6754
6550
|
}
|
|
6755
|
-
if (format ===
|
|
6551
|
+
if (format === 'date') {
|
|
6756
6552
|
return jsx(DateViewer, { schema: colSchema, prefix, column });
|
|
6757
6553
|
}
|
|
6758
|
-
if (format ===
|
|
6554
|
+
if (format === 'date-time') {
|
|
6759
6555
|
return jsx(DateTimeViewer, { schema: colSchema, prefix, column });
|
|
6760
6556
|
}
|
|
6761
|
-
if (variant ===
|
|
6557
|
+
if (variant === 'text-area') {
|
|
6762
6558
|
return jsx(TextAreaViewer, { schema: colSchema, prefix, column });
|
|
6763
6559
|
}
|
|
6764
6560
|
return jsx(StringViewer, { schema: colSchema, prefix, column });
|
|
6765
6561
|
}
|
|
6766
|
-
if (type ===
|
|
6562
|
+
if (type === 'number' || type === 'integer') {
|
|
6767
6563
|
return jsx(NumberViewer, { schema: colSchema, prefix, column });
|
|
6768
6564
|
}
|
|
6769
|
-
if (type ===
|
|
6565
|
+
if (type === 'boolean') {
|
|
6770
6566
|
return jsx(BooleanViewer, { schema: colSchema, prefix, column });
|
|
6771
6567
|
}
|
|
6772
|
-
if (type ===
|
|
6568
|
+
if (type === 'object') {
|
|
6773
6569
|
if (innerProperties) {
|
|
6774
6570
|
return jsx(ObjectViewer, { schema: colSchema, prefix, column });
|
|
6775
6571
|
}
|
|
6776
6572
|
return jsx(RecordInput, { schema: colSchema, prefix, column });
|
|
6777
6573
|
}
|
|
6778
|
-
if (type ===
|
|
6779
|
-
if (variant ===
|
|
6574
|
+
if (type === 'array') {
|
|
6575
|
+
if (variant === 'id-picker') {
|
|
6780
6576
|
idPickerSanityCheck(column, foreign_key);
|
|
6781
6577
|
return (jsx(IdViewer, { schema: colSchema, prefix, column, isMultiple: true }));
|
|
6782
6578
|
}
|
|
6783
|
-
if (variant ===
|
|
6579
|
+
if (variant === 'tag-picker') {
|
|
6784
6580
|
return jsx(TagViewer, { schema: colSchema, prefix, column });
|
|
6785
6581
|
}
|
|
6786
|
-
if (variant ===
|
|
6582
|
+
if (variant === 'file-picker') {
|
|
6583
|
+
return jsx(FileViewer, { schema: colSchema, prefix, column });
|
|
6584
|
+
}
|
|
6585
|
+
if (variant === 'media-library-browser') {
|
|
6787
6586
|
return jsx(FileViewer, { schema: colSchema, prefix, column });
|
|
6788
6587
|
}
|
|
6789
|
-
if (variant ===
|
|
6588
|
+
if (variant === 'enum-picker') {
|
|
6790
6589
|
const { items } = schema;
|
|
6791
6590
|
const { enum: enumItems } = items;
|
|
6792
6591
|
const enumSchema = {
|
|
6793
|
-
type:
|
|
6592
|
+
type: 'string',
|
|
6794
6593
|
enum: enumItems,
|
|
6795
6594
|
};
|
|
6796
6595
|
return (jsx(EnumViewer, { isMultiple: true, schema: enumSchema, prefix, column }));
|
|
@@ -6800,7 +6599,7 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
6800
6599
|
}
|
|
6801
6600
|
return jsx(Text, { children: `array ${column}` });
|
|
6802
6601
|
}
|
|
6803
|
-
if (type ===
|
|
6602
|
+
if (type === 'null') {
|
|
6804
6603
|
return jsx(Text, { children: `null ${column}` });
|
|
6805
6604
|
}
|
|
6806
6605
|
return jsx(Text, { children: "missing type" });
|
|
@@ -7194,4 +6993,524 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
|
|
|
7194
6993
|
}
|
|
7195
6994
|
};
|
|
7196
6995
|
|
|
7197
|
-
|
|
6996
|
+
const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
6997
|
+
const { columns, translate, data } = useDataTableContext();
|
|
6998
|
+
const columnsMap = Object.fromEntries(columns.map((def) => {
|
|
6999
|
+
const { accessorKey, id } = def;
|
|
7000
|
+
if (accessorKey) {
|
|
7001
|
+
return [accessorKey, def];
|
|
7002
|
+
}
|
|
7003
|
+
return [id, def];
|
|
7004
|
+
}));
|
|
7005
|
+
const columnHeaders = Object.keys(columnsMap);
|
|
7006
|
+
const totalWidths = columns
|
|
7007
|
+
.map(({ size }) => {
|
|
7008
|
+
if (!!size === false) {
|
|
7009
|
+
return 0;
|
|
7010
|
+
}
|
|
7011
|
+
if (typeof size === "number") {
|
|
7012
|
+
return size;
|
|
7013
|
+
}
|
|
7014
|
+
return 0;
|
|
7015
|
+
})
|
|
7016
|
+
.reduce((previous, current) => previous + current, 0);
|
|
7017
|
+
const columnWidths = columns
|
|
7018
|
+
.map(({ size }) => {
|
|
7019
|
+
if (!!size === false) {
|
|
7020
|
+
return "1fr";
|
|
7021
|
+
}
|
|
7022
|
+
return `minmax(${size}px, ${(size / totalWidths) * 100}%)`;
|
|
7023
|
+
})
|
|
7024
|
+
.join(" ");
|
|
7025
|
+
console.log({ columnWidths }, "hadfg");
|
|
7026
|
+
const cellProps = {
|
|
7027
|
+
flex: "1 0 0%",
|
|
7028
|
+
overflow: "auto",
|
|
7029
|
+
paddingX: "2",
|
|
7030
|
+
py: "1",
|
|
7031
|
+
color: { base: "colorPalette.900", _dark: "colorPalette.100" },
|
|
7032
|
+
bgColor: { base: "colorPalette.50", _dark: "colorPalette.950" },
|
|
7033
|
+
borderBottomColor: { base: "colorPalette.200", _dark: "colorPalette.800" },
|
|
7034
|
+
borderBottomWidth: "1px",
|
|
7035
|
+
...{ colorPalette },
|
|
7036
|
+
};
|
|
7037
|
+
if (data.length <= 0) {
|
|
7038
|
+
return jsx(Fragment, { children: emptyComponent });
|
|
7039
|
+
}
|
|
7040
|
+
return (jsxs(Grid, { templateColumns: `${columnWidths}`, overflow: "auto", borderWidth: "1px", color: { base: "colorPalette.900", _dark: "colorPalette.100" }, borderColor: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: [jsx(Grid, { templateColumns: `${columnWidths}`, column: `1/span ${columns.length}`, bg: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: columnHeaders.map((header) => {
|
|
7041
|
+
return (jsx(Box, { flex: "1 0 0%", paddingX: "2", py: "1", overflow: "auto", textOverflow: "ellipsis", children: translate.t(`column_header.${header}`) }));
|
|
7042
|
+
}) }), data.map((record) => {
|
|
7043
|
+
return (jsx(Fragment, { children: columnHeaders.map((header) => {
|
|
7044
|
+
const { cell } = columnsMap[header];
|
|
7045
|
+
const value = record[header];
|
|
7046
|
+
if (!!record === false) {
|
|
7047
|
+
return (jsx(Box, { ...cellProps, children: translate.t(`column_cell.placeholder`) }));
|
|
7048
|
+
}
|
|
7049
|
+
if (cell) {
|
|
7050
|
+
return (jsx(Box, { ...cellProps, children: cell({ row: { original: record } }) }));
|
|
7051
|
+
}
|
|
7052
|
+
if (typeof value === "object") {
|
|
7053
|
+
return (jsx(Box, { ...cellProps, children: jsx(RecordDisplay, { object: value }) }));
|
|
7054
|
+
}
|
|
7055
|
+
return jsx(Box, { ...cellProps, children: value });
|
|
7056
|
+
}) }));
|
|
7057
|
+
})] }));
|
|
7058
|
+
};
|
|
7059
|
+
|
|
7060
|
+
const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
|
|
7061
|
+
'use no memo';
|
|
7062
|
+
const { table } = useDataTableContext();
|
|
7063
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
7064
|
+
const [hoveredRow, setHoveredRow] = useState(-1);
|
|
7065
|
+
const handleRowHover = (index) => {
|
|
7066
|
+
setHoveredRow(index);
|
|
7067
|
+
};
|
|
7068
|
+
const getTdProps = (column) => {
|
|
7069
|
+
const tdProps = column.getIsPinned()
|
|
7070
|
+
? {
|
|
7071
|
+
left: showSelector
|
|
7072
|
+
? `${column.getStart('left') + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
7073
|
+
: `${column.getStart('left')}px`,
|
|
7074
|
+
position: 'relative',
|
|
7075
|
+
}
|
|
7076
|
+
: {};
|
|
7077
|
+
return tdProps;
|
|
7078
|
+
};
|
|
7079
|
+
const getTrProps = ({ hoveredRow, index, }) => {
|
|
7080
|
+
if (hoveredRow === -1) {
|
|
7081
|
+
return {};
|
|
7082
|
+
}
|
|
7083
|
+
if (hoveredRow === index) {
|
|
7084
|
+
return {
|
|
7085
|
+
opacity: '1',
|
|
7086
|
+
};
|
|
7087
|
+
}
|
|
7088
|
+
return {
|
|
7089
|
+
opacity: '0.8',
|
|
7090
|
+
};
|
|
7091
|
+
};
|
|
7092
|
+
// Get the number of skeleton rows based on current pageSize
|
|
7093
|
+
const pageSize = table.getState().pagination.pageSize;
|
|
7094
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
7095
|
+
return (jsx(Table$1.Body, { children: Array.from({ length: pageSize }).map((_, rowIndex) => {
|
|
7096
|
+
return (jsxs(Table$1.Row, { display: 'flex', zIndex: 1, onMouseEnter: () => handleRowHover(rowIndex), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index: rowIndex }), children: [showSelector && jsx(TableRowSelectorSkeleton, {}), visibleColumns.map((column, colIndex) => {
|
|
7097
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
|
|
7098
|
+
// styling resize and pinning start
|
|
7099
|
+
flex: `${canResize ? '0' : '1'} 0 ${column.getSize()}px`,
|
|
7100
|
+
// this is to avoid the cell from being too wide
|
|
7101
|
+
minWidth: `0`, color: {
|
|
7102
|
+
base: 'colorPalette.900',
|
|
7103
|
+
_dark: 'colorPalette.100',
|
|
7104
|
+
},
|
|
7105
|
+
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...getTdProps(column), children: jsx(Skeleton, { height: "20px", width: "80%" }) }, `chakra-table-skeleton-cell-${rowIndex}-${colIndex}`));
|
|
7106
|
+
})] }, `chakra-table-skeleton-row-${rowIndex}`));
|
|
7107
|
+
}) }));
|
|
7108
|
+
};
|
|
7109
|
+
const TableRowSelectorSkeleton = () => {
|
|
7110
|
+
const { table } = useDataTableContext();
|
|
7111
|
+
const SELECTION_BOX_WIDTH = 20;
|
|
7112
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid', color: {
|
|
7113
|
+
base: 'colorPalette.900',
|
|
7114
|
+
_dark: 'colorPalette.100',
|
|
7115
|
+
},
|
|
7116
|
+
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsx(Skeleton, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }) }));
|
|
7117
|
+
};
|
|
7118
|
+
|
|
7119
|
+
const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = '', isLoading = false, }) => {
|
|
7120
|
+
if (variant === 'greedy') {
|
|
7121
|
+
const bodyComponent = isLoading ? (jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: false })) : (jsx(TableBody, { ...tableBodyProps, canResize: false, ...tableBodyProps }));
|
|
7122
|
+
return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { canResize: false,
|
|
7123
|
+
showLoading: isLoading,
|
|
7124
|
+
showSelector: tableHeaderProps.showSelector ??
|
|
7125
|
+
tableBodyProps.showSelector ??
|
|
7126
|
+
false,
|
|
7127
|
+
...tableProps, children: [jsx(TableHeader, { canResize: false, ...tableHeaderProps }), bodyComponent, showFooter && (jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
|
|
7128
|
+
}
|
|
7129
|
+
const bodyComponent = isLoading ? (jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: tableBodyProps.canResize })) : (jsx(TableBody, { ...tableBodyProps }));
|
|
7130
|
+
return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { showLoading: isLoading,
|
|
7131
|
+
showSelector: tableHeaderProps.showSelector ??
|
|
7132
|
+
tableBodyProps.showSelector ??
|
|
7133
|
+
false,
|
|
7134
|
+
...tableProps, children: [jsx(TableHeader, { ...tableHeaderProps }), bodyComponent, showFooter && jsx(TableFooter, { ...tableFooterProps })] }) }));
|
|
7135
|
+
};
|
|
7136
|
+
|
|
7137
|
+
/**
|
|
7138
|
+
* DefaultTableServer is a wrapper around DefaultTable that automatically
|
|
7139
|
+
* detects server-side loading state from DataTableServerContext.
|
|
7140
|
+
*
|
|
7141
|
+
* Use this component when working with DataTableServer to automatically
|
|
7142
|
+
* show skeleton loading state during data fetching.
|
|
7143
|
+
*
|
|
7144
|
+
* @example
|
|
7145
|
+
* ```tsx
|
|
7146
|
+
* <DataTableServer columns={columns} {...datatableServer}>
|
|
7147
|
+
* <DefaultTableServer />
|
|
7148
|
+
* </DataTableServer>
|
|
7149
|
+
* ```
|
|
7150
|
+
*/
|
|
7151
|
+
const DefaultTableServer = ({ isLoading: isLoadingOverride, ...props }) => {
|
|
7152
|
+
// Automatically detect loading state from server context
|
|
7153
|
+
const serverContext = useDataTableServerContext();
|
|
7154
|
+
const isLoading = isLoadingOverride ?? serverContext?.query?.isLoading ?? false;
|
|
7155
|
+
return jsx(DefaultTable, { ...props, isLoading: isLoading });
|
|
7156
|
+
};
|
|
7157
|
+
|
|
7158
|
+
const CellRenderer = ({ cell }) => {
|
|
7159
|
+
const { translate } = useDataTableContext();
|
|
7160
|
+
const getLabel = ({ columnId }) => {
|
|
7161
|
+
if (translate !== undefined) {
|
|
7162
|
+
return translate.t(`${columnId}`);
|
|
7163
|
+
}
|
|
7164
|
+
return snakeToLabel(columnId);
|
|
7165
|
+
};
|
|
7166
|
+
const formatValue = (value) => {
|
|
7167
|
+
if (typeof value === "object") {
|
|
7168
|
+
return JSON.stringify(value);
|
|
7169
|
+
}
|
|
7170
|
+
if (typeof value === "string") {
|
|
7171
|
+
return value;
|
|
7172
|
+
}
|
|
7173
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
7174
|
+
return `${value}`;
|
|
7175
|
+
}
|
|
7176
|
+
if (value === undefined) {
|
|
7177
|
+
if (translate !== undefined) {
|
|
7178
|
+
return translate.t(`undefined`);
|
|
7179
|
+
}
|
|
7180
|
+
return `undefined`;
|
|
7181
|
+
}
|
|
7182
|
+
throw new Error(`value is unknown, ${typeof value}`);
|
|
7183
|
+
};
|
|
7184
|
+
const showCustomDataDisplay = cell.column.columnDef.meta?.showCustomDisplay ?? false;
|
|
7185
|
+
const gridColumn = cell.column.columnDef.meta?.gridColumn ?? [
|
|
7186
|
+
"span 12",
|
|
7187
|
+
"span 6",
|
|
7188
|
+
"span 3",
|
|
7189
|
+
];
|
|
7190
|
+
const gridRow = cell.column.columnDef.meta?.gridRow ?? {};
|
|
7191
|
+
if (showCustomDataDisplay) {
|
|
7192
|
+
return (jsx(Flex, { gridColumn, gridRow, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
|
|
7193
|
+
}
|
|
7194
|
+
const value = cell.getValue();
|
|
7195
|
+
if (typeof value === "object") {
|
|
7196
|
+
return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { children: getLabel({ columnId: cell.column.id }) }), jsx(RecordDisplay, { boxProps: {
|
|
7197
|
+
borderWidth: 1,
|
|
7198
|
+
borderRadius: 4,
|
|
7199
|
+
borderColor: "gray.400",
|
|
7200
|
+
paddingX: 4,
|
|
7201
|
+
paddingY: 2,
|
|
7202
|
+
}, object: value })] }, cell.id));
|
|
7203
|
+
}
|
|
7204
|
+
return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { color: "colorPalette.400", children: getLabel({ columnId: cell.column.id }) }), jsx(Box, { wordBreak: "break-word", textOverflow: "ellipsis", overflow: "hidden", children: `${formatValue(cell.getValue())}` })] }, cell.id));
|
|
7205
|
+
};
|
|
7206
|
+
const DataDisplay = ({ variant = "" }) => {
|
|
7207
|
+
const { table, translate } = useDataTableContext();
|
|
7208
|
+
return (jsx(Flex, { flexFlow: "column", gap: "1", children: table.getRowModel().rows.map((row) => {
|
|
7209
|
+
const rowId = row.id;
|
|
7210
|
+
return (jsx(Card.Root, { children: jsx(Card.Body, { display: "grid", gap: 4, padding: 4, gridTemplateColumns: "repeat(12, 1fr)", children: table.getAllColumns().map((column) => {
|
|
7211
|
+
const childCell = row.getAllCells().find((cell) => {
|
|
7212
|
+
return cell.id === `${rowId}_${column.id}`;
|
|
7213
|
+
});
|
|
7214
|
+
if (column.columns.length > 0) {
|
|
7215
|
+
return (jsxs(Card.Root, { margin: "1", gridColumn: "span 12", children: [jsx(Card.Header, { color: "gray.400", children: translate.t(column.id) }), jsx(Card.Body, { display: "grid", gap: "4", gridTemplateColumns: "repeat(12, 1fr)", children: column.columns.map((column) => {
|
|
7216
|
+
if (!column.getIsVisible()) {
|
|
7217
|
+
return jsx(Fragment, {});
|
|
7218
|
+
}
|
|
7219
|
+
const foundCell = row
|
|
7220
|
+
.getVisibleCells()
|
|
7221
|
+
.find((cell) => {
|
|
7222
|
+
return cell.id === `${rowId}_${column.id}`;
|
|
7223
|
+
});
|
|
7224
|
+
return jsx(CellRenderer, { cell: foundCell });
|
|
7225
|
+
}) })] }, `chakra-table-card-${childCell?.id}`));
|
|
7226
|
+
}
|
|
7227
|
+
return jsx(CellRenderer, { cell: childCell });
|
|
7228
|
+
}) }) }, `chakra-table-card-${rowId}`));
|
|
7229
|
+
}) }));
|
|
7230
|
+
};
|
|
7231
|
+
|
|
7232
|
+
// Reference: https://tanstack.com/table/latest/docs/framework/react/examples/custom-features
|
|
7233
|
+
// TypeScript setup for our new feature with all of the same type-safety as stock TanStack Table features
|
|
7234
|
+
// end of TS setup!
|
|
7235
|
+
// Here is all of the actual javascript code for our new feature
|
|
7236
|
+
const DensityFeature = {
|
|
7237
|
+
// define the new feature's initial state
|
|
7238
|
+
getInitialState: (state) => {
|
|
7239
|
+
return {
|
|
7240
|
+
density: "sm",
|
|
7241
|
+
...state,
|
|
7242
|
+
};
|
|
7243
|
+
},
|
|
7244
|
+
// define the new feature's default options
|
|
7245
|
+
getDefaultOptions: (table) => {
|
|
7246
|
+
return {
|
|
7247
|
+
enableDensity: true,
|
|
7248
|
+
onDensityChange: makeStateUpdater("density", table),
|
|
7249
|
+
};
|
|
7250
|
+
},
|
|
7251
|
+
// if you need to add a default column definition...
|
|
7252
|
+
// getDefaultColumnDef: <TData extends RowData>(): Partial<ColumnDef<TData>> => {
|
|
7253
|
+
// return { meta: {} } //use meta instead of directly adding to the columnDef to avoid typescript stuff that's hard to workaround
|
|
7254
|
+
// },
|
|
7255
|
+
// define the new feature's table instance methods
|
|
7256
|
+
createTable: (table) => {
|
|
7257
|
+
table.setDensity = (updater) => {
|
|
7258
|
+
const safeUpdater = (old) => {
|
|
7259
|
+
let newState = functionalUpdate(updater, old);
|
|
7260
|
+
return newState;
|
|
7261
|
+
};
|
|
7262
|
+
return table.options.onDensityChange?.(safeUpdater);
|
|
7263
|
+
};
|
|
7264
|
+
table.toggleDensity = (value) => {
|
|
7265
|
+
table.setDensity((old) => {
|
|
7266
|
+
if (value)
|
|
7267
|
+
return value;
|
|
7268
|
+
if (old === "sm") {
|
|
7269
|
+
return "md";
|
|
7270
|
+
}
|
|
7271
|
+
if (old === "md") {
|
|
7272
|
+
return "lg";
|
|
7273
|
+
}
|
|
7274
|
+
return "sm";
|
|
7275
|
+
});
|
|
7276
|
+
};
|
|
7277
|
+
table.getDensityValue = (value) => {
|
|
7278
|
+
let density;
|
|
7279
|
+
if (value) {
|
|
7280
|
+
density = value;
|
|
7281
|
+
}
|
|
7282
|
+
else {
|
|
7283
|
+
density = table.getState().density;
|
|
7284
|
+
}
|
|
7285
|
+
if (density === "sm") {
|
|
7286
|
+
return 8;
|
|
7287
|
+
}
|
|
7288
|
+
if (density === "md") {
|
|
7289
|
+
return 16;
|
|
7290
|
+
}
|
|
7291
|
+
return 32;
|
|
7292
|
+
};
|
|
7293
|
+
},
|
|
7294
|
+
// if you need to add row instance APIs...
|
|
7295
|
+
// createRow: <TData extends RowData>(row, table): void => {},
|
|
7296
|
+
// if you need to add cell instance APIs...
|
|
7297
|
+
// createCell: <TData extends RowData>(cell, column, row, table): void => {},
|
|
7298
|
+
// if you need to add column instance APIs...
|
|
7299
|
+
// createColumn: <TData extends RowData>(column, table): void => {},
|
|
7300
|
+
// if you need to add header instance APIs...
|
|
7301
|
+
// createHeader: <TData extends RowData>(header, table): void => {},
|
|
7302
|
+
};
|
|
7303
|
+
//end of custom feature code
|
|
7304
|
+
|
|
7305
|
+
// Define a custom fuzzy filter function that will apply ranking info to rows (using match-sorter utils)
|
|
7306
|
+
const fuzzyFilter = (row, columnId, value, addMeta) => {
|
|
7307
|
+
// Rank the item
|
|
7308
|
+
const itemRank = rankItem(row.getValue(columnId), value);
|
|
7309
|
+
// Store the itemRank info
|
|
7310
|
+
addMeta({
|
|
7311
|
+
itemRank,
|
|
7312
|
+
});
|
|
7313
|
+
// Return if the item should be filtered in/out
|
|
7314
|
+
return itemRank.passed;
|
|
7315
|
+
};
|
|
7316
|
+
/**
|
|
7317
|
+
* DataTable will create a context to hold all values to
|
|
7318
|
+
* help the render of the DataTable in serverside
|
|
7319
|
+
*
|
|
7320
|
+
*
|
|
7321
|
+
* The query is required to be a GET request that can receive
|
|
7322
|
+
* specified params and return a specified response
|
|
7323
|
+
*
|
|
7324
|
+
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
7325
|
+
*/
|
|
7326
|
+
function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, translate, children, tableLabel = {
|
|
7327
|
+
view: 'View',
|
|
7328
|
+
edit: 'Edit',
|
|
7329
|
+
filterButtonText: 'Filter',
|
|
7330
|
+
filterTitle: 'Filter',
|
|
7331
|
+
filterReset: 'Reset',
|
|
7332
|
+
filterClose: 'Close',
|
|
7333
|
+
reloadTooltip: 'Reload',
|
|
7334
|
+
reloadButtonText: 'Reload',
|
|
7335
|
+
resetSelection: 'Reset Selection',
|
|
7336
|
+
resetSorting: 'Reset Sorting',
|
|
7337
|
+
rowCountText: 'Row Count',
|
|
7338
|
+
hasErrorText: 'Has Error',
|
|
7339
|
+
globalFilterPlaceholder: 'Search',
|
|
7340
|
+
trueLabel: 'True',
|
|
7341
|
+
falseLabel: 'False',
|
|
7342
|
+
}, }) {
|
|
7343
|
+
const table = useReactTable({
|
|
7344
|
+
_features: [DensityFeature],
|
|
7345
|
+
data: data,
|
|
7346
|
+
rowCount: data.length,
|
|
7347
|
+
columns: columns,
|
|
7348
|
+
getCoreRowModel: getCoreRowModel(),
|
|
7349
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
7350
|
+
getSortedRowModel: getSortedRowModel(),
|
|
7351
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
7352
|
+
defaultColumn: {
|
|
7353
|
+
size: 150, //starting column size
|
|
7354
|
+
minSize: 10, //enforced during column resizing
|
|
7355
|
+
maxSize: 10000, //enforced during column resizing
|
|
7356
|
+
},
|
|
7357
|
+
enableRowSelection: enableRowSelection,
|
|
7358
|
+
enableMultiRowSelection: enableMultiRowSelection,
|
|
7359
|
+
enableSubRowSelection: enableSubRowSelection,
|
|
7360
|
+
columnResizeMode: 'onChange',
|
|
7361
|
+
// global filter start
|
|
7362
|
+
filterFns: {
|
|
7363
|
+
fuzzy: fuzzyFilter,
|
|
7364
|
+
},
|
|
7365
|
+
globalFilterFn: 'fuzzy',
|
|
7366
|
+
state: {
|
|
7367
|
+
pagination,
|
|
7368
|
+
sorting,
|
|
7369
|
+
columnFilters,
|
|
7370
|
+
rowSelection,
|
|
7371
|
+
columnOrder,
|
|
7372
|
+
globalFilter,
|
|
7373
|
+
density,
|
|
7374
|
+
columnVisibility,
|
|
7375
|
+
},
|
|
7376
|
+
onPaginationChange: setPagination,
|
|
7377
|
+
onSortingChange: setSorting,
|
|
7378
|
+
onColumnFiltersChange: setColumnFilters,
|
|
7379
|
+
onRowSelectionChange: setRowSelection,
|
|
7380
|
+
onColumnOrderChange: (state) => {
|
|
7381
|
+
setColumnOrder(state);
|
|
7382
|
+
},
|
|
7383
|
+
onGlobalFilterChange: (state) => {
|
|
7384
|
+
setGlobalFilter(state);
|
|
7385
|
+
},
|
|
7386
|
+
onDensityChange: setDensity,
|
|
7387
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
7388
|
+
});
|
|
7389
|
+
return (jsx(DataTableContext.Provider, { value: {
|
|
7390
|
+
table: table,
|
|
7391
|
+
globalFilter,
|
|
7392
|
+
setGlobalFilter,
|
|
7393
|
+
type: 'client',
|
|
7394
|
+
translate,
|
|
7395
|
+
columns: columns,
|
|
7396
|
+
sorting,
|
|
7397
|
+
setSorting,
|
|
7398
|
+
columnFilters,
|
|
7399
|
+
setColumnFilters,
|
|
7400
|
+
pagination,
|
|
7401
|
+
setPagination,
|
|
7402
|
+
rowSelection,
|
|
7403
|
+
setRowSelection,
|
|
7404
|
+
columnOrder,
|
|
7405
|
+
setColumnOrder,
|
|
7406
|
+
density,
|
|
7407
|
+
setDensity,
|
|
7408
|
+
columnVisibility,
|
|
7409
|
+
setColumnVisibility,
|
|
7410
|
+
data,
|
|
7411
|
+
tableLabel,
|
|
7412
|
+
}, children: children }));
|
|
7413
|
+
}
|
|
7414
|
+
|
|
7415
|
+
/**
|
|
7416
|
+
* DataTableServer will create a context to hold all values to
|
|
7417
|
+
* help the render of the DataTable in serverside
|
|
7418
|
+
*
|
|
7419
|
+
* The query is required to be a GET request that can receive
|
|
7420
|
+
* specified params and return a specified response
|
|
7421
|
+
*
|
|
7422
|
+
* The `useDataTableServer` can help to create the specified request and response
|
|
7423
|
+
*
|
|
7424
|
+
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
7425
|
+
*/
|
|
7426
|
+
function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url, translate, children, tableLabel = {
|
|
7427
|
+
view: "View",
|
|
7428
|
+
edit: "Edit",
|
|
7429
|
+
filterButtonText: "Filter",
|
|
7430
|
+
filterTitle: "Filter",
|
|
7431
|
+
filterReset: "Reset",
|
|
7432
|
+
filterClose: "Close",
|
|
7433
|
+
reloadTooltip: "Reload",
|
|
7434
|
+
reloadButtonText: "Reload",
|
|
7435
|
+
resetSelection: "Reset Selection",
|
|
7436
|
+
resetSorting: "Reset Sorting",
|
|
7437
|
+
rowCountText: "Row Count",
|
|
7438
|
+
hasErrorText: "Has Error",
|
|
7439
|
+
globalFilterPlaceholder: "Search",
|
|
7440
|
+
trueLabel: "True",
|
|
7441
|
+
falseLabel: "False",
|
|
7442
|
+
}, }) {
|
|
7443
|
+
const table = useReactTable({
|
|
7444
|
+
_features: [DensityFeature],
|
|
7445
|
+
data: (query.data?.data ?? []),
|
|
7446
|
+
rowCount: query.data?.count ?? 0,
|
|
7447
|
+
columns: columns,
|
|
7448
|
+
getCoreRowModel: getCoreRowModel(),
|
|
7449
|
+
manualPagination: true,
|
|
7450
|
+
manualSorting: true,
|
|
7451
|
+
columnResizeMode: "onChange",
|
|
7452
|
+
defaultColumn: {
|
|
7453
|
+
size: 150, //starting column size
|
|
7454
|
+
minSize: 10, //enforced during column resizing
|
|
7455
|
+
maxSize: 10000, //enforced during column resizing
|
|
7456
|
+
},
|
|
7457
|
+
enableRowSelection: enableRowSelection,
|
|
7458
|
+
enableMultiRowSelection: enableMultiRowSelection,
|
|
7459
|
+
enableSubRowSelection: enableSubRowSelection,
|
|
7460
|
+
state: {
|
|
7461
|
+
pagination,
|
|
7462
|
+
sorting,
|
|
7463
|
+
columnFilters,
|
|
7464
|
+
rowSelection,
|
|
7465
|
+
columnOrder,
|
|
7466
|
+
globalFilter,
|
|
7467
|
+
density,
|
|
7468
|
+
columnVisibility,
|
|
7469
|
+
},
|
|
7470
|
+
onPaginationChange: setPagination,
|
|
7471
|
+
onSortingChange: setSorting,
|
|
7472
|
+
onColumnFiltersChange: setColumnFilters,
|
|
7473
|
+
onRowSelectionChange: setRowSelection,
|
|
7474
|
+
onColumnOrderChange: (state) => {
|
|
7475
|
+
setColumnOrder(state);
|
|
7476
|
+
},
|
|
7477
|
+
onGlobalFilterChange: (state) => {
|
|
7478
|
+
setGlobalFilter(state);
|
|
7479
|
+
},
|
|
7480
|
+
onDensityChange: setDensity,
|
|
7481
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
7482
|
+
// for tanstack-table ts bug start
|
|
7483
|
+
filterFns: {
|
|
7484
|
+
fuzzy: () => {
|
|
7485
|
+
return false;
|
|
7486
|
+
},
|
|
7487
|
+
},
|
|
7488
|
+
// for tanstack-table ts bug end
|
|
7489
|
+
});
|
|
7490
|
+
return (jsx(DataTableContext.Provider, { value: {
|
|
7491
|
+
table: table,
|
|
7492
|
+
globalFilter,
|
|
7493
|
+
setGlobalFilter,
|
|
7494
|
+
type: "server",
|
|
7495
|
+
translate,
|
|
7496
|
+
columns: columns,
|
|
7497
|
+
sorting,
|
|
7498
|
+
setSorting,
|
|
7499
|
+
columnFilters,
|
|
7500
|
+
setColumnFilters,
|
|
7501
|
+
pagination,
|
|
7502
|
+
setPagination,
|
|
7503
|
+
rowSelection,
|
|
7504
|
+
setRowSelection,
|
|
7505
|
+
columnOrder,
|
|
7506
|
+
setColumnOrder,
|
|
7507
|
+
density,
|
|
7508
|
+
setDensity,
|
|
7509
|
+
columnVisibility,
|
|
7510
|
+
setColumnVisibility,
|
|
7511
|
+
data: query.data?.data ?? [],
|
|
7512
|
+
tableLabel,
|
|
7513
|
+
}, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
7514
|
+
}
|
|
7515
|
+
|
|
7516
|
+
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|