@bsol-oss/react-datatable5 13.0.1-beta.1 → 13.0.1-beta.2

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 CHANGED
@@ -817,12 +817,25 @@ interface TimePickerLabels {
817
817
  placeholder?: string;
818
818
  emptyMessage?: string;
819
819
  }
820
+ interface LoadInitialValuesParams {
821
+ ids: string[];
822
+ foreign_key: ForeignKeyProps;
823
+ setIdMap: React__default.Dispatch<React__default.SetStateAction<Record<string, object>>>;
824
+ }
825
+ interface LoadInitialValuesResult {
826
+ data: {
827
+ data: Record<string, any>[];
828
+ count: number;
829
+ };
830
+ idMap: Record<string, object>;
831
+ }
820
832
  interface CustomJSONSchema7 extends JSONSchema7 {
821
833
  gridColumn?: string;
822
834
  gridRow?: string;
823
835
  foreign_key?: ForeignKeyProps;
824
836
  variant?: string;
825
837
  renderDisplay?: (item: unknown) => ReactNode;
838
+ loadInitialValues?: (params: LoadInitialValuesParams) => Promise<LoadInitialValuesResult>;
826
839
  inputRender?: (props: {
827
840
  column: string;
828
841
  schema: CustomJSONSchema7;
@@ -844,6 +857,24 @@ interface CustomJSONSchema7 extends JSONSchema7 {
844
857
  numberStorageType?: 'string' | 'number';
845
858
  errorMessages?: Partial<Record<ValidationErrorType | string, string>>;
846
859
  filePicker?: FilePickerProps;
860
+ tagPicker?: {
861
+ queryFn?: (params: {
862
+ in_table: string;
863
+ where?: {
864
+ id: string;
865
+ value: string[];
866
+ }[];
867
+ limit?: number;
868
+ offset?: number;
869
+ searching?: string;
870
+ }) => Promise<{
871
+ data: {
872
+ data: any[];
873
+ count: number;
874
+ };
875
+ idMap?: Record<string, object>;
876
+ }>;
877
+ };
847
878
  }
848
879
  declare const defaultRenderDisplay: (item: unknown) => ReactNode;
849
880
  interface TagPickerProps {
@@ -869,7 +900,6 @@ interface FilePickerProps {
869
900
 
870
901
  interface FormRootProps<TData extends FieldValues> {
871
902
  schema: CustomJSONSchema7;
872
- serverUrl: string;
873
903
  requestUrl?: string;
874
904
  idMap: Record<string, object>;
875
905
  setIdMap: Dispatch<SetStateAction<Record<string, object>>>;
@@ -913,7 +943,7 @@ declare const idPickerSanityCheck: (column: string, foreign_key?: {
913
943
  table?: string | undefined;
914
944
  column?: string | undefined;
915
945
  } | undefined) => void;
916
- declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, serverUrl, translate, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, requireConfirmation, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => react_jsx_runtime.JSX.Element;
946
+ declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, translate, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, requireConfirmation, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => react_jsx_runtime.JSX.Element;
917
947
 
918
948
  interface DefaultFormProps<TData extends FieldValues> {
919
949
  formConfig: Omit<FormRootProps<TData>, "children">;
@@ -1388,4 +1418,4 @@ declare module '@tanstack/react-table' {
1388
1418
  }
1389
1419
  }
1390
1420
 
1391
- export { CalendarDisplay, type CalendarDisplayProps, type CalendarEvent, type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, DatePickerInput, type DatePickerInputProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type ErrorMessageConfig, type ErrorMessageResult, type FieldErrorConfig, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, type GetColumnsConfigs, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, MediaLibraryBrowser, type MediaLibraryBrowserProps, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerLabels, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, SelectAllRowsToggle, type SelectAllRowsToggleProps, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, type TagPickerProps, TextCell, type TextCellProps, type TimePickerLabels, type Translate, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type ValidationErrorType, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
1421
+ export { CalendarDisplay, type CalendarDisplayProps, type CalendarEvent, type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, DatePickerInput, type DatePickerInputProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type ErrorMessageConfig, type ErrorMessageResult, type FieldErrorConfig, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, type GetColumnsConfigs, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, type LoadInitialValuesParams, type LoadInitialValuesResult, MediaLibraryBrowser, type MediaLibraryBrowserProps, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerLabels, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, SelectAllRowsToggle, type SelectAllRowsToggleProps, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, type TagPickerProps, TextCell, type TextCellProps, type TimePickerLabels, type Translate, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type ValidationErrorType, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
package/dist/index.js CHANGED
@@ -4036,7 +4036,6 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
4036
4036
  //@ts-expect-error TODO: find appropriate type
4037
4037
  const SchemaFormContext = React.createContext({
4038
4038
  schema: {},
4039
- serverUrl: '',
4040
4039
  requestUrl: '',
4041
4040
  order: [],
4042
4041
  ignore: [],
@@ -4276,7 +4275,7 @@ const idPickerSanityCheck = (column, foreign_key) => {
4276
4275
  throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
4277
4276
  }
4278
4277
  };
4279
- const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
4278
+ const FormRoot = ({ schema, idMap, setIdMap, form, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
4280
4279
  showSubmitButton: true,
4281
4280
  showResetButton: true,
4282
4281
  showTitle: true,
@@ -4317,9 +4316,11 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
4317
4316
  }
4318
4317
  };
4319
4318
  const defaultSubmitPromise = (data) => {
4319
+ if (!requestOptions.url) {
4320
+ throw new Error('requestOptions.url is required when onSubmit is not provided');
4321
+ }
4320
4322
  const options = {
4321
4323
  method: 'POST',
4322
- url: `${serverUrl}`,
4323
4324
  data: clearEmptyString(data),
4324
4325
  ...requestOptions,
4325
4326
  };
@@ -4337,7 +4338,6 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
4337
4338
  };
4338
4339
  return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
4339
4340
  schema,
4340
- serverUrl,
4341
4341
  order,
4342
4342
  ignore,
4343
4343
  include,
@@ -5618,106 +5618,20 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
5618
5618
  }) })] }));
5619
5619
  };
5620
5620
 
