@bsol-oss/react-datatable5 8.0.1 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Flex, Text, Tag as Tag$1, Input, useDisclosure, DialogBackdrop, CheckboxCard as CheckboxCard$1, Menu, createRecipeContext, createContext as createContext$1, Pagination, usePaginationContext, Image, Card, DataList, Checkbox as Checkbox$1, Table as Table$1, Tooltip as Tooltip$1, Icon, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, EmptyState as EmptyState$2, VStack, List, Alert, Group, InputElement, Popover, Field as Field$1, NumberInput, Accordion, Show, RadioCard, CheckboxGroup, Heading, Center } from '@chakra-ui/react';
3
3
  import { AiOutlineColumnWidth } from 'react-icons/ai';
4
4
  import * as React from 'react';
5
- import React__default, { createContext, useContext, useState, useEffect, useRef, useMemo } from 'react';
5
+ import React__default, { createContext, useContext, useState, useEffect, useRef } from 'react';
6
6
  import { MdFilterAlt, MdArrowUpward, MdArrowDownward, MdOutlineMoveDown, MdOutlineSort, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdOutlineChecklist, MdClose, MdSearch } from 'react-icons/md';
7
7
  import { LuX, LuCheck, LuChevronRight, LuChevronDown } from 'react-icons/lu';
8
8
  import Dayzed from '@bsol-oss/dayzed-react19';
@@ -351,7 +351,7 @@ const ResetFilteringButton = ({ text = "Reset Filtering", }) => {
351
351
  }, children: text }));
352
352
  };
353
353
 
354
- const EditFilterButton = ({ text, title = "Edit Filter", closeText = "Close", resetText = "Reset", icon = jsx(MdFilterAlt, {}), }) => {
354
+ const EditFilterButton$1 = ({ text, title = "Edit Filter", closeText = "Close", resetText = "Reset", icon = jsx(MdFilterAlt, {}), }) => {
355
355
  const filterModal = useDisclosure();
356
356
  return (jsx(Fragment, { children: jsx(DialogRoot, { size: ["full", "full", "md", "md"], open: filterModal.open, children: jsxs(DialogRoot, { children: [jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: filterModal.onOpen, children: [icon, " ", text] }) }), jsxs(DialogContent, { children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: title }) }), jsx(DialogBody, { children: jsxs(Flex, { flexFlow: "column", gap: "1rem", children: [jsx(TableFilter, {}), jsx(ResetFilteringButton, { text: resetText })] }) }), jsxs(DialogFooter, { children: [jsx(DialogActionTrigger, { asChild: true, children: jsx(Button$1, { onClick: filterModal.onClose, children: closeText }) }), jsx(Button$1, { children: "Save" })] }), jsx(DialogCloseTrigger, {})] })] }) }) }));
357
357
  };
@@ -2430,7 +2430,7 @@ const TableViewer = () => {
2430
2430
  }) }));
2431
2431
  };
2432
2432
 
2433
- const EditViewButton = ({ text, icon = jsx(IoMdEye, {}), title = "Edit View", }) => {
2433
+ const EditViewButton$1 = ({ text, icon = jsx(IoMdEye, {}), title = "Edit View", }) => {
2434
2434
  const viewModel = useDisclosure();
2435
2435
  return (jsx(Fragment, { children: jsxs(DialogRoot, { children: [jsx(DialogBackdrop, {}), jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: viewModel.onOpen, children: [icon, " ", text] }) }), jsxs(DialogContent, { children: [jsx(DialogCloseTrigger, {}), jsxs(DialogHeader, { children: [jsx(DialogTitle, {}), title] }), jsx(DialogBody, { children: jsx(TableViewer, {}) }), jsx(DialogFooter, {})] })] }) }));
2436
2436
  };
@@ -2585,7 +2585,6 @@ const snakeToLabel = (str) => {
2585
2585
  };
2586
2586
 
2587
2587
  const RecordDisplay = ({ object, boxProps }) => {
2588
- console.log(object, "dkfos");
2589
2588
  if (object === null) {
2590
2589
  return jsx(Fragment, { children: "null" });
2591
2590
  }
@@ -3178,7 +3177,7 @@ const useDataTableServerContext = () => {
3178
3177
  return { ...context, isEmpty };
3179
3178
  };
3180
3179
 
3181
- const ReloadButton = ({ text = "Reload", variant = "icon", }) => {
3180
+ const ReloadButton$1 = ({ text = "Reload", variant = "icon", }) => {
3182
3181
  const { url } = useDataTableServerContext();
3183
3182
  const queryClient = useQueryClient();
3184
3183
  if (variant === "icon") {
@@ -3223,7 +3222,7 @@ const TableComponent = ({ render = () => {
3223
3222
  return render(table);
3224
3223
  };
3225
3224
 
3226
- const TableFilterTags = () => {
3225
+ const TableFilterTags$1 = () => {
3227
3226
  const { table } = useDataTableContext();
3228
3227
  return (jsx(Flex, { gap: "0.5rem", flexFlow: "wrap", children: table.getState().columnFilters.map(({ id, value }) => {
3229
3228
  return (jsx(Tag, { gap: "0.5rem", closable: true, cursor: "pointer", onClick: () => {
@@ -3458,7 +3457,7 @@ const ErrorAlert = ({ showMessage = true }) => {
3458
3457
  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 }))] })] })) }));
3459
3458
  };
3460
3459
 
3461
- const FilterOptions = ({ column }) => {
3460
+ const FilterOptions$1 = ({ column }) => {
3462
3461
  const { table } = useDataTableContext();
3463
3462
  const tableColumn = table.getColumn(column);
3464
3463
  const options = tableColumn?.columnDef.meta?.filterOptions ?? [];
@@ -3490,7 +3489,7 @@ const InputGroup = React.forwardRef(function InputGroup(props, ref) {
3490
3489
  }), endElement && (jsx(InputElement, { placement: "end", ...endElementProps, children: endElement }))] }));
3491
3490
  });
