@bsol-oss/react-datatable5 13.0.1-beta.21 → 13.0.1-beta.22
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 +2 -19
- package/dist/index.js +130 -205
- package/dist/index.mjs +133 -205
- package/dist/types/components/Form/components/core/FormRoot.d.ts +0 -2
- package/dist/types/components/Form/components/fields/useIdPickerData.d.ts +2 -3
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +0 -2
- package/dist/types/index.d.ts +0 -1
- package/package.json +1 -1
- package/dist/types/components/DataTable/utils/getColumns.d.ts +0 -14
- package/dist/types/components/Form/utils/idListSanityCheck.d.ts +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ import { TableHeaderProps as TableHeaderProps$1, TableRowProps, GridProps, Table
|
|
|
7
7
|
import { IconType } from 'react-icons';
|
|
8
8
|
import { UseQueryResult } from '@tanstack/react-query';
|
|
9
9
|
import { RankingInfo } from '@tanstack/match-sorter-utils';
|
|
10
|
-
import { JSONSchema7 } from 'json-schema';
|
|
11
10
|
import { AxiosRequestConfig } from 'axios';
|
|
11
|
+
import { JSONSchema7 } from 'json-schema';
|
|
12
12
|
import * as react_hook_form from 'react-hook-form';
|
|
13
13
|
import { UseFormReturn, FieldValues, SubmitHandler } from 'react-hook-form';
|
|
14
14
|
|
|
@@ -488,19 +488,6 @@ interface DataTableContextProps<TData = unknown> extends Omit<DataTableProps, 't
|
|
|
488
488
|
|
|
489
489
|
declare const useDataTableContext: <TData>() => DataTableContextProps<TData>;
|
|
490
490
|
|
|
491
|
-
interface GetColumnsConfigs<K extends RowData> {
|
|
492
|
-
schema: JSONSchema7;
|
|
493
|
-
include?: K[];
|
|
494
|
-
ignore?: K[];
|
|
495
|
-
width?: number[];
|
|
496
|
-
meta?: {
|
|
497
|
-
[key in K as string]?: object;
|
|
498
|
-
};
|
|
499
|
-
defaultWidth?: number;
|
|
500
|
-
}
|
|
501
|
-
declare const widthSanityCheck: <K extends unknown>(widthList: number[], ignoreList: K[], properties: { [key in K as string]?: object | undefined; }) => void;
|
|
502
|
-
declare const getColumns: <TData extends unknown>({ schema, include, ignore, width, meta, defaultWidth, }: GetColumnsConfigs<TData>) => ColumnDef<TData>[];
|
|
503
|
-
|
|
504
491
|
interface CustomQueryFnResponse {
|
|
505
492
|
/**
|
|
506
493
|
* The data of the query
|
|
@@ -591,7 +578,6 @@ interface TimePickerLabels {
|
|
|
591
578
|
interface LoadInitialValuesParams {
|
|
592
579
|
ids: string[];
|
|
593
580
|
customQueryFn: CustomQueryFn;
|
|
594
|
-
idColumn: string;
|
|
595
581
|
setIdMap: React__default.Dispatch<React__default.SetStateAction<Record<string, object>>>;
|
|
596
582
|
}
|
|
597
583
|
interface LoadInitialValuesResult {
|
|
@@ -605,7 +591,6 @@ interface CustomJSONSchema7 extends JSONSchema7 {
|
|
|
605
591
|
gridColumn?: string;
|
|
606
592
|
gridRow?: string;
|
|
607
593
|
customQueryFn?: CustomQueryFn;
|
|
608
|
-
idColumn?: string;
|
|
609
594
|
variant?: string;
|
|
610
595
|
renderDisplay?: (item: unknown) => ReactNode;
|
|
611
596
|
itemToValue?: (item: unknown) => string;
|
|
@@ -740,10 +725,8 @@ interface CustomJSONSchema7Definition extends JSONSchema7 {
|
|
|
740
725
|
gridColumn: string;
|
|
741
726
|
gridRow: string;
|
|
742
727
|
customQueryFn: any;
|
|
743
|
-
idColumn: string;
|
|
744
728
|
children: ReactNode;
|
|
745
729
|
}
|
|
746
|
-
declare const idPickerSanityCheck: (column: string, customQueryFn?: any, idColumn?: string) => void;
|
|
747
730
|
declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => react_jsx_runtime.JSX.Element;
|
|
748
731
|
|
|
749
732
|
interface DefaultFormProps<TData extends FieldValues> {
|
|
@@ -1253,4 +1236,4 @@ declare module '@tanstack/react-table' {
|
|
|
1253
1236
|
}
|
|
1254
1237
|
}
|
|
1255
1238
|
|
|
1256
|
-
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, DatePickerContext, 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 FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, type
|
|
1239
|
+
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, DatePickerContext, 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 FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, 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, type TableFilterTagsProps, 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, defaultRenderDisplay, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, useForm };
|
package/dist/index.js
CHANGED
|
@@ -4186,88 +4186,6 @@ const useDataTableServer = (props) => {
|
|
|
4186
4186
|
};
|
|
4187
4187
|
};
|
|
4188
4188
|
|
|
4189
|
-
const idListSanityCheck = (param, idList, properties) => {
|
|
4190
|
-
const allKeyExists = idList.every((key) => Object.keys(properties).some((column) => column == key));
|
|
4191
|
-
if (!allKeyExists) {
|
|
4192
|
-
const wrongKey = idList.find((key) => !Object.keys(properties).some((column) => column == key));
|
|
4193
|
-
throw new Error(`The key ${wrongKey} in ${param} does not exist in schema.`);
|
|
4194
|
-
}
|
|
4195
|
-
};
|
|
4196
|
-
|
|
4197
|
-
const snakeToLabel = (str) => {
|
|
4198
|
-
return str
|
|
4199
|
-
.split("_") // Split by underscore
|
|
4200
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
|
|
4201
|
-
.join(" "); // Join with space
|
|
4202
|
-
};
|
|
4203
|
-
|
|
4204
|
-
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
4205
|
-
const getColumn = ({ field }) => {
|
|
4206
|
-
return snakeToLabel(field);
|
|
4207
|
-
};
|
|
4208
|
-
if (object === null) {
|
|
4209
|
-
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "null" });
|
|
4210
|
-
}
|
|
4211
|
-
return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
4212
|
-
const uniqueKey = `${prefix}${field}-${index}`;
|
|
4213
|
-
return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsxRuntime.jsx(react.Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, uniqueKey));
|
|
4214
|
-
}) }));
|
|
4215
|
-
};
|
|
4216
|
-
|
|
4217
|
-
const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
4218
|
-
const widthListToolong = widthList.length > Object.keys(properties).length;
|
|
4219
|
-
if (widthListToolong) {
|
|
4220
|
-
throw new Error(`The width list is too long given from the number of properties.`);
|
|
4221
|
-
}
|
|
4222
|
-
const widthListToolongWithIgnore = widthList.length > Object.keys(properties).length - ignoreList.length;
|
|
4223
|
-
if (widthListToolongWithIgnore) {
|
|
4224
|
-
throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
|
|
4225
|
-
}
|
|
4226
|
-
};
|
|
4227
|
-
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
|
|
4228
|
-
const { properties } = schema;
|
|
4229
|
-
idListSanityCheck('ignore', ignore, properties);
|
|
4230
|
-
widthSanityCheck(width, ignore, properties);
|
|
4231
|
-
idListSanityCheck('meta', Object.keys(meta), properties);
|
|
4232
|
-
const getColumn = ({ column }) => {
|
|
4233
|
-
return snakeToLabel(column);
|
|
4234
|
-
};
|
|
4235
|
-
const keys = Object.keys(properties);
|
|
4236
|
-
const included = include.length > 0 ? include : keys;
|
|
4237
|
-
const ignored = included.filter((key) => {
|
|
4238
|
-
return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
|
|
4239
|
-
});
|
|
4240
|
-
const columnHelper = reactTable.createColumnHelper();
|
|
4241
|
-
const columns = [
|
|
4242
|
-
...ignored.map((column, index) => {
|
|
4243
|
-
// @ts-expect-error column accessor type issue with generic TData
|
|
4244
|
-
return columnHelper.accessor(column, {
|
|
4245
|
-
cell: (props) => {
|
|
4246
|
-
// @ts-expect-error find type for unknown
|
|
4247
|
-
const value = props.row.original[column];
|
|
4248
|
-
if (typeof value === 'object') {
|
|
4249
|
-
return (jsxRuntime.jsx(react.Grid, { overflow: 'auto', children: jsxRuntime.jsx(RecordDisplay, { object: value }) }));
|
|
4250
|
-
}
|
|
4251
|
-
return jsxRuntime.jsx(TextCell, { children: value });
|
|
4252
|
-
},
|
|
4253
|
-
header: (columnHeader) => {
|
|
4254
|
-
const displayName = columnHeader.column.columnDef.meta?.displayName ??
|
|
4255
|
-
getColumn({ column });
|
|
4256
|
-
return jsxRuntime.jsx("span", { children: displayName });
|
|
4257
|
-
},
|
|
4258
|
-
footer: (columnFooter) => {
|
|
4259
|
-
const displayName = columnFooter.column.columnDef.meta?.displayName ??
|
|
4260
|
-
getColumn({ column });
|
|
4261
|
-
return jsxRuntime.jsx("span", { children: displayName });
|
|
4262
|
-
},
|
|
4263
|
-
size: width[index] ?? defaultWidth,
|
|
4264
|
-
meta: Object.keys(meta).length > 0 ? meta[column] : {},
|
|
4265
|
-
});
|
|
4266
|
-
}),
|
|
4267
|
-
];
|
|
4268
|
-
return columns;
|
|
4269
|
-
};
|
|
4270
|
-
|
|
4271
4189
|
//@ts-expect-error TODO: find appropriate type
|
|
4272
4190
|
const SchemaFormContext = React.createContext({
|
|
4273
4191
|
schema: {},
|
|
@@ -4291,114 +4209,6 @@ const useSchemaContext = () => {
|
|
|
4291
4209
|
return React.useContext(SchemaFormContext);
|
|
4292
4210
|
};
|
|
4293
4211
|
|
|
4294
|
-
const clearEmptyString = (object) => {
|
|
4295
|
-
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
4296
|
-
};
|
|
4297
|
-
|
|
4298
|
-
const idPickerSanityCheck = (column, customQueryFn, idColumn) => {
|
|
4299
|
-
if (!customQueryFn) {
|
|
4300
|
-
throw new Error(`customQueryFn is required in properties of column ${column} when using id-picker.`);
|
|
4301
|
-
}
|
|
4302
|
-
if (!idColumn) {
|
|
4303
|
-
throw new Error(`idColumn is required in properties of column ${column} when using id-picker.`);
|
|
4304
|
-
}
|
|
4305
|
-
};
|
|
4306
|
-
const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
|
|
4307
|
-
showSubmitButton: true,
|
|
4308
|
-
showResetButton: true,
|
|
4309
|
-
showTitle: true,
|
|
4310
|
-
}, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
4311
|
-
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
4312
|
-
const [isError, setIsError] = React.useState(false);
|
|
4313
|
-
const [isSubmiting, setIsSubmiting] = React.useState(false);
|
|
4314
|
-
const [validatedData, setValidatedData] = React.useState();
|
|
4315
|
-
const [error, setError] = React.useState();
|
|
4316
|
-
const onBeforeSubmit = () => {
|
|
4317
|
-
setIsSubmiting(true);
|
|
4318
|
-
};
|
|
4319
|
-
const onAfterSubmit = () => {
|
|
4320
|
-
setIsSubmiting(false);
|
|
4321
|
-
};
|
|
4322
|
-
const onSubmitError = (error) => {
|
|
4323
|
-
setIsError(true);
|
|
4324
|
-
setError(error);
|
|
4325
|
-
};
|
|
4326
|
-
const onSubmitSuccess = () => {
|
|
4327
|
-
setIsSuccess(true);
|
|
4328
|
-
};
|
|
4329
|
-
const defaultOnSubmit = async (promise) => {
|
|
4330
|
-
try {
|
|
4331
|
-
console.log('onBeforeSubmit');
|
|
4332
|
-
onBeforeSubmit();
|
|
4333
|
-
await promise;
|
|
4334
|
-
console.log('onSubmitSuccess');
|
|
4335
|
-
onSubmitSuccess();
|
|
4336
|
-
}
|
|
4337
|
-
catch (error) {
|
|
4338
|
-
console.log('onSubmitError', error);
|
|
4339
|
-
onSubmitError(error);
|
|
4340
|
-
}
|
|
4341
|
-
finally {
|
|
4342
|
-
onAfterSubmit();
|
|
4343
|
-
}
|
|
4344
|
-
};
|
|
4345
|
-
const defaultSubmitPromise = (data) => {
|
|
4346
|
-
if (!requestOptions.url) {
|
|
4347
|
-
throw new Error('requestOptions.url is required when onSubmit is not provided');
|
|
4348
|
-
}
|
|
4349
|
-
const options = {
|
|
4350
|
-
method: 'POST',
|
|
4351
|
-
data: clearEmptyString(data),
|
|
4352
|
-
...requestOptions,
|
|
4353
|
-
};
|
|
4354
|
-
return axios.request(options);
|
|
4355
|
-
};
|
|
4356
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4357
|
-
const onFormSubmit = async (data) => {
|
|
4358
|
-
// Validation is handled by react-hook-form
|
|
4359
|
-
// This function will only be called if validation passes
|
|
4360
|
-
if (onSubmit === undefined) {
|
|
4361
|
-
await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
|
|
4362
|
-
return;
|
|
4363
|
-
}
|
|
4364
|
-
await defaultOnSubmit(Promise.resolve(onSubmit(data)));
|
|
4365
|
-
};
|
|
4366
|
-
return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
|
|
4367
|
-
schema,
|
|
4368
|
-
order,
|
|
4369
|
-
ignore,
|
|
4370
|
-
include,
|
|
4371
|
-
// @ts-expect-error TODO: find appropriate types
|
|
4372
|
-
onSubmit,
|
|
4373
|
-
rowNumber,
|
|
4374
|
-
idMap,
|
|
4375
|
-
setIdMap,
|
|
4376
|
-
requestOptions,
|
|
4377
|
-
isSuccess,
|
|
4378
|
-
setIsSuccess,
|
|
4379
|
-
isError,
|
|
4380
|
-
setIsError,
|
|
4381
|
-
isSubmiting,
|
|
4382
|
-
setIsSubmiting,
|
|
4383
|
-
validatedData,
|
|
4384
|
-
setValidatedData,
|
|
4385
|
-
error,
|
|
4386
|
-
setError,
|
|
4387
|
-
getUpdatedData,
|
|
4388
|
-
customErrorRenderer,
|
|
4389
|
-
customSuccessRenderer,
|
|
4390
|
-
displayConfig,
|
|
4391
|
-
onFormSubmit,
|
|
4392
|
-
dateTimePickerLabels,
|
|
4393
|
-
idPickerLabels,
|
|
4394
|
-
enumPickerLabels,
|
|
4395
|
-
filePickerLabels,
|
|
4396
|
-
formButtonLabels,
|
|
4397
|
-
timePickerLabels,
|
|
4398
|
-
insideDialog,
|
|
4399
|
-
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
4400
|
-
};
|
|
4401
|
-
|
|
4402
4212
|
const useFormLabel = (column, prefix = '', schema) => {
|
|
4403
4213
|
const colLabel = `${prefix}${column}`;
|
|
4404
4214
|
return {
|
|
@@ -6012,13 +5822,12 @@ const defaultRenderDisplay = (item) => {
|
|
|
6012
5822
|
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
6013
5823
|
const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
6014
5824
|
const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
6015
|
-
const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn,
|
|
5825
|
+
const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn, variant, } = schema;
|
|
6016
5826
|
// loadInitialValues should be provided in schema for id-picker fields
|
|
6017
5827
|
// It's used to load the record of the id so the display is human-readable
|
|
6018
5828
|
if (variant === 'id-picker' && !loadInitialValues) {
|
|
6019
5829
|
console.warn(`loadInitialValues is recommended in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
|
|
6020
5830
|
}
|
|
6021
|
-
const column_ref = idColumn || 'id';
|
|
6022
5831
|
const [searchText, setSearchText] = React.useState('');
|
|
6023
5832
|
const debouncedSearchText = usehooks.useDebounce(searchText, 300);
|
|
6024
5833
|
const [limit] = React.useState(50); // Increased limit for combobox
|
|
@@ -6078,7 +5887,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6078
5887
|
const result = await loadInitialValues({
|
|
6079
5888
|
ids: missingIds,
|
|
6080
5889
|
customQueryFn: customQueryFn,
|
|
6081
|
-
idColumn: column_ref,
|
|
6082
5890
|
setIdMap,
|
|
6083
5891
|
});
|
|
6084
5892
|
return result.data;
|
|
@@ -6139,12 +5947,15 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6139
5947
|
// Depend on idMapKey which only changes when items we care about change
|
|
6140
5948
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6141
5949
|
}, [currentValueKey, idMapKey]);
|
|
6142
|
-
//
|
|
6143
|
-
|
|
6144
|
-
// Use schema's itemToValue if provided, otherwise use default
|
|
5950
|
+
// Use schema's itemToValue if provided, otherwise throw error
|
|
5951
|
+
// schemaItemToValue should be provided in schema for id-picker fields
|
|
6145
5952
|
const itemToValueFn = schemaItemToValue
|
|
6146
5953
|
? (item) => schemaItemToValue(item)
|
|
6147
|
-
:
|
|
5954
|
+
: (item) => {
|
|
5955
|
+
console.warn(`itemToValue is required in schema for IdPicker field '${column}'. Please provide itemToValue function in the schema. Currently trying to get 'id' field as last resort`);
|
|
5956
|
+
// Fallback: try to get 'id' field as last resort
|
|
5957
|
+
return String(item?.id ?? item);
|
|
5958
|
+
};
|
|
6148
5959
|
// itemToString function: convert item to readable string using renderDisplay
|
|
6149
5960
|
// This ensures items can always be displayed as readable strings in the combobox
|
|
6150
5961
|
const renderFn = renderDisplay || defaultRenderDisplay;
|
|
@@ -6206,7 +6017,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6206
6017
|
})
|
|
6207
6018
|
.filter((item) => item !== null);
|
|
6208
6019
|
return [...itemsFromIdMap, ...itemsFromDataList];
|
|
6209
|
-
}, [dataList,
|
|
6020
|
+
}, [dataList, renderDisplay, idMapItems, itemToValueFn]);
|
|
6210
6021
|
// Use filter hook for combobox
|
|
6211
6022
|
const { contains } = react.useFilter({ sensitivity: 'base' });
|
|
6212
6023
|
// Create collection for combobox
|
|
@@ -6272,7 +6083,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6272
6083
|
itemToString: itemToStringFn,
|
|
6273
6084
|
loadInitialValues: loadInitialValues ??
|
|
6274
6085
|
(async () => ({ data: { data: [], count: 0 }, idMap: {} })), // Fallback if not provided
|
|
6275
|
-
column_ref,
|
|
6276
6086
|
errors,
|
|
6277
6087
|
setValue,
|
|
6278
6088
|
};
|
|
@@ -8121,7 +7931,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
8121
7931
|
|
|
8122
7932
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
8123
7933
|
const colSchema = schema;
|
|
8124
|
-
const { type, variant, properties: innerProperties,
|
|
7934
|
+
const { type, variant, properties: innerProperties, format, items } = schema;
|
|
8125
7935
|
if (variant === 'custom-input') {
|
|
8126
7936
|
return jsxRuntime.jsx(CustomInput, { schema: colSchema, prefix, column });
|
|
8127
7937
|
}
|
|
@@ -8130,7 +7940,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
8130
7940
|
return jsxRuntime.jsx(EnumPicker, { schema: colSchema, prefix, column });
|
|
8131
7941
|
}
|
|
8132
7942
|
if (variant === 'id-picker') {
|
|
8133
|
-
idPickerSanityCheck(column, customQueryFn, idColumn);
|
|
8134
7943
|
return jsxRuntime.jsx(IdPickerSingle, { schema: colSchema, prefix, column });
|
|
8135
7944
|
}
|
|
8136
7945
|
if (format === 'date') {
|
|
@@ -8164,7 +7973,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
8164
7973
|
}
|
|
8165
7974
|
if (type === 'array') {
|
|
8166
7975
|
if (variant === 'id-picker') {
|
|
8167
|
-
idPickerSanityCheck(column, customQueryFn, idColumn);
|
|
8168
7976
|
return jsxRuntime.jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
|
|
8169
7977
|
}
|
|
8170
7978
|
if (variant === 'tag-picker') {
|
|
@@ -8278,6 +8086,106 @@ const FormTitle = () => {
|
|
|
8278
8086
|
return jsxRuntime.jsx(react.Heading, { children: schema.title ?? 'Form' });
|
|
8279
8087
|
};
|
|
8280
8088
|
|
|
8089
|
+
const clearEmptyString = (object) => {
|
|
8090
|
+
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
8091
|
+
};
|
|
8092
|
+
|
|
8093
|
+
const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
|
|
8094
|
+
showSubmitButton: true,
|
|
8095
|
+
showResetButton: true,
|
|
8096
|
+
showTitle: true,
|
|
8097
|
+
}, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
8098
|
+
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
8099
|
+
const [isError, setIsError] = React.useState(false);
|
|
8100
|
+
const [isSubmiting, setIsSubmiting] = React.useState(false);
|
|
8101
|
+
const [validatedData, setValidatedData] = React.useState();
|
|
8102
|
+
const [error, setError] = React.useState();
|
|
8103
|
+
const onBeforeSubmit = () => {
|
|
8104
|
+
setIsSubmiting(true);
|
|
8105
|
+
};
|
|
8106
|
+
const onAfterSubmit = () => {
|
|
8107
|
+
setIsSubmiting(false);
|
|
8108
|
+
};
|
|
8109
|
+
const onSubmitError = (error) => {
|
|
8110
|
+
setIsError(true);
|
|
8111
|
+
setError(error);
|
|
8112
|
+
};
|
|
8113
|
+
const onSubmitSuccess = () => {
|
|
8114
|
+
setIsSuccess(true);
|
|
8115
|
+
};
|
|
8116
|
+
const defaultOnSubmit = async (promise) => {
|
|
8117
|
+
try {
|
|
8118
|
+
console.log('onBeforeSubmit');
|
|
8119
|
+
onBeforeSubmit();
|
|
8120
|
+
await promise;
|
|
8121
|
+
console.log('onSubmitSuccess');
|
|
8122
|
+
onSubmitSuccess();
|
|
8123
|
+
}
|
|
8124
|
+
catch (error) {
|
|
8125
|
+
console.log('onSubmitError', error);
|
|
8126
|
+
onSubmitError(error);
|
|
8127
|
+
}
|
|
8128
|
+
finally {
|
|
8129
|
+
onAfterSubmit();
|
|
8130
|
+
}
|
|
8131
|
+
};
|
|
8132
|
+
const defaultSubmitPromise = (data) => {
|
|
8133
|
+
if (!requestOptions.url) {
|
|
8134
|
+
throw new Error('requestOptions.url is required when onSubmit is not provided');
|
|
8135
|
+
}
|
|
8136
|
+
const options = {
|
|
8137
|
+
method: 'POST',
|
|
8138
|
+
data: clearEmptyString(data),
|
|
8139
|
+
...requestOptions,
|
|
8140
|
+
};
|
|
8141
|
+
return axios.request(options);
|
|
8142
|
+
};
|
|
8143
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8144
|
+
const onFormSubmit = async (data) => {
|
|
8145
|
+
// Validation is handled by react-hook-form
|
|
8146
|
+
// This function will only be called if validation passes
|
|
8147
|
+
if (onSubmit === undefined) {
|
|
8148
|
+
await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
|
|
8149
|
+
return;
|
|
8150
|
+
}
|
|
8151
|
+
await defaultOnSubmit(Promise.resolve(onSubmit(data)));
|
|
8152
|
+
};
|
|
8153
|
+
return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
|
|
8154
|
+
schema,
|
|
8155
|
+
order,
|
|
8156
|
+
ignore,
|
|
8157
|
+
include,
|
|
8158
|
+
// @ts-expect-error TODO: find appropriate types
|
|
8159
|
+
onSubmit,
|
|
8160
|
+
rowNumber,
|
|
8161
|
+
idMap,
|
|
8162
|
+
setIdMap,
|
|
8163
|
+
requestOptions,
|
|
8164
|
+
isSuccess,
|
|
8165
|
+
setIsSuccess,
|
|
8166
|
+
isError,
|
|
8167
|
+
setIsError,
|
|
8168
|
+
isSubmiting,
|
|
8169
|
+
setIsSubmiting,
|
|
8170
|
+
validatedData,
|
|
8171
|
+
setValidatedData,
|
|
8172
|
+
error,
|
|
8173
|
+
setError,
|
|
8174
|
+
getUpdatedData,
|
|
8175
|
+
customErrorRenderer,
|
|
8176
|
+
customSuccessRenderer,
|
|
8177
|
+
displayConfig,
|
|
8178
|
+
onFormSubmit,
|
|
8179
|
+
dateTimePickerLabels,
|
|
8180
|
+
idPickerLabels,
|
|
8181
|
+
enumPickerLabels,
|
|
8182
|
+
filePickerLabels,
|
|
8183
|
+
formButtonLabels,
|
|
8184
|
+
timePickerLabels,
|
|
8185
|
+
insideDialog,
|
|
8186
|
+
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
8187
|
+
};
|
|
8188
|
+
|
|
8281
8189
|
const DefaultForm = ({ formConfig, }) => {
|
|
8282
8190
|
const { showTitle } = formConfig.displayConfig ?? {};
|
|
8283
8191
|
return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
|
|
@@ -8526,6 +8434,26 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
|
|
|
8526
8434
|
}
|
|
8527
8435
|
};
|
|
8528
8436
|
|
|
8437
|
+
const snakeToLabel = (str) => {
|
|
8438
|
+
return str
|
|
8439
|
+
.split("_") // Split by underscore
|
|
8440
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
|
|
8441
|
+
.join(" "); // Join with space
|
|
8442
|
+
};
|
|
8443
|
+
|
|
8444
|
+
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
8445
|
+
const getColumn = ({ field }) => {
|
|
8446
|
+
return snakeToLabel(field);
|
|
8447
|
+
};
|
|
8448
|
+
if (object === null) {
|
|
8449
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "null" });
|
|
8450
|
+
}
|
|
8451
|
+
return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
8452
|
+
const uniqueKey = `${prefix}${field}-${index}`;
|
|
8453
|
+
return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsxRuntime.jsx(react.Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, uniqueKey));
|
|
8454
|
+
}) }));
|
|
8455
|
+
};
|
|
8456
|
+
|
|
8529
8457
|
const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
8530
8458
|
const { columns, data } = useDataTableContext();
|
|
8531
8459
|
const columnsMap = Object.fromEntries(columns.map((def) => {
|
|
@@ -9457,12 +9385,9 @@ exports.TableViewer = TableViewer;
|
|
|
9457
9385
|
exports.TextCell = TextCell;
|
|
9458
9386
|
exports.ViewDialog = ViewDialog;
|
|
9459
9387
|
exports.defaultRenderDisplay = defaultRenderDisplay;
|
|
9460
|
-
exports.getColumns = getColumns;
|
|
9461
9388
|
exports.getMultiDates = getMultiDates;
|
|
9462
9389
|
exports.getRangeDates = getRangeDates;
|
|
9463
|
-
exports.idPickerSanityCheck = idPickerSanityCheck;
|
|
9464
9390
|
exports.useDataTable = useDataTable;
|
|
9465
9391
|
exports.useDataTableContext = useDataTableContext;
|
|
9466
9392
|
exports.useDataTableServer = useDataTableServer;
|
|
9467
9393
|
exports.useForm = useForm;
|
|
9468
|
-
exports.widthSanityCheck = widthSanityCheck;
|
package/dist/index.mjs
CHANGED
|
@@ -21,10 +21,10 @@ import { IoReload } from 'react-icons/io5';
|
|
|
21
21
|
import { useDebounce } from '@uidotdev/usehooks';
|
|
22
22
|
import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
|
|
23
23
|
import { HiColorSwatch } from 'react-icons/hi';
|
|
24
|
-
import { flexRender,
|
|
24
|
+
import { flexRender, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel } from '@tanstack/react-table';
|
|
25
25
|
import { GrAscend, GrDescend } from 'react-icons/gr';
|
|
26
26
|
import axios from 'axios';
|
|
27
|
-
import {
|
|
27
|
+
import { useFormContext, FormProvider, useForm as useForm$1 } from 'react-hook-form';
|
|
28
28
|
import dayjs from 'dayjs';
|
|
29
29
|
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
30
30
|
import timezone from 'dayjs/plugin/timezone';
|
|
@@ -4166,88 +4166,6 @@ const useDataTableServer = (props) => {
|
|
|
4166
4166
|
};
|
|
4167
4167
|
};
|
|
4168
4168
|
|
|
4169
|
-
const idListSanityCheck = (param, idList, properties) => {
|
|
4170
|
-
const allKeyExists = idList.every((key) => Object.keys(properties).some((column) => column == key));
|
|
4171
|
-
if (!allKeyExists) {
|
|
4172
|
-
const wrongKey = idList.find((key) => !Object.keys(properties).some((column) => column == key));
|
|
4173
|
-
throw new Error(`The key ${wrongKey} in ${param} does not exist in schema.`);
|
|
4174
|
-
}
|
|
4175
|
-
};
|
|
4176
|
-
|
|
4177
|
-
const snakeToLabel = (str) => {
|
|
4178
|
-
return str
|
|
4179
|
-
.split("_") // Split by underscore
|
|
4180
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
|
|
4181
|
-
.join(" "); // Join with space
|
|
4182
|
-
};
|
|
4183
|
-
|
|
4184
|
-
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
4185
|
-
const getColumn = ({ field }) => {
|
|
4186
|
-
return snakeToLabel(field);
|
|
4187
|
-
};
|
|
4188
|
-
if (object === null) {
|
|
4189
|
-
return jsx(Fragment, { children: "null" });
|
|
4190
|
-
}
|
|
4191
|
-
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
4192
|
-
const uniqueKey = `${prefix}${field}-${index}`;
|
|
4193
|
-
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsx(Text, { children: JSON.stringify(value) }))] }, uniqueKey));
|
|
4194
|
-
}) }));
|
|
4195
|
-
};
|
|
4196
|
-
|
|
4197
|
-
const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
4198
|
-
const widthListToolong = widthList.length > Object.keys(properties).length;
|
|
4199
|
-
if (widthListToolong) {
|
|
4200
|
-
throw new Error(`The width list is too long given from the number of properties.`);
|
|
4201
|
-
}
|
|
4202
|
-
const widthListToolongWithIgnore = widthList.length > Object.keys(properties).length - ignoreList.length;
|
|
4203
|
-
if (widthListToolongWithIgnore) {
|
|
4204
|
-
throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
|
|
4205
|
-
}
|
|
4206
|
-
};
|
|
4207
|
-
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
|
|
4208
|
-
const { properties } = schema;
|
|
4209
|
-
idListSanityCheck('ignore', ignore, properties);
|
|
4210
|
-
widthSanityCheck(width, ignore, properties);
|
|
4211
|
-
idListSanityCheck('meta', Object.keys(meta), properties);
|
|
4212
|
-
const getColumn = ({ column }) => {
|
|
4213
|
-
return snakeToLabel(column);
|
|
4214
|
-
};
|
|
4215
|
-
const keys = Object.keys(properties);
|
|
4216
|
-
const included = include.length > 0 ? include : keys;
|
|
4217
|
-
const ignored = included.filter((key) => {
|
|
4218
|
-
return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
|
|
4219
|
-
});
|
|
4220
|
-
const columnHelper = createColumnHelper();
|
|
4221
|
-
const columns = [
|
|
4222
|
-
...ignored.map((column, index) => {
|
|
4223
|
-
// @ts-expect-error column accessor type issue with generic TData
|
|
4224
|
-
return columnHelper.accessor(column, {
|
|
4225
|
-
cell: (props) => {
|
|
4226
|
-
// @ts-expect-error find type for unknown
|
|
4227
|
-
const value = props.row.original[column];
|
|
4228
|
-
if (typeof value === 'object') {
|
|
4229
|
-
return (jsx(Grid, { overflow: 'auto', children: jsx(RecordDisplay, { object: value }) }));
|
|
4230
|
-
}
|
|
4231
|
-
return jsx(TextCell, { children: value });
|
|
4232
|
-
},
|
|
4233
|
-
header: (columnHeader) => {
|
|
4234
|
-
const displayName = columnHeader.column.columnDef.meta?.displayName ??
|
|
4235
|
-
getColumn({ column });
|
|
4236
|
-
return jsx("span", { children: displayName });
|
|
4237
|
-
},
|
|
4238
|
-
footer: (columnFooter) => {
|
|
4239
|
-
const displayName = columnFooter.column.columnDef.meta?.displayName ??
|
|
4240
|
-
getColumn({ column });
|
|
4241
|
-
return jsx("span", { children: displayName });
|
|
4242
|
-
},
|
|
4243
|
-
size: width[index] ?? defaultWidth,
|
|
4244
|
-
meta: Object.keys(meta).length > 0 ? meta[column] : {},
|
|
4245
|
-
});
|
|
4246
|
-
}),
|
|
4247
|
-
];
|
|
4248
|
-
return columns;
|
|
4249
|
-
};
|
|
4250
|
-
|
|
4251
4169
|
//@ts-expect-error TODO: find appropriate type
|
|
4252
4170
|
const SchemaFormContext = createContext({
|
|
4253
4171
|
schema: {},
|
|
@@ -4271,114 +4189,6 @@ const useSchemaContext = () => {
|
|
|
4271
4189
|
return useContext(SchemaFormContext);
|
|
4272
4190
|
};
|
|
4273
4191
|
|
|
4274
|
-
const clearEmptyString = (object) => {
|
|
4275
|
-
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
4276
|
-
};
|
|
4277
|
-
|
|
4278
|
-
const idPickerSanityCheck = (column, customQueryFn, idColumn) => {
|
|
4279
|
-
if (!customQueryFn) {
|
|
4280
|
-
throw new Error(`customQueryFn is required in properties of column ${column} when using id-picker.`);
|
|
4281
|
-
}
|
|
4282
|
-
if (!idColumn) {
|
|
4283
|
-
throw new Error(`idColumn is required in properties of column ${column} when using id-picker.`);
|
|
4284
|
-
}
|
|
4285
|
-
};
|
|
4286
|
-
const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
|
|
4287
|
-
showSubmitButton: true,
|
|
4288
|
-
showResetButton: true,
|
|
4289
|
-
showTitle: true,
|
|
4290
|
-
}, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
4291
|
-
const [isSuccess, setIsSuccess] = useState(false);
|
|
4292
|
-
const [isError, setIsError] = useState(false);
|
|
4293
|
-
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
4294
|
-
const [validatedData, setValidatedData] = useState();
|
|
4295
|
-
const [error, setError] = useState();
|
|
4296
|
-
const onBeforeSubmit = () => {
|
|
4297
|
-
setIsSubmiting(true);
|
|
4298
|
-
};
|
|
4299
|
-
const onAfterSubmit = () => {
|
|
4300
|
-
setIsSubmiting(false);
|
|
4301
|
-
};
|
|
4302
|
-
const onSubmitError = (error) => {
|
|
4303
|
-
setIsError(true);
|
|
4304
|
-
setError(error);
|
|
4305
|
-
};
|
|
4306
|
-
const onSubmitSuccess = () => {
|
|
4307
|
-
setIsSuccess(true);
|
|
4308
|
-
};
|
|
4309
|
-
const defaultOnSubmit = async (promise) => {
|
|
4310
|
-
try {
|
|
4311
|
-
console.log('onBeforeSubmit');
|
|
4312
|
-
onBeforeSubmit();
|
|
4313
|
-
await promise;
|
|
4314
|
-
console.log('onSubmitSuccess');
|
|
4315
|
-
onSubmitSuccess();
|
|
4316
|
-
}
|
|
4317
|
-
catch (error) {
|
|
4318
|
-
console.log('onSubmitError', error);
|
|
4319
|
-
onSubmitError(error);
|
|
4320
|
-
}
|
|
4321
|
-
finally {
|
|
4322
|
-
onAfterSubmit();
|
|
4323
|
-
}
|
|
4324
|
-
};
|
|
4325
|
-
const defaultSubmitPromise = (data) => {
|
|
4326
|
-
if (!requestOptions.url) {
|
|
4327
|
-
throw new Error('requestOptions.url is required when onSubmit is not provided');
|
|
4328
|
-
}
|
|
4329
|
-
const options = {
|
|
4330
|
-
method: 'POST',
|
|
4331
|
-
data: clearEmptyString(data),
|
|
4332
|
-
...requestOptions,
|
|
4333
|
-
};
|
|
4334
|
-
return axios.request(options);
|
|
4335
|
-
};
|
|
4336
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4337
|
-
const onFormSubmit = async (data) => {
|
|
4338
|
-
// Validation is handled by react-hook-form
|
|
4339
|
-
// This function will only be called if validation passes
|
|
4340
|
-
if (onSubmit === undefined) {
|
|
4341
|
-
await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
|
|
4342
|
-
return;
|
|
4343
|
-
}
|
|
4344
|
-
await defaultOnSubmit(Promise.resolve(onSubmit(data)));
|
|
4345
|
-
};
|
|
4346
|
-
return (jsx(SchemaFormContext.Provider, { value: {
|
|
4347
|
-
schema,
|
|
4348
|
-
order,
|
|
4349
|
-
ignore,
|
|
4350
|
-
include,
|
|
4351
|
-
// @ts-expect-error TODO: find appropriate types
|
|
4352
|
-
onSubmit,
|
|
4353
|
-
rowNumber,
|
|
4354
|
-
idMap,
|
|
4355
|
-
setIdMap,
|
|
4356
|
-
requestOptions,
|
|
4357
|
-
isSuccess,
|
|
4358
|
-
setIsSuccess,
|
|
4359
|
-
isError,
|
|
4360
|
-
setIsError,
|
|
4361
|
-
isSubmiting,
|
|
4362
|
-
setIsSubmiting,
|
|
4363
|
-
validatedData,
|
|
4364
|
-
setValidatedData,
|
|
4365
|
-
error,
|
|
4366
|
-
setError,
|
|
4367
|
-
getUpdatedData,
|
|
4368
|
-
customErrorRenderer,
|
|
4369
|
-
customSuccessRenderer,
|
|
4370
|
-
displayConfig,
|
|
4371
|
-
onFormSubmit,
|
|
4372
|
-
dateTimePickerLabels,
|
|
4373
|
-
idPickerLabels,
|
|
4374
|
-
enumPickerLabels,
|
|
4375
|
-
filePickerLabels,
|
|
4376
|
-
formButtonLabels,
|
|
4377
|
-
timePickerLabels,
|
|
4378
|
-
insideDialog,
|
|
4379
|
-
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
4380
|
-
};
|
|
4381
|
-
|
|
4382
4192
|
const useFormLabel = (column, prefix = '', schema) => {
|
|
4383
4193
|
const colLabel = `${prefix}${column}`;
|
|
4384
4194
|
return {
|
|
@@ -5992,13 +5802,12 @@ const defaultRenderDisplay = (item) => {
|
|
|
5992
5802
|
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5993
5803
|
const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
|
|
5994
5804
|
const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5995
|
-
const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn,
|
|
5805
|
+
const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn, variant, } = schema;
|
|
5996
5806
|
// loadInitialValues should be provided in schema for id-picker fields
|
|
5997
5807
|
// It's used to load the record of the id so the display is human-readable
|
|
5998
5808
|
if (variant === 'id-picker' && !loadInitialValues) {
|
|
5999
5809
|
console.warn(`loadInitialValues is recommended in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
|
|
6000
5810
|
}
|
|
6001
|
-
const column_ref = idColumn || 'id';
|
|
6002
5811
|
const [searchText, setSearchText] = useState('');
|
|
6003
5812
|
const debouncedSearchText = useDebounce(searchText, 300);
|
|
6004
5813
|
const [limit] = useState(50); // Increased limit for combobox
|
|
@@ -6058,7 +5867,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6058
5867
|
const result = await loadInitialValues({
|
|
6059
5868
|
ids: missingIds,
|
|
6060
5869
|
customQueryFn: customQueryFn,
|
|
6061
|
-
idColumn: column_ref,
|
|
6062
5870
|
setIdMap,
|
|
6063
5871
|
});
|
|
6064
5872
|
return result.data;
|
|
@@ -6119,12 +5927,15 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6119
5927
|
// Depend on idMapKey which only changes when items we care about change
|
|
6120
5928
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6121
5929
|
}, [currentValueKey, idMapKey]);
|
|
6122
|
-
//
|
|
6123
|
-
|
|
6124
|
-
// Use schema's itemToValue if provided, otherwise use default
|
|
5930
|
+
// Use schema's itemToValue if provided, otherwise throw error
|
|
5931
|
+
// schemaItemToValue should be provided in schema for id-picker fields
|
|
6125
5932
|
const itemToValueFn = schemaItemToValue
|
|
6126
5933
|
? (item) => schemaItemToValue(item)
|
|
6127
|
-
:
|
|
5934
|
+
: (item) => {
|
|
5935
|
+
console.warn(`itemToValue is required in schema for IdPicker field '${column}'. Please provide itemToValue function in the schema. Currently trying to get 'id' field as last resort`);
|
|
5936
|
+
// Fallback: try to get 'id' field as last resort
|
|
5937
|
+
return String(item?.id ?? item);
|
|
5938
|
+
};
|
|
6128
5939
|
// itemToString function: convert item to readable string using renderDisplay
|
|
6129
5940
|
// This ensures items can always be displayed as readable strings in the combobox
|
|
6130
5941
|
const renderFn = renderDisplay || defaultRenderDisplay;
|
|
@@ -6186,7 +5997,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6186
5997
|
})
|
|
6187
5998
|
.filter((item) => item !== null);
|
|
6188
5999
|
return [...itemsFromIdMap, ...itemsFromDataList];
|
|
6189
|
-
}, [dataList,
|
|
6000
|
+
}, [dataList, renderDisplay, idMapItems, itemToValueFn]);
|
|
6190
6001
|
// Use filter hook for combobox
|
|
6191
6002
|
const { contains } = useFilter({ sensitivity: 'base' });
|
|
6192
6003
|
// Create collection for combobox
|
|
@@ -6252,7 +6063,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6252
6063
|
itemToString: itemToStringFn,
|
|
6253
6064
|
loadInitialValues: loadInitialValues ??
|
|
6254
6065
|
(async () => ({ data: { data: [], count: 0 }, idMap: {} })), // Fallback if not provided
|
|
6255
|
-
column_ref,
|
|
6256
6066
|
errors,
|
|
6257
6067
|
setValue,
|
|
6258
6068
|
};
|
|
@@ -8101,7 +7911,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
8101
7911
|
|
|
8102
7912
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
8103
7913
|
const colSchema = schema;
|
|
8104
|
-
const { type, variant, properties: innerProperties,
|
|
7914
|
+
const { type, variant, properties: innerProperties, format, items } = schema;
|
|
8105
7915
|
if (variant === 'custom-input') {
|
|
8106
7916
|
return jsx(CustomInput, { schema: colSchema, prefix, column });
|
|
8107
7917
|
}
|
|
@@ -8110,7 +7920,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
8110
7920
|
return jsx(EnumPicker, { schema: colSchema, prefix, column });
|
|
8111
7921
|
}
|
|
8112
7922
|
if (variant === 'id-picker') {
|
|
8113
|
-
idPickerSanityCheck(column, customQueryFn, idColumn);
|
|
8114
7923
|
return jsx(IdPickerSingle, { schema: colSchema, prefix, column });
|
|
8115
7924
|
}
|
|
8116
7925
|
if (format === 'date') {
|
|
@@ -8144,7 +7953,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
8144
7953
|
}
|
|
8145
7954
|
if (type === 'array') {
|
|
8146
7955
|
if (variant === 'id-picker') {
|
|
8147
|
-
idPickerSanityCheck(column, customQueryFn, idColumn);
|
|
8148
7956
|
return jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
|
|
8149
7957
|
}
|
|
8150
7958
|
if (variant === 'tag-picker') {
|
|
@@ -8258,6 +8066,106 @@ const FormTitle = () => {
|
|
|
8258
8066
|
return jsx(Heading, { children: schema.title ?? 'Form' });
|
|
8259
8067
|
};
|
|
8260
8068
|
|
|
8069
|
+
const clearEmptyString = (object) => {
|
|
8070
|
+
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
8071
|
+
};
|
|
8072
|
+
|
|
8073
|
+
const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
|
|
8074
|
+
showSubmitButton: true,
|
|
8075
|
+
showResetButton: true,
|
|
8076
|
+
showTitle: true,
|
|
8077
|
+
}, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
8078
|
+
const [isSuccess, setIsSuccess] = useState(false);
|
|
8079
|
+
const [isError, setIsError] = useState(false);
|
|
8080
|
+
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
8081
|
+
const [validatedData, setValidatedData] = useState();
|
|
8082
|
+
const [error, setError] = useState();
|
|
8083
|
+
const onBeforeSubmit = () => {
|
|
8084
|
+
setIsSubmiting(true);
|
|
8085
|
+
};
|
|
8086
|
+
const onAfterSubmit = () => {
|
|
8087
|
+
setIsSubmiting(false);
|
|
8088
|
+
};
|
|
8089
|
+
const onSubmitError = (error) => {
|
|
8090
|
+
setIsError(true);
|
|
8091
|
+
setError(error);
|
|
8092
|
+
};
|
|
8093
|
+
const onSubmitSuccess = () => {
|
|
8094
|
+
setIsSuccess(true);
|
|
8095
|
+
};
|
|
8096
|
+
const defaultOnSubmit = async (promise) => {
|
|
8097
|
+
try {
|
|
8098
|
+
console.log('onBeforeSubmit');
|
|
8099
|
+
onBeforeSubmit();
|
|
8100
|
+
await promise;
|
|
8101
|
+
console.log('onSubmitSuccess');
|
|
8102
|
+
onSubmitSuccess();
|
|
8103
|
+
}
|
|
8104
|
+
catch (error) {
|
|
8105
|
+
console.log('onSubmitError', error);
|
|
8106
|
+
onSubmitError(error);
|
|
8107
|
+
}
|
|
8108
|
+
finally {
|
|
8109
|
+
onAfterSubmit();
|
|
8110
|
+
}
|
|
8111
|
+
};
|
|
8112
|
+
const defaultSubmitPromise = (data) => {
|
|
8113
|
+
if (!requestOptions.url) {
|
|
8114
|
+
throw new Error('requestOptions.url is required when onSubmit is not provided');
|
|
8115
|
+
}
|
|
8116
|
+
const options = {
|
|
8117
|
+
method: 'POST',
|
|
8118
|
+
data: clearEmptyString(data),
|
|
8119
|
+
...requestOptions,
|
|
8120
|
+
};
|
|
8121
|
+
return axios.request(options);
|
|
8122
|
+
};
|
|
8123
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8124
|
+
const onFormSubmit = async (data) => {
|
|
8125
|
+
// Validation is handled by react-hook-form
|
|
8126
|
+
// This function will only be called if validation passes
|
|
8127
|
+
if (onSubmit === undefined) {
|
|
8128
|
+
await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
|
|
8129
|
+
return;
|
|
8130
|
+
}
|
|
8131
|
+
await defaultOnSubmit(Promise.resolve(onSubmit(data)));
|
|
8132
|
+
};
|
|
8133
|
+
return (jsx(SchemaFormContext.Provider, { value: {
|
|
8134
|
+
schema,
|
|
8135
|
+
order,
|
|
8136
|
+
ignore,
|
|
8137
|
+
include,
|
|
8138
|
+
// @ts-expect-error TODO: find appropriate types
|
|
8139
|
+
onSubmit,
|
|
8140
|
+
rowNumber,
|
|
8141
|
+
idMap,
|
|
8142
|
+
setIdMap,
|
|
8143
|
+
requestOptions,
|
|
8144
|
+
isSuccess,
|
|
8145
|
+
setIsSuccess,
|
|
8146
|
+
isError,
|
|
8147
|
+
setIsError,
|
|
8148
|
+
isSubmiting,
|
|
8149
|
+
setIsSubmiting,
|
|
8150
|
+
validatedData,
|
|
8151
|
+
setValidatedData,
|
|
8152
|
+
error,
|
|
8153
|
+
setError,
|
|
8154
|
+
getUpdatedData,
|
|
8155
|
+
customErrorRenderer,
|
|
8156
|
+
customSuccessRenderer,
|
|
8157
|
+
displayConfig,
|
|
8158
|
+
onFormSubmit,
|
|
8159
|
+
dateTimePickerLabels,
|
|
8160
|
+
idPickerLabels,
|
|
8161
|
+
enumPickerLabels,
|
|
8162
|
+
filePickerLabels,
|
|
8163
|
+
formButtonLabels,
|
|
8164
|
+
timePickerLabels,
|
|
8165
|
+
insideDialog,
|
|
8166
|
+
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
8167
|
+
};
|
|
8168
|
+
|
|
8261
8169
|
const DefaultForm = ({ formConfig, }) => {
|
|
8262
8170
|
const { showTitle } = formConfig.displayConfig ?? {};
|
|
8263
8171
|
return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
|
|
@@ -8506,6 +8414,26 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
|
|
|
8506
8414
|
}
|
|
8507
8415
|
};
|
|
8508
8416
|
|
|
8417
|
+
const snakeToLabel = (str) => {
|
|
8418
|
+
return str
|
|
8419
|
+
.split("_") // Split by underscore
|
|
8420
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
|
|
8421
|
+
.join(" "); // Join with space
|
|
8422
|
+
};
|
|
8423
|
+
|
|
8424
|
+
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
8425
|
+
const getColumn = ({ field }) => {
|
|
8426
|
+
return snakeToLabel(field);
|
|
8427
|
+
};
|
|
8428
|
+
if (object === null) {
|
|
8429
|
+
return jsx(Fragment, { children: "null" });
|
|
8430
|
+
}
|
|
8431
|
+
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
8432
|
+
const uniqueKey = `${prefix}${field}-${index}`;
|
|
8433
|
+
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsx(Text, { children: JSON.stringify(value) }))] }, uniqueKey));
|
|
8434
|
+
}) }));
|
|
8435
|
+
};
|
|
8436
|
+
|
|
8509
8437
|
const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
8510
8438
|
const { columns, data } = useDataTableContext();
|
|
8511
8439
|
const columnsMap = Object.fromEntries(columns.map((def) => {
|
|
@@ -9389,4 +9317,4 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
9389
9317
|
}, children: jsx(DataTableServerContext.Provider, { value: { url: url ?? '', query }, children: children }) }));
|
|
9390
9318
|
}
|
|
9391
9319
|
|
|
9392
|
-
export { CalendarDisplay, CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerContext, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, defaultRenderDisplay,
|
|
9320
|
+
export { CalendarDisplay, CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerContext, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, defaultRenderDisplay, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, useForm };
|
|
@@ -62,8 +62,6 @@ export interface CustomJSONSchema7Definition extends JSONSchema7 {
|
|
|
62
62
|
gridColumn: string;
|
|
63
63
|
gridRow: string;
|
|
64
64
|
customQueryFn: any;
|
|
65
|
-
idColumn: string;
|
|
66
65
|
children: ReactNode;
|
|
67
66
|
}
|
|
68
|
-
export declare const idPickerSanityCheck: (column: string, customQueryFn?: any, idColumn?: string) => void;
|
|
69
67
|
export declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { CustomJSONSchema7, LoadInitialValuesParams, LoadInitialValuesResult } from '../types/CustomJSONSchema7';
|
|
2
|
+
import { CustomJSONSchema7, IdPickerLabels, LoadInitialValuesParams, LoadInitialValuesResult } from '../types/CustomJSONSchema7';
|
|
3
3
|
export interface RecordType {
|
|
4
4
|
[key: string]: any;
|
|
5
5
|
}
|
|
@@ -39,13 +39,12 @@ export interface UseIdPickerDataReturn {
|
|
|
39
39
|
raw: RecordType;
|
|
40
40
|
}>) => void;
|
|
41
41
|
idMap: Record<string, object>;
|
|
42
|
-
idPickerLabels
|
|
42
|
+
idPickerLabels?: IdPickerLabels;
|
|
43
43
|
insideDialog: boolean;
|
|
44
44
|
renderDisplay: ((item: RecordType) => React.ReactNode) | undefined;
|
|
45
45
|
itemToValue: (item: RecordType) => string;
|
|
46
46
|
itemToString: (item: RecordType) => string;
|
|
47
47
|
loadInitialValues: (params: LoadInitialValuesParams) => Promise<LoadInitialValuesResult>;
|
|
48
|
-
column_ref: string;
|
|
49
48
|
errors: any;
|
|
50
49
|
setValue: (name: string, value: any) => void;
|
|
51
50
|
}
|
|
@@ -72,7 +72,6 @@ export interface TimePickerLabels {
|
|
|
72
72
|
export interface LoadInitialValuesParams {
|
|
73
73
|
ids: string[];
|
|
74
74
|
customQueryFn: CustomQueryFn;
|
|
75
|
-
idColumn: string;
|
|
76
75
|
setIdMap: React.Dispatch<React.SetStateAction<Record<string, object>>>;
|
|
77
76
|
}
|
|
78
77
|
export interface LoadInitialValuesResult {
|
|
@@ -86,7 +85,6 @@ export interface CustomJSONSchema7 extends JSONSchema7 {
|
|
|
86
85
|
gridColumn?: string;
|
|
87
86
|
gridRow?: string;
|
|
88
87
|
customQueryFn?: CustomQueryFn;
|
|
89
|
-
idColumn?: string;
|
|
90
88
|
variant?: string;
|
|
91
89
|
renderDisplay?: (item: unknown) => ReactNode;
|
|
92
90
|
itemToValue?: (item: unknown) => string;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -123,7 +123,6 @@ export * from './components/DataTable/display/ErrorAlert';
|
|
|
123
123
|
export * from './components/DataTable/useDataTable';
|
|
124
124
|
export * from './components/DataTable/useDataTableServer';
|
|
125
125
|
export * from './components/DataTable/context/useDataTableContext';
|
|
126
|
-
export * from './components/DataTable/utils/getColumns';
|
|
127
126
|
export * from './components/Form/components/core/DefaultForm';
|
|
128
127
|
export * from './components/Form/components/core/FormRoot';
|
|
129
128
|
export * from './components/Form/components/core/FormTitle';
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { ColumnDef, RowData } from '@tanstack/react-table';
|
|
2
|
-
import { JSONSchema7 } from 'json-schema';
|
|
3
|
-
export interface GetColumnsConfigs<K extends RowData> {
|
|
4
|
-
schema: JSONSchema7;
|
|
5
|
-
include?: K[];
|
|
6
|
-
ignore?: K[];
|
|
7
|
-
width?: number[];
|
|
8
|
-
meta?: {
|
|
9
|
-
[key in K as string]?: object;
|
|
10
|
-
};
|
|
11
|
-
defaultWidth?: number;
|
|
12
|
-
}
|
|
13
|
-
export declare const widthSanityCheck: <K extends unknown>(widthList: number[], ignoreList: K[], properties: { [key in K as string]?: object | undefined; }) => void;
|
|
14
|
-
export declare const getColumns: <TData extends unknown>({ schema, include, ignore, width, meta, defaultWidth, }: GetColumnsConfigs<TData>) => ColumnDef<TData>[];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const idListSanityCheck: (param: string, idList: string[], properties: object) => void;
|