5621
- const getTableData = async ({ serverUrl, in_table, searching = "", where = [], limit = 10, offset = 0, }) => {
5622
- if (serverUrl === undefined || serverUrl.length == 0) {
5623
- throw new Error("The serverUrl is missing");
5624
- }
5625
- if (in_table === undefined || in_table.length == 0) {
5626
- throw new Error("The in_table is missing");
5627
- }
5628
- const options = {
5629
- method: "GET",
5630
- url: `${serverUrl}/api/g/${in_table}`,
5631
- params: {
5632
- searching,
5633
- where,
5634
- limit,
5635
- offset
5636
- },
5637
- };
5638
- try {
5639
- const { data } = await axios.request(options);
5640
- console.log(data);
5641
- return data;
5642
- }
5643
- catch (error) {
5644
- console.error(error);
5645
- throw error;
5646
- }
5647
- };
5648
-
5649
5621
  // Default renderDisplay function that stringifies JSON
5650
5622
  const defaultRenderDisplay = (item) => {
5651
5623
  return JSON.stringify(item);
5652
5624
  };
5653
5625
 
5654
- /**
5655
- * Load initial values for IdPicker fields into idMap
5656
- * Uses customQueryFn if available, otherwise falls back to getTableData
5657
- *
5658
- * @param params - Configuration for loading initial values
5659
- * @returns Promise with fetched data and idMap
5660
- */
5661
- const loadInitialValues = async ({ ids, foreign_key, serverUrl, setIdMap, }) => {
5662
- if (!ids || ids.length === 0) {
5663
- return { data: { data: [], count: 0 }, idMap: {} };
5664
- }
5665
- const { table, column: column_ref, customQueryFn } = foreign_key;
5666
- // Filter out IDs that are already in idMap (optional optimization)
5667
- // For now, we'll fetch all requested IDs to ensure consistency
5668
- if (customQueryFn) {
5669
- const { data, idMap: returnedIdMap } = await customQueryFn({
5670
- searching: '',
5671
- limit: ids.length,
5672
- offset: 0,
5673
- where: [
5674
- {
5675
- id: column_ref,
5676
- value: ids.length === 1 ? ids[0] : ids, // CustomQueryFn accepts string | string[]
5677
- },
5678
- ],
5679
- });
5680
- // Update idMap with returned values
5681
- if (returnedIdMap && Object.keys(returnedIdMap).length > 0) {
5682
- setIdMap((state) => {
5683
- return { ...state, ...returnedIdMap };
5684
- });
5685
- }
5686
- return { data, idMap: returnedIdMap || {} };
5687
- }
5688
- // Fallback to default getTableData
5689
- const data = await getTableData({
5690
- serverUrl,
5691
- searching: '',
5692
- in_table: table,
5693
- limit: ids.length,
5694
- offset: 0,
5695
- where: [
5696
- {
5697
- id: column_ref,
5698
- value: ids, // Always pass as array
5699
- },
5700
- ],
5701
- });
5702
- // Build idMap from fetched data
5703
- const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
5704
- return [
5705
- item[column_ref],
5706
- {
5707
- ...item,
5708
- },
5709
- ];
5710
- }));
5711
- // Update idMap state
5712
- setIdMap((state) => {
5713
- return { ...state, ...newMap };
5714
- });
5715
- return { data: data, idMap: newMap };
5716
- };
5717
5626
  const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5718
5627
  const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