3492
3491
 
3493
- const GlobalFilter = () => {
3492
+ const GlobalFilter$1 = () => {
3494
3493
  const { table } = useDataTableContext();
3495
3494
  const [searchTerm, setSearchTerm] = useState("");
3496
3495
  const debouncedSearchTerm = useDebounce(searchTerm, 500);
@@ -3540,16 +3539,17 @@ const Field = React.forwardRef(function Field(props, ref) {
3540
3539
  });
3541
3540
 
3542
3541
  const useSchemaContext = () => {
3543
- const { schema, serverUrl, order, ignore, onSubmit, preLoadedValues, rowNumber, displayText, } = useContext(SchemaFormContext);
3542
+ const { schema, serverUrl, order, ignore, onSubmit, rowNumber, displayText, idMap, setIdMap, } = useContext(SchemaFormContext);
3544
3543
  return {
3545
3544
  schema,
3546
3545
  serverUrl,
3547
3546
  order,
3548
3547
  ignore,
3549
3548
  onSubmit,
3550
- preLoadedValues,
3551
3549
  rowNumber,
3552
3550
  displayText,
3551
+ idMap,
3552
+ setIdMap,
3553
3553
  };
3554
3554
  };
3555
3555
 
@@ -3587,7 +3587,7 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
3587
3587
 
3588
3588
  const IdPicker = ({ column, isMultiple = false }) => {
3589
3589
  const { watch, formState: { errors }, setValue, } = useFormContext();
3590
- const { schema, serverUrl, displayText } = useSchemaContext();
3590
+ const { schema, serverUrl, displayText, idMap, setIdMap } = useSchemaContext();
3591
3591
  const { fieldRequired } = displayText;
3592
3592
  const { required } = schema;
3593
3593
  const isRequired = required?.some((columnId) => columnId === column);
@@ -3597,21 +3597,20 @@ const IdPicker = ({ column, isMultiple = false }) => {
3597
3597
  const { total, showing, typeToSearch } = displayText;
3598
3598
  const { gridColumn, gridRow, title, renderDisplay, foreign_key } = schema
3599
3599
  .properties[column];
3600
- const { table: in_table, column: column_ref, display_column } = foreign_key;
3600
+ const { table, column: column_ref, display_column, } = foreign_key;
3601
3601
  const [searchText, setSearchText] = useState();
3602
3602
  const [limit, setLimit] = useState(10);
3603
3603
  const [openSearchResult, setOpenSearchResult] = useState();
3604
3604
  const [page, setPage] = useState(0);
3605
- const [idMap, setIdMap] = useState({});
3606
3605
  const ref = useRef(null);
3607
3606
  const selectedIds = watch(column) ?? [];
3608
3607
  const query = useQuery({
3609
- queryKey: [`idpicker`, { searchText, limit, page }],
3608
+ queryKey: [`idpicker`, { column, searchText, limit, page }],
3610
3609
  queryFn: async () => {
3611
3610
  const data = await getTableData({
3612
3611
  serverUrl,
3613
3612
  searching: searchText ?? "",
3614
- in_table: in_table,
3613
+ in_table: table,
3615
3614
  limit: limit,
3616
3615
  offset: page * 10,
3617
3616
  });
@@ -3631,33 +3630,8 @@ const IdPicker = ({ column, isMultiple = false }) => {
3631
3630
  enabled: (searchText ?? "")?.length > 0,
3632
3631
  staleTime: 300000,
3633
3632
  });
3634
- useQuery({
3635
- queryKey: [`idpicker`, { selectedIds }],
3636
- queryFn: async () => {
3637
- const data = await getTableData({
3638
- serverUrl,
3639
- in_table: in_table,
3640
- limit: 1,
3641
- where: [{ id: column_ref, value: watchId }],
3642
- });
3643
- const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
3644
- return [
3645
- item[column_ref],
3646
- {
3647
- ...item,
3648
- },
3649
- ];
3650
- }));
3651
- setIdMap((state) => {
3652
- return { ...state, ...newMap };
3653
- });
3654
- return data;
3655
- },
3656
- enabled: (selectedIds ?? []).length > 0,
3657
- staleTime: 300000,
3658
- });
3659
3633
  const { isLoading, isFetching, data, isPending, isError } = query;
3660
- const dataList = useMemo(() => data?.data ?? [], [data]);
3634
+ const dataList = data?.data ?? [];
3661
3635
  const count = data?.count ?? 0;
3662
3636
  const isDirty = (searchText?.length ?? 0) > 0;
3663
3637
  const onSearchChange = async (event) => {
@@ -3733,32 +3707,16 @@ const DataListItem = React.forwardRef(function DataListItem(props, ref) {
3733
3707
  return (jsxs(DataList.Item, { ref: ref, ...rest, children: [jsxs(DataList.ItemLabel, { flex: grow ? "1" : undefined, children: [label, info && jsx(InfoTip, { children: info })] }), jsx(DataList.ItemValue, { flex: grow ? "1" : undefined, children: value }), children] }));
3734
3708
  });
3735
3709
 
3736
- const IdViewer = ({ value, column }) => {
3737
- const { schema, serverUrl } = useSchemaContext();
3710
+ const IdViewer = ({ value, column, dataListItemProps, }) => {
3711
+ const { schema, idMap } = useSchemaContext();
3738
3712
  if (schema.properties == undefined) {
3739
3713
  throw new Error("schema properties when using DatePicker");
3740
3714
  }
3741
3715
  const { title, foreign_key } = schema.properties[column];
3742
3716
  if (foreign_key === undefined) {
3743
- throw new Error('foreign_key when variant is id-picker');
3717
+ throw new Error("foreign_key when variant is id-picker");
3744
3718
  }
3745
- const { table, column: foreginKeyColumn, display_column } = foreign_key;
3746
- const query = useQuery({
3747
- queryKey: [`idpicker`, table, value],
3748
- queryFn: async () => {
3749
- return await getTableData({
3750
- serverUrl,
3751
- in_table: foreginKeyColumn ?? '',
3752
- where: [
3753
- {
3754
- id: column,
3755
- value: value,
3756
- },
3757
- ],
3758
- });
3759
- },
3760
- staleTime: 10000,
3761
- });
3719
+ const { display_column } = foreign_key;
3762
3720
  const getDataListProps = (value) => {
3763
3721
  if (value == undefined || value.length <= 0) {
3764
3722
  return {
@@ -3770,7 +3728,10 @@ const IdViewer = ({ value, column }) => {
3770
3728
  value: value,
3771
3729
  };
3772
3730
  };
3773
- return (jsx(Fragment, { children: jsx(DataListItem, { label: `${title ?? snakeToLabel(column)}`, ...getDataListProps((query.data?.data[0] ?? {})[display_column]) }) }));
3731
+ if (value === undefined) {
3732
+ return jsx(Fragment, { children: "undefined" });
3733
+ }
3734
+ return (jsx(DataListItem, { label: `${title ?? snakeToLabel(column)}`, ...getDataListProps(idMap[value][display_column]), ...dataListItemProps }));
3774
3735
  };
3775
3736
 
3776
3737
  const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
@@ -3928,156 +3889,71 @@ const DatePicker = ({ column }) => {
3928
3889
  } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: fieldRequired ?? "The field is requried" }))] }));
