ding-react-admin 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -2
- package/dist/index.js +712 -723
- package/dist/src/crud/InlineFormSet.d.ts +13 -11
- package/dist/src/crud/InlineFormSet.d.ts.map +1 -1
- package/dist/src/crud/ResourceForm.d.ts +10 -2
- package/dist/src/crud/ResourceForm.d.ts.map +1 -1
- package/dist/src/crud/ResourceFormModal.d.ts.map +1 -1
- package/dist/src/crud/ResourceList.d.ts.map +1 -1
- package/dist/src/crud/context/SubmitFieldsContext.d.ts +18 -0
- package/dist/src/crud/context/SubmitFieldsContext.d.ts.map +1 -0
- package/dist/src/crud/fields/BooleanField.d.ts +3 -1
- package/dist/src/crud/fields/BooleanField.d.ts.map +1 -1
- package/dist/src/crud/fields/DateField.d.ts +3 -1
- package/dist/src/crud/fields/DateField.d.ts.map +1 -1
- package/dist/src/crud/fields/FieldWrapper.d.ts +7 -14
- package/dist/src/crud/fields/FieldWrapper.d.ts.map +1 -1
- package/dist/src/crud/fields/NumberField.d.ts +5 -3
- package/dist/src/crud/fields/NumberField.d.ts.map +1 -1
- package/dist/src/crud/fields/PasswordField.d.ts +5 -3
- package/dist/src/crud/fields/PasswordField.d.ts.map +1 -1
- package/dist/src/crud/fields/ReferenceField.d.ts +6 -5
- package/dist/src/crud/fields/ReferenceField.d.ts.map +1 -1
- package/dist/src/crud/fields/ReferenceManyField.d.ts +3 -1
- package/dist/src/crud/fields/ReferenceManyField.d.ts.map +1 -1
- package/dist/src/crud/fields/SelectField.d.ts +3 -1
- package/dist/src/crud/fields/SelectField.d.ts.map +1 -1
- package/dist/src/crud/fields/TextField.d.ts +5 -3
- package/dist/src/crud/fields/TextField.d.ts.map +1 -1
- package/dist/src/crud/index.d.ts +8 -4
- package/dist/src/crud/index.d.ts.map +1 -1
- package/dist/src/crud/types.d.ts +21 -20
- package/dist/src/crud/types.d.ts.map +1 -1
- package/dist/src/crud/utils/inlineFieldName.d.ts +3 -0
- package/dist/src/crud/utils/inlineFieldName.d.ts.map +1 -0
- package/dist/src/crud/utils/useAbortableEffect.d.ts +7 -0
- package/dist/src/crud/utils/useAbortableEffect.d.ts.map +1 -0
- package/dist/src/crud/utils/useResourceFormData.d.ts +47 -0
- package/dist/src/crud/utils/useResourceFormData.d.ts.map +1 -0
- package/dist/src/data/abortError.d.ts +3 -0
- package/dist/src/data/abortError.d.ts.map +1 -0
- package/dist/src/data/abortError.test.d.ts +2 -0
- package/dist/src/data/abortError.test.d.ts.map +1 -0
- package/dist/src/data/createRestResourceHandlers.d.ts +2 -2
- package/dist/src/data/createRestResourceHandlers.d.ts.map +1 -1
- package/dist/src/data/dataProviderTypes.d.ts +7 -1
- package/dist/src/data/dataProviderTypes.d.ts.map +1 -1
- package/dist/src/data/resourceHandlers.d.ts +2 -2
- package/dist/src/data/resourceHandlers.d.ts.map +1 -1
- package/dist/src/index.d.ts +4 -3
- package/dist/src/index.d.ts.map +1 -1
- package/docs/assets/form-with-inline.png +0 -0
- package/package.json +59 -59
- package/src/crud/InlineFormSet.tsx +77 -89
- package/src/crud/ResourceForm.tsx +87 -202
- package/src/crud/ResourceFormModal.tsx +37 -25
- package/src/crud/ResourceList.tsx +35 -26
- package/src/crud/context/SubmitFieldsContext.tsx +62 -0
- package/src/crud/fields/BooleanField.tsx +22 -16
- package/src/crud/fields/DateField.tsx +32 -26
- package/src/crud/fields/FieldWrapper.tsx +32 -54
- package/src/crud/fields/NumberField.tsx +36 -34
- package/src/crud/fields/PasswordField.tsx +41 -40
- package/src/crud/fields/ReferenceField.tsx +35 -130
- package/src/crud/fields/ReferenceManyField.tsx +31 -25
- package/src/crud/fields/SelectField.tsx +6 -0
- package/src/crud/fields/TextField.tsx +32 -30
- package/src/crud/index.ts +19 -2
- package/src/crud/types.ts +132 -130
- package/src/crud/utils/inlineFieldName.ts +8 -0
- package/src/crud/utils/useAbortableEffect.ts +17 -0
- package/src/crud/utils/useResourceFormData.ts +231 -0
- package/src/data/abortError.test.ts +19 -0
- package/src/data/abortError.ts +10 -0
- package/src/data/createMemoryResourceHandlers.ts +1 -1
- package/src/data/createRestResourceHandlers.ts +4 -4
- package/src/data/dataProviderTypes.ts +8 -0
- package/src/data/resourceHandlers.ts +4 -3
- package/src/index.ts +14 -1
- package/dist/src/crud/context/FormFieldsContext.d.ts +0 -14
- package/dist/src/crud/context/FormFieldsContext.d.ts.map +0 -1
- package/dist/src/crud/context/InlineFormContext.d.ts +0 -16
- package/dist/src/crud/context/InlineFormContext.d.ts.map +0 -1
- package/dist/src/crud/fields/useInlineOrFormField.d.ts +0 -10
- package/dist/src/crud/fields/useInlineOrFormField.d.ts.map +0 -1
- package/src/crud/context/FormFieldsContext.tsx +0 -76
- package/src/crud/context/InlineFormContext.tsx +0 -71
- package/src/crud/fields/useInlineOrFormField.tsx +0 -91
|
@@ -2,18 +2,21 @@ import { Select } from "antd";
|
|
|
2
2
|
import { useMemo, useState } from "react";
|
|
3
3
|
import type { BaseSourceProps, FieldRules, ReferenceProps } from "../types";
|
|
4
4
|
import { useChoices } from "../utils/useChoices";
|
|
5
|
-
import {
|
|
5
|
+
import { FieldWrapper } from "./FieldWrapper";
|
|
6
6
|
|
|
7
7
|
export type ReferenceManyFieldProps = BaseSourceProps &
|
|
8
8
|
ReferenceProps & {
|
|
9
|
+
name?: string;
|
|
9
10
|
required?: boolean;
|
|
10
11
|
rules?: FieldRules;
|
|
11
12
|
search?: boolean;
|
|
12
13
|
allowClear?: boolean;
|
|
14
|
+
hideLabel?: boolean;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
export function ReferenceManyField({
|
|
16
18
|
source,
|
|
19
|
+
name,
|
|
17
20
|
label,
|
|
18
21
|
reference,
|
|
19
22
|
choices,
|
|
@@ -23,6 +26,7 @@ export function ReferenceManyField({
|
|
|
23
26
|
rules,
|
|
24
27
|
search,
|
|
25
28
|
allowClear = true,
|
|
29
|
+
hideLabel,
|
|
26
30
|
}: ReferenceManyFieldProps) {
|
|
27
31
|
const [searchText, setSearchText] = useState<string | undefined>();
|
|
28
32
|
const { options, loading } = useChoices(
|
|
@@ -42,29 +46,31 @@ export function ReferenceManyField({
|
|
|
42
46
|
[options],
|
|
43
47
|
);
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
49
|
+
return (
|
|
50
|
+
<FieldWrapper
|
|
51
|
+
source={source}
|
|
52
|
+
name={name}
|
|
53
|
+
label={label}
|
|
54
|
+
required={required}
|
|
55
|
+
rules={rules}
|
|
56
|
+
hideLabel={hideLabel}
|
|
57
|
+
>
|
|
58
|
+
{({ value, onChange, disabled }) => (
|
|
59
|
+
<Select
|
|
60
|
+
mode="multiple"
|
|
61
|
+
value={(value as (string | number)[] | undefined) ?? []}
|
|
62
|
+
onChange={onChange}
|
|
63
|
+
options={selectOptions}
|
|
64
|
+
loading={loading}
|
|
65
|
+
showSearch={search}
|
|
66
|
+
filterOption={search ? false : undefined}
|
|
67
|
+
onSearch={search ? setSearchText : undefined}
|
|
68
|
+
allowClear={allowClear}
|
|
69
|
+
disabled={disabled}
|
|
70
|
+
optionFilterProp="label"
|
|
71
|
+
style={{ width: "100%" }}
|
|
72
|
+
/>
|
|
73
|
+
)}
|
|
74
|
+
</FieldWrapper>
|
|
66
75
|
);
|
|
67
|
-
|
|
68
|
-
if (field.mode === "inline") return null;
|
|
69
|
-
return field.element;
|
|
70
76
|
}
|
|
@@ -3,28 +3,34 @@ import type { BaseSourceProps, ChoiceOption, FieldRules } from "../types";
|
|
|
3
3
|
import { FieldWrapper } from "./FieldWrapper";
|
|
4
4
|
|
|
5
5
|
export type SelectFieldProps = BaseSourceProps & {
|
|
6
|
+
name?: string;
|
|
6
7
|
required?: boolean;
|
|
7
8
|
rules?: FieldRules;
|
|
8
9
|
choices: ChoiceOption[];
|
|
9
10
|
mode?: "multiple";
|
|
10
11
|
allowClear?: boolean;
|
|
12
|
+
hideLabel?: boolean;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
export function SelectField({
|
|
14
16
|
source,
|
|
17
|
+
name,
|
|
15
18
|
label,
|
|
16
19
|
required,
|
|
17
20
|
rules,
|
|
18
21
|
choices,
|
|
19
22
|
mode,
|
|
20
23
|
allowClear,
|
|
24
|
+
hideLabel,
|
|
21
25
|
}: SelectFieldProps) {
|
|
22
26
|
return (
|
|
23
27
|
<FieldWrapper
|
|
24
28
|
source={source}
|
|
29
|
+
name={name}
|
|
25
30
|
label={label}
|
|
26
31
|
required={required}
|
|
27
32
|
rules={rules}
|
|
33
|
+
hideLabel={hideLabel}
|
|
28
34
|
>
|
|
29
35
|
{({ value, onChange, disabled }) => (
|
|
30
36
|
<Select
|
|
@@ -1,44 +1,46 @@
|
|
|
1
1
|
import { Input } from "antd";
|
|
2
2
|
import type { CSSProperties } from "react";
|
|
3
|
-
import type { BaseSourceProps, FieldRules
|
|
4
|
-
import {
|
|
3
|
+
import type { BaseSourceProps, FieldRules } from "../types";
|
|
4
|
+
import { FieldWrapper } from "./FieldWrapper";
|
|
5
5
|
|
|
6
|
-
export type TextFieldProps = BaseSourceProps &
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
export type TextFieldProps = BaseSourceProps & {
|
|
7
|
+
name?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
rules?: FieldRules;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
inputStyle?: CSSProperties;
|
|
12
|
+
hideLabel?: boolean;
|
|
13
|
+
};
|
|
13
14
|
|
|
14
15
|
export function TextField({
|
|
15
16
|
source,
|
|
17
|
+
name,
|
|
16
18
|
label,
|
|
17
19
|
required,
|
|
18
20
|
rules,
|
|
19
21
|
placeholder,
|
|
20
|
-
width: inlineWidth,
|
|
21
|
-
minWidth: inlineMinWidth,
|
|
22
22
|
inputStyle,
|
|
23
|
+
hideLabel,
|
|
23
24
|
}: TextFieldProps) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
return (
|
|
26
|
+
<FieldWrapper
|
|
27
|
+
source={source}
|
|
28
|
+
name={name}
|
|
29
|
+
label={label}
|
|
30
|
+
required={required}
|
|
31
|
+
rules={rules}
|
|
32
|
+
hideLabel={hideLabel}
|
|
33
|
+
>
|
|
34
|
+
{({ value, onChange, onBlur, disabled }) => (
|
|
35
|
+
<Input
|
|
36
|
+
value={value as string | undefined}
|
|
37
|
+
onChange={(e) => onChange(e.target.value)}
|
|
38
|
+
onBlur={onBlur}
|
|
39
|
+
placeholder={placeholder}
|
|
40
|
+
disabled={disabled}
|
|
41
|
+
style={inputStyle}
|
|
42
|
+
/>
|
|
43
|
+
)}
|
|
44
|
+
</FieldWrapper>
|
|
40
45
|
);
|
|
41
|
-
|
|
42
|
-
if (field.mode === "inline") return null;
|
|
43
|
-
return field.element;
|
|
44
46
|
}
|
package/src/crud/index.ts
CHANGED
|
@@ -10,10 +10,16 @@ export { ResourceFormModal } from "./ResourceFormModal";
|
|
|
10
10
|
export type { ResourceFormModalProps } from "./ResourceFormModal";
|
|
11
11
|
export {
|
|
12
12
|
InlineFormSet,
|
|
13
|
+
InlineFormSetStacked,
|
|
13
14
|
saveInlineRows,
|
|
14
15
|
loadInlineRows,
|
|
15
16
|
} from "./InlineFormSet";
|
|
16
|
-
export type {
|
|
17
|
+
export type {
|
|
18
|
+
InlineFormSetProps,
|
|
19
|
+
InlineFormSetStackedProps,
|
|
20
|
+
SaveInlineOptions,
|
|
21
|
+
InlineFormSetLayout,
|
|
22
|
+
} from "./InlineFormSet";
|
|
17
23
|
export { FormTabs, FormTab } from "./FormTabs";
|
|
18
24
|
export type { FormTabsProps, FormTabProps } from "./FormTabs";
|
|
19
25
|
export { FormSteps, FormStep } from "./FormSteps";
|
|
@@ -27,6 +33,8 @@ export { SelectField } from "./fields/SelectField";
|
|
|
27
33
|
export { PasswordField } from "./fields/PasswordField";
|
|
28
34
|
export { ReferenceField } from "./fields/ReferenceField";
|
|
29
35
|
export { ReferenceManyField } from "./fields/ReferenceManyField";
|
|
36
|
+
export { FieldWrapper } from "./fields/FieldWrapper";
|
|
37
|
+
export type { FieldWrapperProps } from "./fields/FieldWrapper";
|
|
30
38
|
|
|
31
39
|
export { TextColumn } from "./columns/TextColumn";
|
|
32
40
|
export { NumberColumn } from "./columns/NumberColumn";
|
|
@@ -47,6 +55,7 @@ export {
|
|
|
47
55
|
} from "./filters/ReferenceFilter";
|
|
48
56
|
|
|
49
57
|
export { useListQueryState } from "./utils/useListQueryState";
|
|
58
|
+
export { useAbortableEffect } from "./utils/useAbortableEffect";
|
|
50
59
|
export type {
|
|
51
60
|
ListQueryState,
|
|
52
61
|
ListQueryActions,
|
|
@@ -55,8 +64,12 @@ export { useChoices } from "./utils/useChoices";
|
|
|
55
64
|
export { getByPath } from "./utils/getByPath";
|
|
56
65
|
export { pickBySources } from "./utils/pickBySources";
|
|
57
66
|
export { inlineArrayName } from "./utils/inlineArrayName";
|
|
67
|
+
export { inlineFieldName } from "./utils/inlineFieldName";
|
|
58
68
|
export { setByPath } from "./utils/setByPath";
|
|
59
|
-
export {
|
|
69
|
+
export {
|
|
70
|
+
useSubmitField,
|
|
71
|
+
useSectionField,
|
|
72
|
+
} from "./context/SubmitFieldsContext";
|
|
60
73
|
|
|
61
74
|
export type {
|
|
62
75
|
BaseSourceProps,
|
|
@@ -66,6 +79,10 @@ export type {
|
|
|
66
79
|
DisplayProps,
|
|
67
80
|
EditMode,
|
|
68
81
|
FieldRules,
|
|
82
|
+
InlineCellContext,
|
|
83
|
+
InlineColumnDef,
|
|
84
|
+
InlineFormSetBaseProps,
|
|
85
|
+
InlineRowContext,
|
|
69
86
|
ResourceListBuiltInActions,
|
|
70
87
|
ResourceListBulkAction,
|
|
71
88
|
ResourceListBulkActionHelpers,
|
package/src/crud/types.ts
CHANGED
|
@@ -1,130 +1,132 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import type { ColumnsType } from "antd/es/table";
|
|
3
|
-
import type { DataProvider } from "../data/dataProviderTypes";
|
|
4
|
-
import type { RegisterOptions } from "react-hook-form";
|
|
5
|
-
|
|
6
|
-
export type BaseSourceProps = {
|
|
7
|
-
source: string;
|
|
8
|
-
label?: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type ChoiceOption = {
|
|
12
|
-
label: string;
|
|
13
|
-
value: unknown;
|
|
14
|
-
/** Full record when loaded from a reference resource (for dependent fields). */
|
|
15
|
-
record?: Record<string, unknown>;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type ChoicesContext = {
|
|
19
|
-
dataProvider: DataProvider;
|
|
20
|
-
search?: string;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export type ChoicesLoader =
|
|
24
|
-
| { resource: string; filter?: Record<string, unknown> }
|
|
25
|
-
| ChoiceOption[]
|
|
26
|
-
| ((ctx: ChoicesContext) => Promise<ChoiceOption[]>);
|
|
27
|
-
|
|
28
|
-
export type ReferenceProps = {
|
|
29
|
-
reference?: string;
|
|
30
|
-
choices?: ChoicesLoader;
|
|
31
|
-
optionLabel?: string | ((record: Record<string, unknown>) => string);
|
|
32
|
-
optionValue?: string;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export type DisplayProps = {
|
|
36
|
-
display?: string | ((record: Record<string, unknown>) => ReactNode);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export type FieldRules = RegisterOptions;
|
|
40
|
-
|
|
41
|
-
export type ColumnDefinition<T extends Record<string, unknown>> = {
|
|
42
|
-
key: string;
|
|
43
|
-
source: string;
|
|
44
|
-
label?: string;
|
|
45
|
-
sortable?: boolean;
|
|
46
|
-
buildColumn: () => ColumnsType<T>[number];
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export type FilterDefinition = {
|
|
50
|
-
key: string;
|
|
51
|
-
source: string;
|
|
52
|
-
label?: string;
|
|
53
|
-
render: (props: {
|
|
54
|
-
value: unknown;
|
|
55
|
-
onChange: (value: unknown) => void;
|
|
56
|
-
}) => ReactNode;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export type
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
label?: string;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
index
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ColumnsType } from "antd/es/table";
|
|
3
|
+
import type { DataProvider } from "../data/dataProviderTypes";
|
|
4
|
+
import type { RegisterOptions } from "react-hook-form";
|
|
5
|
+
|
|
6
|
+
export type BaseSourceProps = {
|
|
7
|
+
source: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type ChoiceOption = {
|
|
12
|
+
label: string;
|
|
13
|
+
value: unknown;
|
|
14
|
+
/** Full record when loaded from a reference resource (for dependent fields). */
|
|
15
|
+
record?: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ChoicesContext = {
|
|
19
|
+
dataProvider: DataProvider;
|
|
20
|
+
search?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type ChoicesLoader =
|
|
24
|
+
| { resource: string; filter?: Record<string, unknown> }
|
|
25
|
+
| ChoiceOption[]
|
|
26
|
+
| ((ctx: ChoicesContext) => Promise<ChoiceOption[]>);
|
|
27
|
+
|
|
28
|
+
export type ReferenceProps = {
|
|
29
|
+
reference?: string;
|
|
30
|
+
choices?: ChoicesLoader;
|
|
31
|
+
optionLabel?: string | ((record: Record<string, unknown>) => string);
|
|
32
|
+
optionValue?: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type DisplayProps = {
|
|
36
|
+
display?: string | ((record: Record<string, unknown>) => ReactNode);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type FieldRules = RegisterOptions;
|
|
40
|
+
|
|
41
|
+
export type ColumnDefinition<T extends Record<string, unknown>> = {
|
|
42
|
+
key: string;
|
|
43
|
+
source: string;
|
|
44
|
+
label?: string;
|
|
45
|
+
sortable?: boolean;
|
|
46
|
+
buildColumn: () => ColumnsType<T>[number];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type FilterDefinition = {
|
|
50
|
+
key: string;
|
|
51
|
+
source: string;
|
|
52
|
+
label?: string;
|
|
53
|
+
render: (props: {
|
|
54
|
+
value: unknown;
|
|
55
|
+
onChange: (value: unknown) => void;
|
|
56
|
+
}) => ReactNode;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type InlineFormSetBaseProps = {
|
|
60
|
+
resource: string;
|
|
61
|
+
foreignKey: string;
|
|
62
|
+
label?: string;
|
|
63
|
+
name?: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** Passed to each tabular inline column's `cell` renderer. */
|
|
67
|
+
export type InlineCellContext = {
|
|
68
|
+
/** Full RHF path, e.g. `__inline_invoice_lines.0.label`. */
|
|
69
|
+
name: string;
|
|
70
|
+
index: number;
|
|
71
|
+
arrayName: string;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type InlineColumnDef = {
|
|
75
|
+
source: string;
|
|
76
|
+
label?: string;
|
|
77
|
+
width?: number | string;
|
|
78
|
+
minWidth?: number | string;
|
|
79
|
+
cell: (ctx: InlineCellContext) => ReactNode;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Passed to `InlineFormSetStacked`'s `renderRow` for one related row. */
|
|
83
|
+
export type InlineRowContext = {
|
|
84
|
+
arrayName: string;
|
|
85
|
+
index: number;
|
|
86
|
+
/** RHF path helper — `name("label")` → `arrayName.index.label`. */
|
|
87
|
+
name: (source: string) => string;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type EditMode = "page" | "modal" | "both";
|
|
91
|
+
|
|
92
|
+
/** Toggle built-in row actions. Omitted keys default to `true` (still gated by permissions). */
|
|
93
|
+
export type ResourceListBuiltInActions = {
|
|
94
|
+
edit?: boolean;
|
|
95
|
+
quickEdit?: boolean;
|
|
96
|
+
delete?: boolean;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export type ResourceListRowActionsHelpers = {
|
|
100
|
+
reload: () => void;
|
|
101
|
+
openEditModal: (id: string | number) => void;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export type ResourceListBulkActionHelpers = {
|
|
105
|
+
reload: () => void;
|
|
106
|
+
clearSelection: () => void;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/** Bulk list action (Django admin–style). Runs on selected row ids. */
|
|
110
|
+
export type ResourceListBulkAction = {
|
|
111
|
+
key: string;
|
|
112
|
+
label: string;
|
|
113
|
+
/** Optional confirmation message. Return false to cancel. */
|
|
114
|
+
confirm?:
|
|
115
|
+
| string
|
|
116
|
+
| ((
|
|
117
|
+
selectedIds: (string | number)[],
|
|
118
|
+
helpers: ResourceListBulkActionHelpers,
|
|
119
|
+
) => string | false | Promise<string | false>);
|
|
120
|
+
execute: (
|
|
121
|
+
selectedIds: (string | number)[],
|
|
122
|
+
helpers: ResourceListBulkActionHelpers,
|
|
123
|
+
) => void | Promise<void>;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const LIST_QUERY_RESERVED = new Set([
|
|
127
|
+
"page",
|
|
128
|
+
"perPage",
|
|
129
|
+
"sort",
|
|
130
|
+
"create",
|
|
131
|
+
"edit",
|
|
132
|
+
]);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect, type DependencyList } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runs an async effect with an `AbortSignal` that aborts on cleanup.
|
|
5
|
+
* Use with `params.signal` on DataProvider reads and `isAbortError` in catch blocks.
|
|
6
|
+
*/
|
|
7
|
+
export function useAbortableEffect(
|
|
8
|
+
effect: (signal: AbortSignal) => void | Promise<void>,
|
|
9
|
+
deps: DependencyList,
|
|
10
|
+
): void {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
void effect(controller.signal);
|
|
14
|
+
return () => controller.abort();
|
|
15
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
16
|
+
}, deps);
|
|
17
|
+
}
|