5719
- const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
5720
- const { renderDisplay, foreign_key } = schema;
5628
+ const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
5629
+ const { renderDisplay, loadInitialValues: schemaLoadInitialValues, foreign_key, variant, } = schema;
5630
+ // loadInitialValues must be provided in schema for id-picker fields
5631
+ // It's used to load the record of the id so the display is human-readable
5632
+ if (variant === 'id-picker' && !schemaLoadInitialValues) {
5633
+ throw new Error(`loadInitialValues is required in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
5634
+ }
5721
5635
  const { table, column: column_ref, customQueryFn, } = foreign_key;
5722
5636
  const [searchText, setSearchText] = React.useState('');
5723
5637
  const [debouncedSearchText, setDebouncedSearchText] = React.useState('');
@@ -5770,11 +5684,13 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5770
5684
  if (missingIds.length === 0) {
5771
5685
  return { data: [], count: 0 };
5772
5686
  }
5773
- // Use the reusable loadInitialValues function
5774
- const result = await loadInitialValues({
5687
+ // Use schema's loadInitialValues (required for id-picker)
5688
+ if (!schemaLoadInitialValues) {
5689
+ throw new Error(`loadInitialValues is required in schema for IdPicker field '${column}'.`);
5690
+ }
5691
+ const result = await schemaLoadInitialValues({
5775
5692
  ids: missingIds,
5776
5693
  foreign_key: foreign_key,
5777
- serverUrl,
5778
5694
  setIdMap,
5779
5695
  });
5780
5696
  return result.data;
@@ -5787,35 +5703,21 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5787
5703
  const query = reactQuery.useQuery({
5788
5704
  queryKey: [`idpicker`, { column, searchText: debouncedSearchText, limit }],
5789
5705
  queryFn: async () => {
5790
- if (customQueryFn) {
5791
- const { data, idMap } = await customQueryFn({
5792
- searching: debouncedSearchText ?? '',
5793
- limit: limit,
5794
- offset: 0,
5795
- });
5796
- setIdMap((state) => {
5797
- return { ...state, ...idMap };
5798
- });
5799
- return data;
5706
+ // customQueryFn is required when serverUrl is not available
5707
+ if (!customQueryFn) {
5708
+ throw new Error(`customQueryFn is required in foreign_key for table ${table}. serverUrl has been removed.`);
5800
5709
  }
5801
- const data = await getTableData({
5802
- serverUrl,
5710
+ const { data, idMap } = await customQueryFn({
5803
5711
  searching: debouncedSearchText ?? '',
5804
- in_table: table,
5805
5712
  limit: limit,
5806
5713
  offset: 0,
5807
5714
  });
5808
- const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
5809
- return [
5810
- item[column_ref],
5811
- {
5812
- ...item,
5813
- },
5814
- ];
5815
- }));
5816
- setIdMap((state) => {
5817
- return { ...state, ...newMap };
5818
- });
5715
+ // Update idMap with returned values
5716
+ if (idMap && Object.keys(idMap).length > 0) {
5717
+ setIdMap((state) => {
5718
+ return { ...state, ...idMap };
5719
+ });
5720
+ }
5819
5721
  return data;
5820
5722
  },
5821
5723
  enabled: true, // Always enabled for combobox
@@ -5939,6 +5841,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5939
5841
  idPickerLabels,
5940
5842
  insideDialog: insideDialog ?? false,
5941
5843
  renderDisplay,
5844
+ loadInitialValues: schemaLoadInitialValues, // Required for id-picker, checked above
5942
5845
  column_ref,
5943
5846
  errors,
5944
5847
  setValue,
@@ -6232,31 +6135,35 @@ react.RadioCard.ItemIndicator;
6232
6135
 
6233
6136
  const TagPicker = ({ column, schema, prefix }) => {
6234
6137
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
6235
- const { serverUrl } = useSchemaContext();
6236
6138
  if (schema.properties == undefined) {
6237
- throw new Error("schema properties undefined when using DatePicker");
6139
+ throw new Error('schema properties undefined when using DatePicker');
6238
6140
  }
6239
- const { gridColumn, gridRow, in_table, object_id_column } = schema;
6141
+ const { gridColumn, gridRow, in_table, object_id_column, tagPicker } = schema;
6240
6142
  if (in_table === undefined) {
6241
- throw new Error("in_table is undefined when using TagPicker");
6143
+ throw new Error('in_table is undefined when using TagPicker');
6242
6144
  }
6243
6145
  if (object_id_column === undefined) {
6244
- throw new Error("object_id_column is undefined when using TagPicker");
6146
+ throw new Error('object_id_column is undefined when using TagPicker');
6147
+ }
6148
+ if (!tagPicker?.queryFn) {
6149
+ throw new Error('tagPicker.queryFn is required in schema. serverUrl has been removed.');
6245
6150
  }
6246
6151
  const query = reactQuery.useQuery({
6247
6152
  queryKey: [`tagpicker`, in_table],
6248
6153
  queryFn: async () => {
6249
- return await getTableData({
6250
- serverUrl,
6251
- in_table: "tables_tags_view",
6154
+ const result = await tagPicker.queryFn({
6155
+ in_table: 'tables_tags_view',
6252
6156
  where: [
6253
6157
  {
6254
- id: "table_name",
6158
+ id: 'table_name',
6255
6159
  value: [in_table],
6256
6160
  },
6257
6161
  ],
6258
6162
  limit: 100,
6163
+ offset: 0,
6164
+ searching: '',
6259
6165
  });
6166
+ return result.data || { data: [] };
6260
6167
  },
6261
6168
  staleTime: 10000,
6262
6169
  });
@@ -6264,17 +6171,19 @@ const TagPicker = ({ column, schema, prefix }) => {
6264
6171
  const existingTagsQuery = reactQuery.useQuery({
6265
6172
  queryKey: [`existing`, { in_table, object_id_column }, object_id],
6266
6173
  queryFn: async () => {
6267
- return await getTableData({
6268
- serverUrl,
6174
+ const result = await tagPicker.queryFn({
6269
6175
  in_table: in_table,
6270
6176
  where: [
6271
6177
  {
6272
6178
  id: object_id_column,
6273
- value: object_id[0],
6179
+ value: [object_id[0]],
6274
6180
  },
6275
6181
  ],
6276
6182
  limit: 100,
6183
+ offset: 0,
6184
+ searching: '',
6277
6185
  });
6186
+ return result.data || { data: [] };
6278
6187
  },
6279
6188
  enabled: object_id != undefined,
6280
6189
  staleTime: 10000,
@@ -6285,9 +6194,9 @@ const TagPicker = ({ column, schema, prefix }) => {
6285
6194
  if (!!object_id === false) {
6286
6195
  return jsxRuntime.jsx(jsxRuntime.Fragment, {});
6287
6196
  }
6288
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: 4, gridColumn,
6197
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: 4, gridColumn,
6289
6198
  gridRow, children: [isFetching && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isFetching" }), isLoading && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isLoading" }), isPending && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isPending" }), isError && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isError" }), dataList.map(({ parent_tag_name, all_tags, is_mutually_exclusive }) => {
6290
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: 2, children: [jsxRuntime.jsx(react.Text, { children: parent_tag_name }), is_mutually_exclusive && (jsxRuntime.jsx(RadioCardRoot, { defaultValue: "next", variant: "surface", onValueChange: (tagIds) => {
6199
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: 2, children: [jsxRuntime.jsx(react.Text, { children: parent_tag_name }), is_mutually_exclusive && (jsxRuntime.jsx(RadioCardRoot, { defaultValue: "next", variant: 'surface', onValueChange: (tagIds) => {
6291
6200
  const existedTags = Object.values(all_tags)
6292
6201
  .filter(({ id }) => {
6293
6202
  return existingTagList.some(({ tag_id }) => tag_id === id);
@@ -6299,20 +6208,20 @@ const TagPicker = ({ column, schema, prefix }) => {
6299
6208
  tagIds.value,
6300
6209
  ]);
6301
6210
  setValue(`${column}.${parent_tag_name}.old`, existedTags);
6302
- }, children: jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6211
+ }, children: jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6303
6212
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
6304
- return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", disabled: true }, `${tagName}-${id}`));
6213
+ return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', disabled: true }, `${tagName}-${id}`));
6305
6214
  }
6306
- return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", colorPalette: "blue" }, `${tagName}-${id}`));
6215
+ return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', colorPalette: 'blue' }, `${tagName}-${id}`));
6307
6216
  }) }) })), !is_mutually_exclusive && (jsxRuntime.jsx(react.CheckboxGroup, { onValueChange: (tagIds) => {
6308
6217
  setValue(`${column}.${parent_tag_name}.current`, tagIds);
6309
- }, children: jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6218
+ }, children: jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6310
6219
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
6311
- return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%", disabled: true, colorPalette: "blue" }, `${tagName}-${id}`));
6220
+ return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%', disabled: true, colorPalette: 'blue' }, `${tagName}-${id}`));
6312
6221
  }
6313
- return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%" }, `${tagName}-${id}`));
6222
+ return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%' }, `${tagName}-${id}`));
6314
6223
  }) }) }))] }, `tag-${parent_tag_name}`));
6315
- }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
6224
+ }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: (errors[`${column}`]?.message ?? 'No error message') }))] }));
6316
6225
  };
6317
6226
 
6318
6227
  const Textarea = React.forwardRef(({ value, defaultValue, placeholder, onChange, onFocus, onBlur, disabled = false, readOnly = false, className, rows = 4, maxLength, autoFocus = false, invalid = false, required = false, label, helperText, errorText, ...props }, ref) => {
@@ -7994,31 +7903,35 @@ const StringViewer = ({ column, schema, prefix, }) => {
7994
7903
 
7995
7904
  const TagViewer = ({ column, schema, prefix }) => {
7996
7905
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
7997
- const { serverUrl } = useSchemaContext();
7998
7906
  if (schema.properties == undefined) {
7999
- throw new Error("schema properties undefined when using DatePicker");
7907
+ throw new Error('schema properties undefined when using DatePicker');
8000
7908
  }
8001
- const { gridColumn, gridRow, in_table, object_id_column } = schema;
7909
+ const { gridColumn, gridRow, in_table, object_id_column, tagPicker } = schema;
8002
7910
  if (in_table === undefined) {
8003
- throw new Error("in_table is undefined when using TagPicker");
7911
+ throw new Error('in_table is undefined when using TagPicker');
8004
7912
  }
8005
7913
  if (object_id_column === undefined) {
8006
- throw new Error("object_id_column is undefined when using TagPicker");
7914
+ throw new Error('object_id_column is undefined when using TagPicker');
7915
+ }
7916
+ if (!tagPicker?.queryFn) {
7917
+ throw new Error('tagPicker.queryFn is required in schema. serverUrl has been removed.');
8007
7918
  }
8008
7919
  const query = reactQuery.useQuery({
8009
7920
  queryKey: [`tagpicker`, in_table],
8010
7921
  queryFn: async () => {
8011
- return await getTableData({
8012
- serverUrl,
8013
- in_table: "tables_tags_view",
7922
+ const result = await tagPicker.queryFn({
7923
+ in_table: 'tables_tags_view',
8014
7924
  where: [
8015
7925
  {
8016
- id: "table_name",
7926
+ id: 'table_name',
8017
7927
  value: [in_table],
8018
7928
  },
8019
7929
  ],
8020
7930
  limit: 100,
7931
+ offset: 0,
7932
+ searching: '',
8021
7933
  });
7934
+ return result.data || { data: [] };
8022
7935
  },
8023
7936
  staleTime: 10000,
8024
7937
  });
@@ -8026,17 +7939,19 @@ const TagViewer = ({ column, schema, prefix }) => {
8026
7939
  const existingTagsQuery = reactQuery.useQuery({
8027
7940
  queryKey: [`existing`, { in_table, object_id_column }, object_id],
8028
7941
  queryFn: async () => {
8029
- return await getTableData({
8030
- serverUrl,
7942
+ const result = await tagPicker.queryFn({
8031
7943
  in_table: in_table,
8032
7944
  where: [
8033
7945
  {
8034
7946
  id: object_id_column,
8035
- value: object_id[0],
7947
+ value: [object_id[0]],
8036
7948
  },
8037
7949
  ],
8038
7950
  limit: 100,
7951
+ offset: 0,
7952
+ searching: '',
8039
7953
  });
7954
+ return result.data || { data: [] };
8040
7955
  },
8041
7956
  enabled: object_id != undefined,
8042
7957
  staleTime: 10000,
@@ -8047,9 +7962,9 @@ const TagViewer = ({ column, schema, prefix }) => {
8047
7962
  if (!!object_id === false) {
8048
7963
  return jsxRuntime.jsx(jsxRuntime.Fragment, {});
8049
7964
  }
8050
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: 4, gridColumn,
7965
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: 4, gridColumn,
8051
7966
  gridRow, children: [isFetching && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isFetching" }), isLoading && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isLoading" }), isPending && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isPending" }), isError && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isError" }), dataList.map(({ parent_tag_name, all_tags, is_mutually_exclusive }) => {
8052
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: 2, children: [jsxRuntime.jsx(react.Text, { children: parent_tag_name }), is_mutually_exclusive && (jsxRuntime.jsx(RadioCardRoot, { defaultValue: "next", variant: "surface", onValueChange: (tagIds) => {
7967
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: 2, children: [jsxRuntime.jsx(react.Text, { children: parent_tag_name }), is_mutually_exclusive && (jsxRuntime.jsx(RadioCardRoot, { defaultValue: "next", variant: 'surface', onValueChange: (tagIds) => {
8053
7968
  const existedTags = Object.values(all_tags)
8054
7969
  .filter(({ id }) => {
8055
7970
  return existingTagList.some(({ tag_id }) => tag_id === id);
@@ -8061,20 +7976,20 @@ const TagViewer = ({ column, schema, prefix }) => {
8061
7976
  tagIds.value,
8062
7977
  ]);
8063
7978
  setValue(`${column}.${parent_tag_name}.old`, existedTags);
8064
- }, children: jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
7979
+ }, children: jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
8065
7980
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
8066
- return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", disabled: true }, `${tagName}-${id}`));
7981
+ return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', disabled: true }, `${tagName}-${id}`));
8067
7982
  }
8068
- return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", colorPalette: "blue" }, `${tagName}-${id}`));
7983
+ return (jsxRuntime.jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', colorPalette: 'blue' }, `${tagName}-${id}`));
8069
7984
  }) }) })), !is_mutually_exclusive && (jsxRuntime.jsx(react.CheckboxGroup, { onValueChange: (tagIds) => {
8070
7985
  setValue(`${column}.${parent_tag_name}.current`, tagIds);
8071
- }, children: jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
7986
+ }, children: jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
8072
7987
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
8073
- return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%", disabled: true, colorPalette: "blue" }, `${tagName}-${id}`));
7988
+ return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%', disabled: true, colorPalette: 'blue' }, `${tagName}-${id}`));
8074
7989
  }
8075
- return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%" }, `${tagName}-${id}`));
7990
+ return (jsxRuntime.jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%' }, `${tagName}-${id}`));
8076
7991
  }) }) }))] }, `tag-${parent_tag_name}`));
8077
- }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
7992
+ }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: (errors[`${column}`]?.message ?? 'No error message') }))] }));
8078
7993
  };
8079
7994
 
8080
7995
  const TextAreaViewer = ({ column, schema, prefix, }) => {
package/dist/index.mjs CHANGED
@@ -4016,7 +4016,6 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
4016
4016
  //@ts-expect-error TODO: find appropriate type
4017
4017
  const SchemaFormContext = createContext({
4018
4018
  schema: {},
4019
- serverUrl: '',
4020
4019
  requestUrl: '',
4021
4020
  order: [],
4022
4021
  ignore: [],
@@ -4256,7 +4255,7 @@ const idPickerSanityCheck = (column, foreign_key) => {
4256
4255
  throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
4257
4256
  }
4258
4257
  };
4259
- const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
4258
+ const FormRoot = ({ schema, idMap, setIdMap, form, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
4260
4259
  showSubmitButton: true,
4261
4260
  showResetButton: true,
4262
4261
  showTitle: true,
@@ -4297,9 +4296,11 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
4297
4296
  }
4298
4297
  };
4299
4298
  const defaultSubmitPromise = (data) => {
4299
+ if (!requestOptions.url) {
4300
+ throw new Error('requestOptions.url is required when onSubmit is not provided');
4301
+ }
4300
4302
  const options = {
4301
4303
  method: 'POST',
4302
- url: `${serverUrl}`,
4303
4304
  data: clearEmptyString(data),
4304
4305
  ...requestOptions,
4305
4306
  };
@@ -4317,7 +4318,6 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
4317
4318
  };
4318
4319
  return (jsx(SchemaFormContext.Provider, { value: {
4319
4320
  schema,
4320
- serverUrl,
4321
4321
  order,
4322
4322
  ignore,
4323
4323
  include,
@@ -5598,106 +5598,20 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
5598
5598
  }) })] }));
5599
5599
  };
5600
5600
 
5601
- const getTableData = async ({ serverUrl, in_table, searching = "", where = [], limit = 10, offset = 0, }) => {
5602
- if (serverUrl === undefined || serverUrl.length == 0) {
5603
- throw new Error("The serverUrl is missing");
5604
- }
5605
- if (in_table === undefined || in_table.length == 0) {
5606
- throw new Error("The in_table is missing");
5607
- }
5608
- const options = {
5609
- method: "GET",
5610
- url: `${serverUrl}/api/g/${in_table}`,
5611
- params: {
5612
- searching,
5613
- where,
5614
- limit,
5615
- offset
5616
- },
5617
- };
5618
- try {
5619
- const { data } = await axios.request(options);
5620
- console.log(data);
5621
- return data;
5622
- }
5623
- catch (error) {
5624
- console.error(error);
5625
- throw error;
5626
- }
5627
- };
5628
-
5629
5601
  // Default renderDisplay function that stringifies JSON
5630
5602
  const defaultRenderDisplay = (item) => {
5631
5603
  return JSON.stringify(item);
5632
5604
  };
5633
5605
 
5634
- /**
5635
- * Load initial values for IdPicker fields into idMap
5636
- * Uses customQueryFn if available, otherwise falls back to getTableData
5637
- *
5638
- * @param params - Configuration for loading initial values
5639
- * @returns Promise with fetched data and idMap
5640
- */
5641
- const loadInitialValues = async ({ ids, foreign_key, serverUrl, setIdMap, }) => {
5642
- if (!ids || ids.length === 0) {
5643
- return { data: { data: [], count: 0 }, idMap: {} };
5644
- }
5645
- const { table, column: column_ref, customQueryFn } = foreign_key;
5646
- // Filter out IDs that are already in idMap (optional optimization)
5647
- // For now, we'll fetch all requested IDs to ensure consistency
5648
- if (customQueryFn) {
5649
- const { data, idMap: returnedIdMap } = await customQueryFn({
5650
- searching: '',
5651
- limit: ids.length,
5652
- offset: 0,
5653
- where: [
5654
- {
5655
- id: column_ref,
5656
- value: ids.length === 1 ? ids[0] : ids, // CustomQueryFn accepts string | string[]
5657
- },
5658
- ],
5659
- });
5660
- // Update idMap with returned values
5661
- if (returnedIdMap && Object.keys(returnedIdMap).length > 0) {
5662
- setIdMap((state) => {
5663
- return { ...state, ...returnedIdMap };
5664
- });
5665
- }
5666
- return { data, idMap: returnedIdMap || {} };
5667
- }
5668
- // Fallback to default getTableData
5669
- const data = await getTableData({
5670
- serverUrl,
5671
- searching: '',
5672
- in_table: table,
5673
- limit: ids.length,
5674
- offset: 0,
5675
- where: [
5676
- {
5677
- id: column_ref,
5678
- value: ids, // Always pass as array
5679
- },
5680
- ],
5681
- });
5682
- // Build idMap from fetched data
5683
- const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
5684
- return [
5685
- item[column_ref],
5686
- {
5687
- ...item,
5688
- },
5689
- ];
5690
- }));
5691
- // Update idMap state
5692
- setIdMap((state) => {
5693
- return { ...state, ...newMap };
5694
- });
5695
- return { data: data, idMap: newMap };
5696
- };
5697
5606
  const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5698
5607
  const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
5699
- const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
5700
- const { renderDisplay, foreign_key } = schema;
5608
+ const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
5609
+ const { renderDisplay, loadInitialValues: schemaLoadInitialValues, foreign_key, variant, } = schema;
5610
+ // loadInitialValues must be provided in schema for id-picker fields
5611
+ // It's used to load the record of the id so the display is human-readable
5612
+ if (variant === 'id-picker' && !schemaLoadInitialValues) {
5613
+ throw new Error(`loadInitialValues is required in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
5614
+ }
5701
5615
  const { table, column: column_ref, customQueryFn, } = foreign_key;
5702
5616
  const [searchText, setSearchText] = useState('');
5703
5617
  const [debouncedSearchText, setDebouncedSearchText] = useState('');
@@ -5750,11 +5664,13 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5750
5664
  if (missingIds.length === 0) {
5751
5665
  return { data: [], count: 0 };
5752
5666
  }
5753
- // Use the reusable loadInitialValues function
5754
- const result = await loadInitialValues({
5667
+ // Use schema's loadInitialValues (required for id-picker)
5668
+ if (!schemaLoadInitialValues) {
5669
+ throw new Error(`loadInitialValues is required in schema for IdPicker field '${column}'.`);
5670
+ }
5671
+ const result = await schemaLoadInitialValues({
5755
5672
  ids: missingIds,
5756
5673
  foreign_key: foreign_key,
5757
- serverUrl,
5758
5674
  setIdMap,
5759
5675
  });
5760
5676
  return result.data;
@@ -5767,35 +5683,21 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5767
5683
  const query = useQuery({
5768
5684
  queryKey: [`idpicker`, { column, searchText: debouncedSearchText, limit }],
5769
5685
  queryFn: async () => {
5770
- if (customQueryFn) {
5771
- const { data, idMap } = await customQueryFn({
5772
- searching: debouncedSearchText ?? '',
5773
- limit: limit,
5774
- offset: 0,
5775
- });
5776
- setIdMap((state) => {
5777
- return { ...state, ...idMap };
5778
- });
5779
- return data;
5686
+ // customQueryFn is required when serverUrl is not available
5687
+ if (!customQueryFn) {
5688
+ throw new Error(`customQueryFn is required in foreign_key for table ${table}. serverUrl has been removed.`);
5780
5689
  }
5781
- const data = await getTableData({
5782
- serverUrl,
5690
+ const { data, idMap } = await customQueryFn({
5783
5691
  searching: debouncedSearchText ?? '',
5784
- in_table: table,
5785
5692
  limit: limit,
5786
5693
  offset: 0,
5787
5694
  });
5788
- const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
5789
- return [
5790
- item[column_ref],
5791
- {
5792
- ...item,
5793
- },
5794
- ];
5795
- }));
5796
- setIdMap((state) => {
5797
- return { ...state, ...newMap };
5798
- });
5695
+ // Update idMap with returned values
5696
+ if (idMap && Object.keys(idMap).length > 0) {
5697
+ setIdMap((state) => {
5698
+ return { ...state, ...idMap };
5699
+ });
5700
+ }
5799
5701
  return data;
5800
5702
  },
5801
5703
  enabled: true, // Always enabled for combobox
@@ -5919,6 +5821,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5919
5821
  idPickerLabels,
5920
5822
  insideDialog: insideDialog ?? false,
5921
5823
  renderDisplay,
5824
+ loadInitialValues: schemaLoadInitialValues, // Required for id-picker, checked above
5922
5825
  column_ref,
5923
5826
  errors,
5924
5827
  setValue,
@@ -6212,31 +6115,35 @@ RadioCard.ItemIndicator;
6212
6115
 
6213
6116
  const TagPicker = ({ column, schema, prefix }) => {
6214
6117
  const { watch, formState: { errors }, setValue, } = useFormContext();
6215
- const { serverUrl } = useSchemaContext();
6216
6118
  if (schema.properties == undefined) {
6217
- throw new Error("schema properties undefined when using DatePicker");
6119
+ throw new Error('schema properties undefined when using DatePicker');
6218
6120
  }
6219
- const { gridColumn, gridRow, in_table, object_id_column } = schema;
6121
+ const { gridColumn, gridRow, in_table, object_id_column, tagPicker } = schema;
6220
6122
  if (in_table === undefined) {
6221
- throw new Error("in_table is undefined when using TagPicker");
6123
+ throw new Error('in_table is undefined when using TagPicker');
6222
6124
  }
6223
6125
  if (object_id_column === undefined) {
6224
- throw new Error("object_id_column is undefined when using TagPicker");
6126
+ throw new Error('object_id_column is undefined when using TagPicker');
6127
+ }
6128
+ if (!tagPicker?.queryFn) {
6129
+ throw new Error('tagPicker.queryFn is required in schema. serverUrl has been removed.');
6225
6130
  }
6226
6131
  const query = useQuery({
6227
6132
  queryKey: [`tagpicker`, in_table],
6228
6133
  queryFn: async () => {
6229
- return await getTableData({
6230
- serverUrl,
6231
- in_table: "tables_tags_view",
6134
+ const result = await tagPicker.queryFn({
6135
+ in_table: 'tables_tags_view',
6232
6136
  where: [
6233
6137
  {
6234
- id: "table_name",
6138
+ id: 'table_name',
6235
6139
  value: [in_table],
6236
6140
  },
6237
6141
  ],
6238
6142
  limit: 100,
6143
+ offset: 0,
6144
+ searching: '',
6239
6145
  });
6146
+ return result.data || { data: [] };
6240
6147
  },
6241
6148
  staleTime: 10000,
6242
6149
  });
@@ -6244,17 +6151,19 @@ const TagPicker = ({ column, schema, prefix }) => {
6244
6151
  const existingTagsQuery = useQuery({
6245
6152
  queryKey: [`existing`, { in_table, object_id_column }, object_id],
6246
6153
  queryFn: async () => {
6247
- return await getTableData({
6248
- serverUrl,
6154
+ const result = await tagPicker.queryFn({
6249
6155
  in_table: in_table,
6250
6156
  where: [
6251
6157
  {
6252
6158
  id: object_id_column,
6253
- value: object_id[0],
6159
+ value: [object_id[0]],
6254
6160
  },
6255
6161
  ],
6256
6162
  limit: 100,
6163
+ offset: 0,
6164
+ searching: '',
6257
6165
  });
6166
+ return result.data || { data: [] };
6258
6167
  },
6259
6168
  enabled: object_id != undefined,
6260
6169
  staleTime: 10000,
@@ -6265,9 +6174,9 @@ const TagPicker = ({ column, schema, prefix }) => {
6265
6174
  if (!!object_id === false) {
6266
6175
  return jsx(Fragment, {});
6267
6176
  }
6268
- return (jsxs(Flex, { flexFlow: "column", gap: 4, gridColumn,
6177
+ return (jsxs(Flex, { flexFlow: 'column', gap: 4, gridColumn,
6269
6178
  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 }) => {
6270
- 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) => {
6179
+ 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) => {
6271
6180
  const existedTags = Object.values(all_tags)
6272
6181
  .filter(({ id }) => {
6273
6182
  return existingTagList.some(({ tag_id }) => tag_id === id);
@@ -6279,20 +6188,20 @@ const TagPicker = ({ column, schema, prefix }) => {
6279
6188
  tagIds.value,
6280
6189
  ]);
6281
6190
  setValue(`${column}.${parent_tag_name}.old`, existedTags);
6282
- }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6191
+ }, children: jsx(Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6283
6192
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
6284
- return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", disabled: true }, `${tagName}-${id}`));
6193
+ return (jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', disabled: true }, `${tagName}-${id}`));
6285
6194
  }
6286
- return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", colorPalette: "blue" }, `${tagName}-${id}`));
6195
+ return (jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', colorPalette: 'blue' }, `${tagName}-${id}`));
6287
6196
  }) }) })), !is_mutually_exclusive && (jsx(CheckboxGroup, { onValueChange: (tagIds) => {
6288
6197
  setValue(`${column}.${parent_tag_name}.current`, tagIds);
6289
- }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6198
+ }, children: jsx(Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
6290
6199
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
6291
- return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%", disabled: true, colorPalette: "blue" }, `${tagName}-${id}`));
6200
+ return (jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%', disabled: true, colorPalette: 'blue' }, `${tagName}-${id}`));
6292
6201
  }
6293
- return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%" }, `${tagName}-${id}`));
6202
+ return (jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%' }, `${tagName}-${id}`));
6294
6203
  }) }) }))] }, `tag-${parent_tag_name}`));
6295
- }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
6204
+ }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: (errors[`${column}`]?.message ?? 'No error message') }))] }));
6296
6205
  };