3929
3890
  };
3930
3891
 
3931
- const ObjectInput = ({ column }) => {
3932
- const { formState: { errors }, setValue, getValues, } = useFormContext();
3892
+ function filterArray(array, searchTerm) {
3893
+ // Convert the search term to lower case for case-insensitive comparison
3894
+ const lowerCaseSearchTerm = searchTerm.toLowerCase();
3895
+ // Use the filter method to return an array of matching items
3896
+ return array.filter((item) => {
3897
+ // Convert each item to a string and check if it includes the search term
3898
+ return item.toString().toLowerCase().includes(lowerCaseSearchTerm);
3899
+ });
3900
+ }
3901
+
3902
+ const EnumPicker = ({ column, isMultiple = false }) => {
3903
+ const { watch, formState: { errors }, setValue, } = useFormContext();
3933
3904
  const { schema, displayText } = useSchemaContext();
3934
- const { addNew, fieldRequired, save } = displayText;
3905
+ const { fieldRequired, total, showing, typeToSearch } = displayText;
3935
3906
  const { required } = schema;
3936
3907
  const isRequired = required?.some((columnId) => columnId === column);
3937
- const entries = Object.entries(getValues(column) ?? {});
3938
- const [showNewEntries, setShowNewEntries] = useState(false);
3939
- const [newKey, setNewKey] = useState();
3940
- const [newValue, setNewValue] = useState();
3941
3908
  if (schema.properties == undefined) {
3942
3909
  throw new Error("schema properties when using DatePicker");
3943
3910
  }
3944
- const { gridColumn, gridRow, title } = schema.properties[column];
3945
- return (jsxs(Field, { label: `${title ?? snakeToLabel(column)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
3946
- return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
3947
- const filtered = entries.filter(([target]) => {
3948
- return target !== key;
3949
- });
3950
- setValue(column, Object.fromEntries([...filtered, [e.target.value, value]]));
3951
- }, autoComplete: "off" }), jsx(Input, { value: value, onChange: (e) => {
3952
- setValue(column, {
3953
- ...getValues(column),
3954
- [key]: e.target.value,
3955
- });
3956
- }, autoComplete: "off" }), jsx(IconButton, { variant: "ghost", onClick: () => {
3957
- const filtered = entries.filter(([target]) => {
3958
- return target !== key;
3959
- });
3960
- setValue(column, Object.fromEntries([...filtered]));
3961
- }, children: jsx(CgClose, {}) })] }));
3962
- }), jsx(Show, { when: showNewEntries, children: jsxs(Card.Root, { children: [jsx(Card.Body, { gap: "2", children: jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: newKey, onChange: (e) => {
3963
- setNewKey(e.target.value);
3964
- }, autoComplete: "off" }), jsx(Input, { value: newValue, onChange: (e) => {
3965
- setNewValue(e.target.value);
3966
- }, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant: "subtle", onClick: () => {
3967
- setShowNewEntries(false);
3968
- setNewKey(undefined);
3969
- setNewValue(undefined);
3970
- }, children: jsx(CgClose, {}) }), jsx(Button, { onClick: () => {
3971
- if (!!newKey === false) {
3972
- setShowNewEntries(false);
3973
- setNewKey(undefined);
3974
- setNewValue(undefined);
3975
- return;
3976
- }
3977
- setValue(column, Object.fromEntries([...entries, [newKey, newValue]]));
3978
- setShowNewEntries(false);
3979
- setNewKey(undefined);
3980
- setNewValue(undefined);
3981
- }, children: save ?? "Save" })] })] }) }), jsx(Button, { onClick: () => {
3982
- setShowNewEntries(true);
3983
- setNewKey(undefined);
3984
- setNewValue(undefined);
3985
- }, children: addNew ?? "Add New" }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: fieldRequired ?? "The field is requried" }))] }));
3986
- };
3987
-
3988
- const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
3989
- const { inputProps, label, description, addon, icon, indicator = jsx(RadioCard.ItemIndicator, {}), indicatorPlacement = "end", ...rest } = props;
3990
- const hasContent = label || description || icon;
3991
- const ContentWrapper = indicator ? RadioCard.ItemContent : React.Fragment;
3992
- return (jsxs(RadioCard.Item, { ...rest, children: [jsx(RadioCard.ItemHiddenInput, { ref: ref, ...inputProps }), jsxs(RadioCard.ItemControl, { children: [indicatorPlacement === "start" && indicator, hasContent && (jsxs(ContentWrapper, { children: [icon, label && jsx(RadioCard.ItemText, { children: label }), description && (jsx(RadioCard.ItemDescription, { children: description })), indicatorPlacement === "inside" && indicator] })), indicatorPlacement === "end" && indicator] }), addon && jsx(RadioCard.ItemAddon, { children: addon })] }));
3993
- });
3994
- const RadioCardRoot = RadioCard.Root;
3995
- RadioCard.Label;
3996
- RadioCard.ItemIndicator;
3997
-
3998
- const TagPicker = ({ column }) => {
3999
- const { watch, formState: { errors }, setValue, } = useFormContext();
4000
- const { schema, serverUrl } = useSchemaContext();
4001
- if (schema.properties == undefined) {
4002
- throw new Error("schema properties undefined when using DatePicker");
4003
- }
4004
- const { gridColumn, gridRow, in_table, object_id_column } = schema.properties[column];
4005
- if (in_table === undefined) {
4006
- throw new Error("in_table is undefined when using TagPicker");
4007
- }
4008
- if (object_id_column === undefined) {
4009
- throw new Error("object_id_column is undefined when using TagPicker");
4010
- }
4011
- const query = useQuery({
4012
- queryKey: [`tagpicker`, in_table],
4013
- queryFn: async () => {
4014
- return await getTableData({
4015
- serverUrl,
4016
- in_table: "tables_tags_view",
4017
- where: [
4018
- {
4019
- id: "table_name",
4020
- value: [in_table],
4021
- },
4022
- ],
4023
- limit: 100,
4024
- });
4025
- },
4026
- staleTime: 10000,
4027
- });
4028
- const object_id = watch(object_id_column);
4029
- const existingTagsQuery = useQuery({
4030
- queryKey: [`existing`, in_table, object_id_column, object_id],
4031
- queryFn: async () => {
4032
- return await getTableData({
4033
- serverUrl,
4034
- in_table: in_table,
4035
- where: [
4036
- {
4037
- id: object_id_column,
4038
- value: object_id[0],
4039
- },
4040
- ],
4041
- limit: 100,
4042
- });
4043
- },
4044
- enabled: object_id != undefined,
4045
- staleTime: 10000,
4046
- });
4047
- const { isLoading, isFetching, data, isPending, isError } = query;
4048
- const dataList = data?.data ?? [];
4049
- const existingTagList = existingTagsQuery.data?.data ?? [];
4050
- if (!!object_id === false) {
4051
- return jsx(Fragment, {});
4052
- }
4053
- return (jsxs(Flex, { flexFlow: "column", gap: 4, gridColumn,
4054
- gridRow, children: [isFetching && jsx(Fragment, { children: "isFetching" }), isLoading && jsx(Fragment, { children: "isLoading" }), isPending && jsx(Fragment, { children: "isPending" }), isError && jsx(Fragment, { children: "isError" }), dataList.map(({ parent_tag_name, all_tags, is_mutually_exclusive }) => {
4055
- return (jsxs(Flex, { flexFlow: "column", gap: 2, children: [jsx(Text, { children: parent_tag_name }), is_mutually_exclusive && (jsx(RadioCardRoot, { defaultValue: "next", variant: "surface", onValueChange: (tagIds) => {
4056
- const existedTags = Object.values(all_tags)
4057
- .filter(({ id }) => {
4058
- return existingTagList.some(({ tag_id }) => tag_id === id);
4059
- })
4060
- .map(({ id }) => {
4061
- return id;
4062
- });
4063
- setValue(`${column}.${parent_tag_name}.current`, [
4064
- tagIds.value,
4065
- ]);
4066
- setValue(`${column}.${parent_tag_name}.old`, existedTags);
4067
- }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
4068
- if (existingTagList.some(({ tag_id }) => tag_id === id)) {
4069
- return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", disabled: true }, `${tagName}-${id}`));
4070
- }
4071
- return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", colorPalette: "blue" }, `${tagName}-${id}`));
4072
- }) }) })), !is_mutually_exclusive && (jsx(CheckboxGroup, { onValueChange: (tagIds) => {
4073
- setValue(`${column}.${parent_tag_name}.current`, tagIds);
4074
- }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
4075
- if (existingTagList.some(({ tag_id }) => tag_id === id)) {
4076
- return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%", disabled: true, colorPalette: "blue" }, `${tagName}-${id}`));
4077
- }
4078
- return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%" }, `${tagName}-${id}`));
4079
- }) }) }))] }, `tag-${parent_tag_name}`));
4080
- }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
3911
+ const { gridColumn, gridRow, title, renderDisplay } = schema.properties[column];
3912
+ const [searchText, setSearchText] = useState();
3913
+ const [limit, setLimit] = useState(10);
3914
+ const [openSearchResult, setOpenSearchResult] = useState();
3915
+ const ref = useRef(null);
3916
+ const watchEnum = watch(column);
3917
+ const watchEnums = (watch(column) ?? []);
3918
+ const properties = (schema.properties[column] ?? {});
3919
+ const dataList = properties.enum ?? [];
3920
+ const count = properties.enum?.length ?? 0;
3921
+ const isDirty = (searchText?.length ?? 0) > 0;
3922
+ const onSearchChange = async (event) => {
3923
+ setSearchText(event.target.value);
3924
+ setLimit(10);
3925
+ };
3926
+ return (jsxs(Field, { label: `${title ?? snakeToLabel(column)}`, required: isRequired, alignItems: "stretch", gridColumn,
3927
+ gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchEnums.map((enumValue) => {
3928
+ const item = enumValue;
3929
+ if (item === undefined) {
3930
+ return jsx(Fragment, { children: "undefined" });
3931
+ }
3932
+ return (jsx(Tag, { closable: true, onClick: () => {
3933
+ setSelectedEnums((state) => state.filter((id) => id != item));
3934
+ setValue(column, watchEnums.filter((id) => id != item));
3935
+ }, children: !!renderDisplay === true ? renderDisplay(item) : item }));
3936
+ }), jsx(Tag, { cursor: "pointer", onClick: () => {
3937
+ setOpenSearchResult(true);
3938
+ }, children: "Add" })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
3939
+ setOpenSearchResult(true);
3940
+ }, children: watchEnum })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: typeToSearch ?? "Type to search", onChange: (event) => {
3941
+ onSearchChange(event);
3942
+ setOpenSearchResult(true);
3943
+ }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), jsx(Text, { children: `${total ?? "Total"}: ${count}, ${showing ?? "Showing"} ${limit}` }), jsxs(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsx(Flex, { flexFlow: "column wrap", children: filterArray(dataList, searchText ?? "").map((item) => {
3944
+ const selected = isMultiple
3945
+ ? watchEnums.some((enumValue) => item === enumValue)
3946
+ : watchEnum == item;
3947
+ return (jsx(Box, { cursor: "pointer", onClick: () => {
3948
+ if (!isMultiple) {
3949
+ setOpenSearchResult(false);
3950
+ setValue(column, item);
3951
+ return;
3952
+ }
3953
+ const newSet = new Set([...(watchEnums ?? []), item]);
3954
+ setValue(column, [...newSet]);
3955
+ }, ...(selected ? { color: "gray.400/50" } : {}), children: !!renderDisplay === true ? renderDisplay(item) : item }, `${column}-${item}`));
3956
+ }) }), isDirty && (jsxs(Fragment, { children: [dataList.length <= 0 && jsx(Fragment, { children: "Empty Search Result" }), " "] }))] })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: fieldRequired ?? "The field is requried" }))] }));
4081
3957
  };
4082
3958
 
4083
3959
  function isEnteringWindow(_ref) {
@@ -4455,71 +4331,156 @@ const FilePicker = ({ column }) => {
4455
4331
  }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: fieldRequired ?? "The field is requried" }))] }));
4456
4332
  };
4457
4333
 
4458
- function filterArray(array, searchTerm) {
4459
- // Convert the search term to lower case for case-insensitive comparison
4460
- const lowerCaseSearchTerm = searchTerm.toLowerCase();
4461
- // Use the filter method to return an array of matching items
4462
- return array.filter((item) => {
4463
- // Convert each item to a string and check if it includes the search term
4464
- return item.toString().toLowerCase().includes(lowerCaseSearchTerm);
4465
- });
4466
- }
4467
-
4468
- const EnumPicker = ({ column, isMultiple = false }) => {
4469
- const { watch, formState: { errors }, setValue, } = useFormContext();
4334
+ const ObjectInput = ({ column }) => {
4335
+ const { formState: { errors }, setValue, getValues, } = useFormContext();
4470
4336
  const { schema, displayText } = useSchemaContext();
4471
- const { fieldRequired, total, showing, typeToSearch } = displayText;
4337
+ const { addNew, fieldRequired, save } = displayText;
4472
4338
  const { required } = schema;
4473
4339
  const isRequired = required?.some((columnId) => columnId === column);
4340
+ const entries = Object.entries(getValues(column) ?? {});
4341
+ const [showNewEntries, setShowNewEntries] = useState(false);
4342
+ const [newKey, setNewKey] = useState();
4343
+ const [newValue, setNewValue] = useState();
4474
4344
  if (schema.properties == undefined) {
4475
4345
  throw new Error("schema properties when using DatePicker");
4476
4346
  }
4477
- const { gridColumn, gridRow, title, renderDisplay } = schema.properties[column];
4478
- const [searchText, setSearchText] = useState();
4479
- const [limit, setLimit] = useState(10);
4480
- const [openSearchResult, setOpenSearchResult] = useState();
4481
- const ref = useRef(null);
4482
- const watchEnum = watch(column);
4483
- const watchEnums = (watch(column) ?? []);
4484
- const properties = (schema.properties[column] ?? {});
4485
- const dataList = properties.enum ?? [];
4486
- const count = properties.enum?.length ?? 0;
4487
- const isDirty = (searchText?.length ?? 0) > 0;
4488
- const onSearchChange = async (event) => {
4489
- setSearchText(event.target.value);
4490
- setLimit(10);
4491
- };
4492
- return (jsxs(Field, { label: `${title ?? snakeToLabel(column)}`, required: isRequired, alignItems: "stretch", gridColumn,
4493
- gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchEnums.map((enumValue) => {
4494
- const item = enumValue;
4495
- if (item === undefined) {
4496
- return jsx(Fragment, { children: "undefined" });
4497
- }
4498
- return (jsx(Tag, { closable: true, onClick: () => {
4499
- setSelectedEnums((state) => state.filter((id) => id != item));
4500
- setValue(column, watchEnums.filter((id) => id != item));
4501
- }, children: !!renderDisplay === true ? renderDisplay(item) : item }));
4502
- }), jsx(Tag, { cursor: "pointer", onClick: () => {
4503
- setOpenSearchResult(true);
4504
- }, children: "Add" })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
4505
- setOpenSearchResult(true);
4506
- }, children: watchEnum })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: typeToSearch ?? "Type to search", onChange: (event) => {
4507
- onSearchChange(event);
4508
- setOpenSearchResult(true);
4509
- }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), jsx(Text, { children: `${total ?? "Total"}: ${count}, ${showing ?? "Showing"} ${limit}` }), jsxs(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsx(Flex, { flexFlow: "column wrap", children: filterArray(dataList, searchText ?? "").map((item) => {
4510
- const selected = isMultiple
4511
- ? watchEnums.some((enumValue) => item === enumValue)
4512
- : watchEnum == item;
4513
- return (jsx(Box, { cursor: "pointer", onClick: () => {
4514
- if (!isMultiple) {
4515
- setOpenSearchResult(false);
4516
- setValue(column, item);
4517
- return;
4518
- }
4519
- const newSet = new Set([...(watchEnums ?? []), item]);
4520
- setValue(column, [...newSet]);
4521
- }, ...(selected ? { color: "gray.400/50" } : {}), children: !!renderDisplay === true ? renderDisplay(item) : item }, `${column}-${item}`));
4522
- }) }), isDirty && (jsxs(Fragment, { children: [dataList.length <= 0 && jsx(Fragment, { children: "Empty Search Result" }), " "] }))] })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: fieldRequired ?? "The field is requried" }))] }));
4347
+ const { gridColumn, gridRow, title } = schema.properties[column];
4348
+ return (jsxs(Field, { label: `${title ?? snakeToLabel(column)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4349
+ return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
4350
+ const filtered = entries.filter(([target]) => {
4351
+ return target !== key;
4352
+ });
4353
+ setValue(column, Object.fromEntries([...filtered, [e.target.value, value]]));
4354
+ }, autoComplete: "off" }), jsx(Input, { value: value, onChange: (e) => {
4355
+ setValue(column, {
4356
+ ...getValues(column),
4357
+ [key]: e.target.value,
4358
+ });
4359
+ }, autoComplete: "off" }), jsx(IconButton, { variant: "ghost", onClick: () => {
4360
+ const filtered = entries.filter(([target]) => {
4361
+ return target !== key;
4362
+ });
4363
+ setValue(column, Object.fromEntries([...filtered]));
4364
+ }, children: jsx(CgClose, {}) })] }));
4365
+ }), jsx(Show, { when: showNewEntries, children: jsxs(Card.Root, { children: [jsx(Card.Body, { gap: "2", children: jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: newKey, onChange: (e) => {
4366
+ setNewKey(e.target.value);
4367
+ }, autoComplete: "off" }), jsx(Input, { value: newValue, onChange: (e) => {
4368
+ setNewValue(e.target.value);
4369
+ }, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant: "subtle", onClick: () => {
4370
+ setShowNewEntries(false);
4371
+ setNewKey(undefined);
4372
+ setNewValue(undefined);
4373
+ }, children: jsx(CgClose, {}) }), jsx(Button, { onClick: () => {
4374
+ if (!!newKey === false) {
4375
+ setShowNewEntries(false);
4376
+ setNewKey(undefined);
4377
+ setNewValue(undefined);
4378
+ return;
4379
+ }
4380
+ setValue(column, Object.fromEntries([...entries, [newKey, newValue]]));
4381
+ setShowNewEntries(false);
4382
+ setNewKey(undefined);
4383
+ setNewValue(undefined);
4384
+ }, children: save ?? "Save" })] })] }) }), jsx(Button, { onClick: () => {
4385
+ setShowNewEntries(true);
4386
+ setNewKey(undefined);
4387
+ setNewValue(undefined);
4388
+ }, children: addNew ?? "Add New" }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: fieldRequired ?? "The field is requried" }))] }));
4389
+ };
4390
+
4391
+ const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
4392
+ const { inputProps, label, description, addon, icon, indicator = jsx(RadioCard.ItemIndicator, {}), indicatorPlacement = "end", ...rest } = props;
4393
+ const hasContent = label || description || icon;
4394
+ const ContentWrapper = indicator ? RadioCard.ItemContent : React.Fragment;
4395
+ return (jsxs(RadioCard.Item, { ...rest, children: [jsx(RadioCard.ItemHiddenInput, { ref: ref, ...inputProps }), jsxs(RadioCard.ItemControl, { children: [indicatorPlacement === "start" && indicator, hasContent && (jsxs(ContentWrapper, { children: [icon, label && jsx(RadioCard.ItemText, { children: label }), description && (jsx(RadioCard.ItemDescription, { children: description })), indicatorPlacement === "inside" && indicator] })), indicatorPlacement === "end" && indicator] }), addon && jsx(RadioCard.ItemAddon, { children: addon })] }));
4396
+ });
4397
+ const RadioCardRoot = RadioCard.Root;
4398
+ RadioCard.Label;
4399
+ RadioCard.ItemIndicator;
4400
+
4401
+ const TagPicker = ({ column }) => {
4402
+ const { watch, formState: { errors }, setValue, } = useFormContext();
4403
+ const { schema, serverUrl } = useSchemaContext();
4404
+ if (schema.properties == undefined) {
4405
+ throw new Error("schema properties undefined when using DatePicker");
4406
+ }
4407
+ const { gridColumn, gridRow, in_table, object_id_column } = schema.properties[column];
4408
+ if (in_table === undefined) {
4409
+ throw new Error("in_table is undefined when using TagPicker");
4410
+ }
4411
+ if (object_id_column === undefined) {
4412
+ throw new Error("object_id_column is undefined when using TagPicker");
4413
+ }
4414
+ const query = useQuery({
4415
+ queryKey: [`tagpicker`, in_table],
4416
+ queryFn: async () => {
4417
+ return await getTableData({
4418
+ serverUrl,
4419
+ in_table: "tables_tags_view",
4420
+ where: [
4421
+ {
4422
+ id: "table_name",
4423
+ value: [in_table],
4424
+ },
4425
+ ],
4426
+ limit: 100,
4427
+ });
4428
+ },
4429
+ staleTime: 10000,
4430
+ });
4431
+ const object_id = watch(object_id_column);
4432
+ const existingTagsQuery = useQuery({
4433
+ queryKey: [`existing`, in_table, object_id_column, object_id],
4434
+ queryFn: async () => {
4435
+ return await getTableData({
4436
+ serverUrl,
4437
+ in_table: in_table,
4438
+ where: [
4439
+ {
4440
+ id: object_id_column,
4441
+ value: object_id[0],
4442
+ },
4443
+ ],
4444
+ limit: 100,
4445
+ });
4446
+ },
4447
+ enabled: object_id != undefined,
4448
+ staleTime: 10000,
4449
+ });
4450
+ const { isLoading, isFetching, data, isPending, isError } = query;
4451
+ const dataList = data?.data ?? [];
4452
+ const existingTagList = existingTagsQuery.data?.data ?? [];
4453
+ if (!!object_id === false) {
4454
+ return jsx(Fragment, {});
4455
+ }
4456
+ return (jsxs(Flex, { flexFlow: "column", gap: 4, gridColumn,
4457
+ gridRow, children: [isFetching && jsx(Fragment, { children: "isFetching" }), isLoading && jsx(Fragment, { children: "isLoading" }), isPending && jsx(Fragment, { children: "isPending" }), isError && jsx(Fragment, { children: "isError" }), dataList.map(({ parent_tag_name, all_tags, is_mutually_exclusive }) => {
4458
+ return (jsxs(Flex, { flexFlow: "column", gap: 2, children: [jsx(Text, { children: parent_tag_name }), is_mutually_exclusive && (jsx(RadioCardRoot, { defaultValue: "next", variant: "surface", onValueChange: (tagIds) => {
4459
+ const existedTags = Object.values(all_tags)
4460
+ .filter(({ id }) => {
4461
+ return existingTagList.some(({ tag_id }) => tag_id === id);
4462
+ })
4463
+ .map(({ id }) => {
4464
+ return id;
4465
+ });
4466
+ setValue(`${column}.${parent_tag_name}.current`, [
4467
+ tagIds.value,
4468
+ ]);
4469
+ setValue(`${column}.${parent_tag_name}.old`, existedTags);
4470
+ }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
4471
+ if (existingTagList.some(({ tag_id }) => tag_id === id)) {
4472
+ return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", disabled: true }, `${tagName}-${id}`));
4473
+ }
4474
+ return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", colorPalette: "blue" }, `${tagName}-${id}`));
4475
+ }) }) })), !is_mutually_exclusive && (jsx(CheckboxGroup, { onValueChange: (tagIds) => {
4476
+ setValue(`${column}.${parent_tag_name}.current`, tagIds);
4477
+ }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
4478
+ if (existingTagList.some(({ tag_id }) => tag_id === id)) {
4479
+ return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%", disabled: true, colorPalette: "blue" }, `${tagName}-${id}`));
4480
+ }
4481
+ return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%" }, `${tagName}-${id}`));
4482
+ }) }) }))] }, `tag-${parent_tag_name}`));
4483
+ }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
4523
4484
  };
