Skip to content

Commit 6199648

Browse files
committed
Add Loadmore and search for some more auto inputs
1 parent 68c2a62 commit 6199648

File tree

7 files changed

+151
-22
lines changed

7 files changed

+151
-22
lines changed

packages/react/cypress/support/auto.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const ONLY_RUN_SUITES = {
2424
"AutoForm - Default model field values",
2525
"AutoForm - FindBy object parameters",
2626
"AutoForm - Global actions",
27-
// "AutoForm - HasManyThrough fields",
27+
"AutoForm - HasManyThrough fields",
2828
"AutoForm - Dynamic form input changes",
2929
"AutoForm - Dynamic form input changes - FindBy object parameters",
3030
"AutoForm - Dynamic form input changes - Global actions",

packages/react/src/auto/shadcn/inputs/ShadcnAutoFileInput.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ export const makeShadcnAutoFileInput = ({ Input, Label }: Pick<ShadcnElements, "
3838
if (message) actionHintParts.push(message);
3939
}
4040

41-
console.log(actionHintParts, "actionHintParts");
42-
4341
return (
4442
<div>
4543
<Label>

packages/react/src/auto/shadcn/inputs/ShadcnAutoInput.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { makeShadcnAutoStringInput } from "./ShadcnAutoStringInput.js";
1717
import { makeShadcnAutoRichTextInput } from "./ShadcnautoRichTextInput.js";
1818
import { makeShadcnAutoBelongsToInput } from "./relationships/ShadcnAutoBelongsToInput.js";
1919
import { makeShadcnAutoHasManyInput } from "./relationships/ShadcnAutoHasManyInput.js";
20+
import { makeShadcnAutoHasManyThroughInput } from "./relationships/ShadcnAutoHasManyThroughInput.js";
21+
import { makeShadcnAutoHasOneInput } from "./relationships/ShadcnAutoHasOneInput.js";
2022
export const makeShadcnAutoInput = (
2123
elements: Pick<
2224
ShadcnElements,
@@ -49,12 +51,14 @@ export const makeShadcnAutoInput = (
4951
const AutoBooleanInput = makeShadcnAutoBooleanInput(elements);
5052
const AutoBelongsToInput = makeShadcnAutoBelongsToInput(elements);
5153
const AutoHasManyInput = makeShadcnAutoHasManyInput(elements);
54+
const AutoHasOneInput = makeShadcnAutoHasOneInput(elements);
5255
const AutoRolesInput = makeShadcnAutoRolesInput(elements);
5356
const AutoEnumInput = makeShadcnAutoEnumInput(elements);
5457
const AutoDateTimePicker = makeShadcnAutoDateTimePicker(elements);
5558
const AutoJSONInput = makeShadcnAutoJSONInput(elements);
5659
const AutoRichTextInput = makeShadcnAutoRichTextInput(elements);
5760
const AutoFileInput = makeShadcnAutoFileInput(elements);
61+
const AutoHasManyThroughInput = makeShadcnAutoHasManyThroughInput(elements);
5862

5963
const AutoInput = autoInput(function AutoInput(props: { field: string; label?: string }) {
6064
const { metadata } = useFieldMetadata(props.field);
@@ -79,15 +83,13 @@ export const makeShadcnAutoInput = (
7983
case FieldType.RoleAssignments:
8084
return <AutoRolesInput {...props} />;
8185
case FieldType.HasOne:
82-
return null;
86+
return <AutoHasOneInput {...props} />;
8387
case FieldType.RichText:
8488
return <AutoRichTextInput {...props} />;
8589
case FieldType.File:
8690
return <AutoFileInput {...props} />;
8791
case FieldType.HasMany:
8892
return <AutoHasManyInput {...props} />;
89-
case FieldType.HasManyThrough:
90-
return null;
9193
case FieldType.EncryptedString:
9294
return <AutoEncryptedStringInput {...props} />;
9395
case FieldType.BelongsTo:
@@ -96,6 +98,8 @@ export const makeShadcnAutoInput = (
9698
return <AutoPasswordInput {...props} />;
9799
case FieldType.Boolean:
98100
return <AutoBooleanInput {...props} />;
101+
case FieldType.HasManyThrough:
102+
return <AutoHasManyThroughInput {...props} />;
99103
default:
100104
return <AutoStringInput {...props} />;
101105
}

packages/react/src/auto/shadcn/inputs/relationships/ShadcnAutoBelongsToInput.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { XIcon } from "lucide-react";
2-
import React from "react";
2+
import React, { useCallback } from "react";
3+
import { debounce } from "../../../../utils.js";
34
import { autoInput } from "../../../AutoInput.js";
45
import { useBelongsToInputController } from "../../../hooks/useBelongsToController.js";
5-
import { getRecordAsOption, useOptionLabelForField } from "../../../hooks/useRelatedModel.js";
6+
import { getRecordAsOption, optionRecordsToLoadCount, useOptionLabelForField } from "../../../hooks/useRelatedModel.js";
67
import type { AutoRelationshipInputProps } from "../../../interfaces/AutoRelationshipInputProps.js";
78
import type { ShadcnElements } from "../../elements.js";
89
import { makeShadcnAutoComboInput } from "../ShadcnAutoComboInput.js";
@@ -49,7 +50,6 @@ export const makeShadcnAutoBelongsToInput = ({
4950
});
5051

5152
function ShadcnAutoBelongsToInput(props: AutoRelationshipInputProps) {
52-
//TODO: Implement Load More
5353
const {
5454
fieldMetadata: { path, metadata },
5555
relatedModelOptions: { options, searchFilterOptions, pagination, search, relatedModel },
@@ -92,13 +92,26 @@ export const makeShadcnAutoBelongsToInput = ({
9292
: onSelectRecord(record); // make single selection
9393
};
9494

95+
const handleScrolledToBottom = useCallback(
96+
debounce(() => {
97+
if (pagination.hasNextPage && options.length >= optionRecordsToLoadCount) {
98+
pagination.loadNextPage();
99+
}
100+
}, 300),
101+
[pagination, options.length]
102+
);
103+
95104
return (
96105
<ShadcnComboInput
97106
{...props}
98-
options={options}
107+
options={searchFilterOptions}
99108
path={path}
100109
metadata={metadata}
110+
onChange={search.set}
111+
defaultValue={search.value}
101112
selectedRecordTag={selectedRecordTag}
113+
onScrolledToBottom={handleScrolledToBottom}
114+
willLoadMoreOptions={pagination.hasNextPage && options.length >= optionRecordsToLoadCount}
102115
onSelect={onSelect}
103116
isLoading={isLoading}
104117
errorMessage={errorMessage}

packages/react/src/auto/shadcn/inputs/relationships/ShadcnAutoHasManyInput.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,6 @@ export const makeShadcnAutoHasManyInput = ({
7070
return selectedRecords.map((record) => record.id).filter((id) => !!id) as string[];
7171
}, [selectedRecords]);
7272

73-
const debouncedSearch = useCallback(
74-
debounce((value: string) => {
75-
search.set(value);
76-
}, 400),
77-
[search]
78-
);
79-
8073
const handleScrolledToBottom = useCallback(
8174
debounce(() => {
8275
if (pagination.hasNextPage && options.length >= optionRecordsToLoadCount) {
@@ -92,7 +85,7 @@ export const makeShadcnAutoHasManyInput = ({
9285
options={searchFilterOptions}
9386
path={path}
9487
metadata={metadata}
95-
onChange={debouncedSearch}
88+
onChange={search.set}
9689
selectedRecordTag={
9790
<SelectedRecordTags selectedRecords={selectedRecords} optionLabel={optionLabel} onRemoveRecord={onRemoveRecord} />
9891
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React, { useCallback, useMemo } from "react";
2+
import { debounce } from "../../../../utils.js";
3+
import { autoInput } from "../../../AutoInput.js";
4+
import { useHasManyThroughInputController } from "../../../hooks/useHasManyThroughController.js";
5+
import { optionRecordsToLoadCount, useOptionLabelForField } from "../../../hooks/useRelatedModel.js";
6+
import type { AutoRelationshipInputProps } from "../../../interfaces/AutoRelationshipInputProps.js";
7+
import type { ShadcnElements } from "../../elements.js";
8+
import { makeShadcnAutoComboInput } from "../ShadcnAutoComboInput.js";
9+
import { makeSelectedRecordTags } from "./SelectedRelatedRecordTags.js";
10+
11+
export const makeShadcnAutoHasManyThroughInput = ({
12+
Badge,
13+
Button,
14+
Command,
15+
CommandItem,
16+
CommandInput,
17+
Label,
18+
CommandList,
19+
CommandEmpty,
20+
CommandLoading,
21+
CommandGroup,
22+
Checkbox,
23+
ScrollArea,
24+
}: Pick<
25+
ShadcnElements,
26+
| "Badge"
27+
| "Button"
28+
| "Command"
29+
| "CommandItem"
30+
| "CommandList"
31+
| "CommandLoading"
32+
| "CommandEmpty"
33+
| "CommandGroup"
34+
| "CommandInput"
35+
| "Label"
36+
| "Checkbox"
37+
| "ScrollArea"
38+
>) => {
39+
const { SelectedRecordTags } = makeSelectedRecordTags({ Badge, Button });
40+
41+
const ShadcnComboInput = makeShadcnAutoComboInput({
42+
Command,
43+
CommandInput,
44+
Label,
45+
CommandItem,
46+
CommandList,
47+
CommandLoading,
48+
CommandEmpty,
49+
CommandGroup,
50+
Checkbox,
51+
ScrollArea,
52+
});
53+
54+
function ShadcnAutoHasManyThroughInput(props: AutoRelationshipInputProps) {
55+
const { field } = props;
56+
const {
57+
fieldMetadata: { path, metadata },
58+
relatedModelOptions: { options, searchFilterOptions, search, pagination, relatedModel },
59+
selectedRecords,
60+
errorMessage,
61+
isLoading,
62+
onRemoveRecord,
63+
onSelectRecord,
64+
} = useHasManyThroughInputController(props);
65+
66+
const optionLabel = useOptionLabelForField(field, props.optionLabel);
67+
68+
const selectedRecordIds = useMemo(() => {
69+
return selectedRecords.map((record) => record.id).filter((id) => !!id) as string[];
70+
}, [selectedRecords]);
71+
72+
const handleScrolledToBottom = useCallback(
73+
debounce(() => {
74+
if (pagination.hasNextPage && options.length >= optionRecordsToLoadCount) {
75+
pagination.loadNextPage();
76+
}
77+
}, 300),
78+
[pagination, options.length]
79+
);
80+
81+
return (
82+
<ShadcnComboInput
83+
{...props}
84+
options={searchFilterOptions}
85+
path={path}
86+
metadata={metadata}
87+
onChange={search.set}
88+
defaultValue={search.value}
89+
selectedRecordTag={
90+
<SelectedRecordTags selectedRecords={selectedRecords} optionLabel={optionLabel} onRemoveRecord={onRemoveRecord} />
91+
}
92+
onSelect={onSelectRecord}
93+
checkSelected={(id) => {
94+
return selectedRecordIds.includes(id);
95+
}}
96+
allowMultiple
97+
onScrolledToBottom={handleScrolledToBottom}
98+
willLoadMoreOptions={pagination.hasNextPage && options.length >= optionRecordsToLoadCount}
99+
isLoading={isLoading}
100+
errorMessage={errorMessage}
101+
records={relatedModel.records}
102+
/>
103+
);
104+
}
105+
106+
return autoInput(ShadcnAutoHasManyThroughInput);
107+
};

packages/react/src/auto/shadcn/inputs/relationships/ShadcnAutoHasOneInput.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { XIcon } from "lucide-react";
2-
import React from "react";
2+
import React, { useCallback } from "react";
3+
import { debounce } from "../../../../utils.js";
34
import { autoInput } from "../../../AutoInput.js";
45
import { useHasOneInputController } from "../../../hooks/useHasOneController.js";
5-
import { getRecordAsOption, useOptionLabelForField } from "../../../hooks/useRelatedModel.js";
6+
import { getRecordAsOption, optionRecordsToLoadCount, useOptionLabelForField } from "../../../hooks/useRelatedModel.js";
67
import type { AutoRelationshipInputProps } from "../../../interfaces/AutoRelationshipInputProps.js";
78
import type { ShadcnElements } from "../../elements.js";
89
import { makeShadcnAutoComboInput } from "../ShadcnAutoComboInput.js";
@@ -66,19 +67,32 @@ export const makeShadcnAutoHasOneInput = ({
6667

6768
const selectedRecordTag = selectedOption ? (
6869
<Badge variant={"outline"} key={`selectedRecordTag_${selectedOption.id}`}>
69-
<p id={`${selectedOption.id}_${selectedOption.label}`}>{selectedOption.label}</p>
70+
<p id={`${selectedOption.id}_${selectedOption.label}`}>{selectedOption.label ?? `id: ${selectedOption.id}`}</p>
7071
<Button aria-label={`Remove`} onClick={() => selectedRecord && onRemoveRecord(selectedRecord)} variant="ghost" size="icon">
7172
<XIcon />
7273
</Button>
7374
</Badge>
7475
) : null;
7576

77+
const handleScrolledToBottom = useCallback(
78+
debounce(() => {
79+
if (pagination.hasNextPage && options.length >= optionRecordsToLoadCount) {
80+
pagination.loadNextPage();
81+
}
82+
}, 300),
83+
[pagination, options.length]
84+
);
85+
7686
return (
7787
<ShadcnComboInput
7888
{...props}
79-
options={options}
89+
options={searchFilterOptions}
8090
path={path}
8191
metadata={metadata}
92+
onChange={search.set}
93+
defaultValue={search.value}
94+
onScrolledToBottom={handleScrolledToBottom}
95+
willLoadMoreOptions={pagination.hasNextPage && options.length >= optionRecordsToLoadCount}
8296
selectedRecordTag={selectedRecordTag}
8397
onSelect={onSelectRecord}
8498
checkSelected={(id) => selectedRecord?.id === id}

0 commit comments

Comments
 (0)