6297
6206
 
6298
6207
  const Textarea = forwardRef(({ value, defaultValue, placeholder, onChange, onFocus, onBlur, disabled = false, readOnly = false, className, rows = 4, maxLength, autoFocus = false, invalid = false, required = false, label, helperText, errorText, ...props }, ref) => {
@@ -7974,31 +7883,35 @@ const StringViewer = ({ column, schema, prefix, }) => {
7974
7883
 
7975
7884
  const TagViewer = ({ column, schema, prefix }) => {
7976
7885
  const { watch, formState: { errors }, setValue, } = useFormContext();
7977
- const { serverUrl } = useSchemaContext();
7978
7886
  if (schema.properties == undefined) {
7979
- throw new Error("schema properties undefined when using DatePicker");
7887
+ throw new Error('schema properties undefined when using DatePicker');
7980
7888
  }
7981
- const { gridColumn, gridRow, in_table, object_id_column } = schema;
7889
+ const { gridColumn, gridRow, in_table, object_id_column, tagPicker } = schema;
7982
7890
  if (in_table === undefined) {
7983
- throw new Error("in_table is undefined when using TagPicker");
7891
+ throw new Error('in_table is undefined when using TagPicker');
7984
7892
  }
7985
7893
  if (object_id_column === undefined) {
7986
- throw new Error("object_id_column is undefined when using TagPicker");
7894
+ throw new Error('object_id_column is undefined when using TagPicker');
7895
+ }
7896
+ if (!tagPicker?.queryFn) {
7897
+ throw new Error('tagPicker.queryFn is required in schema. serverUrl has been removed.');
7987
7898
  }
7988
7899
  const query = useQuery({
7989
7900
  queryKey: [`tagpicker`, in_table],
7990
7901
  queryFn: async () => {
7991
- return await getTableData({
7992
- serverUrl,
7993
- in_table: "tables_tags_view",
7902
+ const result = await tagPicker.queryFn({
7903
+ in_table: 'tables_tags_view',
7994
7904
  where: [
7995
7905
  {
7996
- id: "table_name",
7906
+ id: 'table_name',
7997
7907
  value: [in_table],
7998
7908
  },
7999
7909
  ],
8000
7910
  limit: 100,
7911
+ offset: 0,
7912
+ searching: '',
8001
7913
  });
7914
+ return result.data || { data: [] };
8002
7915
  },
8003
7916
  staleTime: 10000,
8004
7917
  });
@@ -8006,17 +7919,19 @@ const TagViewer = ({ column, schema, prefix }) => {
8006
7919
  const existingTagsQuery = useQuery({
8007
7920
  queryKey: [`existing`, { in_table, object_id_column }, object_id],
8008
7921
  queryFn: async () => {
8009
- return await getTableData({
8010
- serverUrl,
7922
+ const result = await tagPicker.queryFn({
8011
7923
  in_table: in_table,
8012
7924
  where: [
8013
7925
  {
8014
7926
  id: object_id_column,
8015
- value: object_id[0],
7927
+ value: [object_id[0]],
8016
7928
  },
8017
7929
  ],
8018
7930
  limit: 100,
7931
+ offset: 0,
7932
+ searching: '',
8019
7933
  });
7934
+ return result.data || { data: [] };
8020
7935
  },
8021
7936
  enabled: object_id != undefined,
8022
7937
  staleTime: 10000,
@@ -8027,9 +7942,9 @@ const TagViewer = ({ column, schema, prefix }) => {
8027
7942
  if (!!object_id === false) {
8028
7943
  return jsx(Fragment, {});
8029
7944
  }
8030
- return (jsxs(Flex, { flexFlow: "column", gap: 4, gridColumn,
7945
+ return (jsxs(Flex, { flexFlow: 'column', gap: 4, gridColumn,
8031
7946
  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 }) => {
8032
- 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) => {
7947
+ 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) => {
8033
7948
  const existedTags = Object.values(all_tags)
8034
7949
  .filter(({ id }) => {
8035
7950
  return existingTagList.some(({ tag_id }) => tag_id === id);
@@ -8041,20 +7956,20 @@ const TagViewer = ({ column, schema, prefix }) => {
8041
7956
  tagIds.value,
8042
7957
  ]);
8043
7958
  setValue(`${column}.${parent_tag_name}.old`, existedTags);
8044
- }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
7959
+ }, children: jsx(Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
8045
7960
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
8046
- return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", disabled: true }, `${tagName}-${id}`));
7961
+ return (jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', disabled: true }, `${tagName}-${id}`));
8047
7962
  }
8048
- return (jsx(RadioCardItem, { label: tagName, value: id, flex: "0 0 0%", colorPalette: "blue" }, `${tagName}-${id}`));
7963
+ return (jsx(RadioCardItem, { label: tagName, value: id, flex: '0 0 0%', colorPalette: 'blue' }, `${tagName}-${id}`));
8049
7964
  }) }) })), !is_mutually_exclusive && (jsx(CheckboxGroup, { onValueChange: (tagIds) => {
8050
7965
  setValue(`${column}.${parent_tag_name}.current`, tagIds);
8051
- }, children: jsx(Flex, { flexFlow: "wrap", gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
7966
+ }, children: jsx(Flex, { flexFlow: 'wrap', gap: 2, children: Object.entries(all_tags).map(([tagName, { id }]) => {
8052
7967
  if (existingTagList.some(({ tag_id }) => tag_id === id)) {
8053
- return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%", disabled: true, colorPalette: "blue" }, `${tagName}-${id}`));
7968
+ return (jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%', disabled: true, colorPalette: 'blue' }, `${tagName}-${id}`));
8054
7969
  }
8055
- return (jsx(CheckboxCard, { label: tagName, value: id, flex: "0 0 0%" }, `${tagName}-${id}`));
7970
+ return (jsx(CheckboxCard, { label: tagName, value: id, flex: '0 0 0%' }, `${tagName}-${id}`));
8056
7971
  }) }) }))] }, `tag-${parent_tag_name}`));
8057
- }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
7972
+ }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: (errors[`${column}`]?.message ?? 'No error message') }))] }));
8058
7973
  };