4524
4485
 
4525
4486
  const idPickerSanityCheck = (column, foreign_key) => {
@@ -4538,7 +4499,7 @@ const idPickerSanityCheck = (column, foreign_key) => {
4538
4499
  }
4539
4500
  };
4540
4501
  const FormInternal = () => {
4541
- const { schema, serverUrl, displayText, order, ignore, onSubmit, rowNumber } = useSchemaContext();
4502
+ const { schema, serverUrl, displayText, order, ignore, onSubmit, rowNumber, idMap, } = useSchemaContext();
4542
4503
  const { title, submit, empty, cancel, submitSuccess, submitAgain, confirm } = displayText;
4543
4504
  const methods = useFormContext();
4544
4505
  const [isSuccess, setIsSuccess] = useState(false);
@@ -4645,8 +4606,7 @@ const FormInternal = () => {
4645
4606
  if (variant === "id-picker") {
4646
4607
  idPickerSanityCheck(column, foreign_key);
4647
4608
  return (jsx(IdViewer, { value: (validatedData ?? {})[column], column,
4648
- gridColumn,
4649
- gridRow }, `form-${key}`));
4609
+ dataListItemProps: { gridColumn, gridRow } }, `form-${key}`));
4650
4610
  }
4651
4611
  if (variant === "date-picker") {
4652
4612
  const value = (validatedData ?? {})[column];
@@ -4684,6 +4644,22 @@ const FormInternal = () => {
4684
4644
  });
4685
4645
  return (jsx(DataListItem, { gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 4", label: `${snakeToLabel(column)}`, ...getDataListProps(JSON.stringify(fileNames)) }, `form-${key}`));
4686
4646
  }
4647
+ if (variant === "id-picker") {
4648
+ const value = (validatedData ?? {})[column];
4649
+ if (schema.properties == undefined) {
4650
+ throw new Error("schema properties when using DatePicker");
4651
+ }
4652
+ const { foreign_key } = schema.properties[column];
4653
+ if (foreign_key === undefined) {
4654
+ throw new Error("foreign_key when variant is id-picker");
4655
+ }
4656
+ const { display_column } = foreign_key;
4657
+ const mapped = value.map((item) => {
4658
+ return idMap[item][display_column];
4659
+ });
4660
+ return (jsxs(Grid, { flexFlow: "column", gridColumn,
4661
+ gridRow, children: [jsx(Text, { children: snakeToLabel(column) }), jsx(RecordDisplay, { object: mapped })] }, `form-${key}`));
4662
+ }
4687
4663
  const objectString = JSON.stringify((validatedData ?? {})[column]);
4688
4664
  return (jsx(DataListItem, { gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 4", label: `${snakeToLabel(column)}`, ...getDataListProps(objectString) }, `form-${key}`));
4689
4665
  }
@@ -4710,8 +4686,9 @@ const FormInternal = () => {
4710
4686
  return jsx(Fragment, {});
4711
4687
  }
4712
4688
  //@ts-expect-error TODO: add more fields to support form-creation
4713
- const { type, variant, in_table, column_ref, foreign_key } = values;
4689
+ const { type, variant, foreign_key } = values;
4714
4690
  if (type === "string") {
4691
+ // @ts-expect-error enum should exists
4715
4692
  if ((values.enum ?? []).length > 0) {
4716
4693
  return jsx(EnumPicker, { column: key }, `form-${key}`);
4717
4694
  }
@@ -4757,6 +4734,7 @@ const FormInternal = () => {
4757
4734
  const Form = ({ schema, serverUrl, order = [], ignore = [], onSubmit = undefined, preLoadedValues = {}, rowNumber = undefined, displayText = {}, }) => {
4758
4735
  const queryClient = new QueryClient();
4759
4736
  const methods = useForm({ values: preLoadedValues });
4737
+ const [idMap, setIdMap] = useState({});
4760
4738
  const { properties } = schema;
4761
4739
  idListSanityCheck("order", order, properties);
4762
4740
  idListSanityCheck("ignore", ignore, properties);
@@ -4770,6 +4748,8 @@ const Form = ({ schema, serverUrl, order = [], ignore = [], onSubmit = undefined
4770
4748
  // @ts-expect-error TODO: find appropriate types
4771
4749
  onSubmit,
4772
4750
  rowNumber,
4751
+ idMap,
4752
+ setIdMap,
4773
4753
  }, children: jsx(FormProvider, { ...methods, children: jsx(FormInternal, {}) }) }) }));
4774
4754
  };
4775
4755
 
@@ -4789,4 +4769,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
4789
4769
  }
4790
4770
  };
4791
4771
 
4792
- export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultTable, DensityToggleButton, EditFilterButton, EditOrderButton, EditSortingButton, EditViewButton, EmptyState, ErrorAlert, FilterOptions, Form, GlobalFilter, PageSizeControl, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableOrderer, TablePagination, TableSelector, TableSorter, TableViewer, TextCell, getColumns, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, widthSanityCheck };
4772
+ export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultTable, DensityToggleButton, EditFilterButton$1 as EditFilterButton, EditOrderButton, EditSortingButton, EditViewButton$1 as EditViewButton, EmptyState, ErrorAlert, FilterOptions$1 as FilterOptions, Form, GlobalFilter$1 as GlobalFilter, PageSizeControl, RecordDisplay, ReloadButton$1 as ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableFilter, TableFilterTags$1 as TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableOrderer, TablePagination, TableSelector, TableSorter, TableViewer, TextCell, getColumns, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, widthSanityCheck };