8059
7974
 
8060
7975
  const TextAreaViewer = ({ column, schema, prefix, }) => {
@@ -6,7 +6,6 @@ import { Translate } from './useForm';
6
6
  import { DateTimePickerLabels, IdPickerLabels, EnumPickerLabels, FilePickerLabels, FormButtonLabels, TimePickerLabels } from './components/types/CustomJSONSchema7';
7
7
  export interface SchemaFormContext<TData extends FieldValues> {
8
8
  schema: JSONSchema7;
9
- serverUrl: string;
10
9
  requestUrl: string;
11
10
  order: string[];
12
11
  ignore: string[];
@@ -7,7 +7,6 @@ import { Translate } from '../../useForm';
7
7
  import { CustomJSONSchema7, DateTimePickerLabels, IdPickerLabels, EnumPickerLabels, FilePickerLabels, FormButtonLabels, TimePickerLabels } from '../types/CustomJSONSchema7';
8
8
  export interface FormRootProps<TData extends FieldValues> {
9
9
  schema: CustomJSONSchema7;
10
- serverUrl: string;
11
10
  requestUrl?: string;
12
11
  idMap: Record<string, object>;
13
12
  setIdMap: Dispatch<SetStateAction<Record<string, object>>>;
@@ -51,4 +50,4 @@ export declare const idPickerSanityCheck: (column: string, foreign_key?: {
51
50
  table?: string | undefined;
52
51
  column?: string | undefined;
53
52
  } | undefined) => void;
54
- export declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, serverUrl, translate, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, requireConfirmation, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => import("react/jsx-runtime").JSX.Element;
53
+ export declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, translate, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, requireConfirmation, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,4 @@
1
- import { TagPickerProps } from "../types/CustomJSONSchema7";
1
+ import { TagPickerProps } from '../types/CustomJSONSchema7';
2
2
  export interface Tag {
3
3
  id: string;
4
4
  name: string;
@@ -1,30 +1,9 @@
1
1
  import React from 'react';
2
- import { ForeignKeyProps } from './StringInputField';
3
- import { CustomJSONSchema7 } from '../types/CustomJSONSchema7';
2
+ import { CustomJSONSchema7, LoadInitialValuesParams, LoadInitialValuesResult } from '../types/CustomJSONSchema7';
4
3
  export interface RecordType {
5
4
  [key: string]: any;
6
5
  }
7
- export interface LoadInitialValuesParams {
8
- ids: string[];
9
- foreign_key: ForeignKeyProps;
10
- serverUrl: string;
11
- setIdMap: React.Dispatch<React.SetStateAction<Record<string, object>>>;
12
- }
13
- export interface LoadInitialValuesResult {
14
- data: {
15
- data: RecordType[];
16
- count: number;
17
- };
18
- idMap: Record<string, object>;
19
- }
20
- /**
21
- * Load initial values for IdPicker fields into idMap
22
- * Uses customQueryFn if available, otherwise falls back to getTableData
23
- *
24
- * @param params - Configuration for loading initial values
25
- * @returns Promise with fetched data and idMap
26
- */
27
- export declare const loadInitialValues: ({ ids, foreign_key, serverUrl, setIdMap, }: LoadInitialValuesParams) => Promise<LoadInitialValuesResult>;
6
+ export type { LoadInitialValuesParams, LoadInitialValuesResult, } from '../types/CustomJSONSchema7';
28
7
  export interface UseIdPickerDataProps {
29
8
  column: string;
30
9
  schema: CustomJSONSchema7;
@@ -61,6 +40,7 @@ export interface UseIdPickerDataReturn {
61
40
  idPickerLabels: any;
62
41
  insideDialog: boolean;
63
42
  renderDisplay: ((item: RecordType) => React.ReactNode) | undefined;
43
+ loadInitialValues: (params: LoadInitialValuesParams) => Promise<LoadInitialValuesResult>;
64
44
  column_ref: string;
65
45
  errors: any;
66
46
  setValue: (name: string, value: any) => void;
@@ -3,6 +3,7 @@ import { ReactNode } from 'react';
3
3
  import { ForeignKeyProps } from '../fields/StringInputField';
4
4
  import { UseFormReturn } from 'react-hook-form';
5
5
  import { ValidationErrorType } from '../../utils/buildErrorMessages';
6
+ import React from 'react';
6
7
  export interface DateTimePickerLabels {
7
8
  monthNamesShort?: string[];
8
9
  weekdayNamesShort?: string[];
@@ -60,12 +61,25 @@ export interface TimePickerLabels {
60
61
  placeholder?: string;
61
62
  emptyMessage?: string;
62
63
  }
64
+ export interface LoadInitialValuesParams {
65
+ ids: string[];
66
+ foreign_key: ForeignKeyProps;
67
+ setIdMap: React.Dispatch<React.SetStateAction<Record<string, object>>>;
68
+ }
69
+ export interface LoadInitialValuesResult {
70
+ data: {
71
+ data: Record<string, any>[];
72
+ count: number;
73
+ };
74
+ idMap: Record<string, object>;
75
+ }
63
76
  export interface CustomJSONSchema7 extends JSONSchema7 {
64
77
  gridColumn?: string;
65
78
  gridRow?: string;
66
79
  foreign_key?: ForeignKeyProps;
67
80
  variant?: string;
68
81
  renderDisplay?: (item: unknown) => ReactNode;
82
+ loadInitialValues?: (params: LoadInitialValuesParams) => Promise<LoadInitialValuesResult>;
69
83
  inputRender?: (props: {
70
84
  column: string;
71
85
  schema: CustomJSONSchema7;
@@ -87,6 +101,24 @@ export interface CustomJSONSchema7 extends JSONSchema7 {
87
101
  numberStorageType?: 'string' | 'number';
88
102
  errorMessages?: Partial<Record<ValidationErrorType | string, string>>;
89
103
  filePicker?: FilePickerProps;
104
+ tagPicker?: {
105
+ queryFn?: (params: {
106
+ in_table: string;
107
+ where?: {
108
+ id: string;
109
+ value: string[];
110
+ }[];
111
+ limit?: number;
112
+ offset?: number;
113
+ searching?: string;
114
+ }) => Promise<{
115
+ data: {
116
+ data: any[];
117
+ count: number;
118
+ };
119
+ idMap?: Record<string, object>;
120
+ }>;
121
+ };
90
122
  }
91
123
  export declare const defaultRenderDisplay: (item: unknown) => ReactNode;
92
124
  export interface TagPickerProps {
@@ -1,4 +1,4 @@
1
- import { CustomJSONSchema7 } from "../types/CustomJSONSchema7";
1
+ import { CustomJSONSchema7 } from '../types/CustomJSONSchema7';
2
2
  export interface Tag {
3
3
  id: string;
4
4
  name: string;
@@ -1,5 +1,4 @@
1
1
  export interface GetTableDataConfig {
2
- serverUrl: string;
3
2
  in_table: string;
4
3
  limit?: number;
5
4
  offset?: number;
@@ -13,4 +12,4 @@ export interface GetTableResponse {
13
12
  data?: object[];
14
13
  count: number;
15
14
  }
16
- export declare const getTableData: ({ serverUrl, in_table, searching, where, limit, offset, }: GetTableDataConfig) => Promise<any>;
15
+ export declare const getTableData: ({ in_table, searching, where, limit, offset, }: GetTableDataConfig) => Promise<never>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsol-oss/react-datatable5",
3
- "version": "13.0.1-beta.1",
3
+ "version": "13.0.1-beta.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",