Skip to content

Add block document reference support to schema form#4

Open
tomerqodo wants to merge 2 commits into
coderabbit_full_base_add_block_document_reference_support_to_schema_form_pr4from
coderabbit_full_head_add_block_document_reference_support_to_schema_form_pr4
Open

Add block document reference support to schema form#4
tomerqodo wants to merge 2 commits into
coderabbit_full_base_add_block_document_reference_support_to_schema_form_pr4from
coderabbit_full_head_add_block_document_reference_support_to_schema_form_pr4

Conversation

@tomerqodo

@tomerqodo tomerqodo commented Jan 30, 2026

Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#4

Summary by CodeRabbit

  • New Features
    • Added a searchable combobox interface for selecting block documents with optional create-new button support.
    • Added a dialog interface for creating new block documents with automatic form field generation and validation.
    • Integrated block document selection and creation capabilities into schema forms for improved user workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces two new React components—BlockDocumentCombobox for selecting block documents and BlockDocumentCreateDialog for creating them—along with SchemaFormInputBlockDocument to integrate both into form schema contexts. Comprehensive tests and Storybook stories are included for each component. The changes integrate into the schema form system, enabling dynamic block document management.

Changes

Cohort / File(s) Summary
BlockDocumentCombobox
ui-v2/src/components/blocks/block-document-combobox/block-document-combobox.tsx, .../.../block-document-combobox.test.tsx, .../.../block-document-combobox.stories.tsx, .../.../index.ts
New searchable async-loaded combobox component for selecting block documents. Fetches and filters documents by name with optional create-new action. Includes comprehensive test coverage (selection, display, placeholder, create behavior) and Storybook stories (default, with create-new, empty states).
BlockDocumentCreateDialog
ui-v2/src/components/blocks/block-document-create-dialog/block-document-create-dialog.tsx, .../.../block-document-create-dialog.test.tsx, .../.../block-document-create-dialog.stories.tsx, .../.../index.ts
New dialog component for creating block documents with dynamic schema-driven fields. Fetches block type and schemas, renders form with validation, and handles submission with toast feedback. Includes tests (rendering, cancel, field visibility) and Storybook story configuration with API mocks.
Schema Form Block Document Input
ui-v2/src/components/schemas/schema-form-input-block-document.tsx, .../.../schema-form-input-block-document.test.tsx
New form input component combining combobox and create dialog for selecting or creating block document references. Manages dialog state and value updates via \$ref format. Tests validate rendering, value changes on selection, and display of selected document names.
Schema Form Integration
ui-v2/src/components/schemas/schema-form-input.tsx
Updated to support blockTypeSlug property detection, now renders SchemaFormInputBlockDocument instead of throwing "not implemented".
Storybook Updates
ui-v2/src/components/schemas/stories/properties.stories.tsx
Added reactQueryDecorator and two new stories (blockTypeSlugEmpty, blockTypeSlugWithValue) demonstrating schema form block document input with MSW-mocked API responses.

Sequence Diagrams

sequenceDiagram
    actor User
    participant SchemaForm as SchemaFormInputBlockDocument
    participant Combobox as BlockDocumentCombobox
    participant API as API Server
    
    User->>SchemaForm: Interact with block input
    SchemaForm->>Combobox: Render with blockTypeSlug
    Combobox->>API: Fetch block documents (query)
    API-->>Combobox: Return filtered results
    Combobox-->>SchemaForm: Display dropdown options
    User->>Combobox: Select block document
    Combobox->>SchemaForm: Call onSelect(blockId)
    SchemaForm->>SchemaForm: Update value { $ref: blockId }
    SchemaForm-->>User: Display selected block name
Loading
sequenceDiagram
    actor User
    participant SchemaForm as SchemaFormInputBlockDocument
    participant Dialog as BlockDocumentCreateDialog
    participant API as API Server
    
    User->>SchemaForm: Click create new button
    SchemaForm->>Dialog: Open dialog (createDialogOpen=true)
    Dialog->>API: Fetch block type by slug
    Dialog->>API: Fetch block schemas for type
    API-->>Dialog: Return schemas
    Dialog-->>User: Display create form
    User->>Dialog: Fill form & submit
    Dialog->>API: POST create block document
    API-->>Dialog: Return new block document
    Dialog->>SchemaForm: Call onCreated(blockId)
    SchemaForm->>SchemaForm: Update value { $ref: blockId }
    SchemaForm->>Dialog: Close dialog
    SchemaForm-->>User: Display newly created block
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A combobox hops and a dialog springs,
New blocks are born on schema's wings!
Create and select with ease so keen,
The finest forms we've ever seen! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is minimal and lacks required details from the template, such as an overview of changes, issue references, test coverage confirmation, or docstring additions. Add a meaningful overview of the proposed changes, reference any related issues, confirm unit test coverage, and document any new functions or classes with helpful docstrings.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding block document reference support to the schema form component.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch coderabbit_full_head_add_block_document_reference_support_to_schema_form_pr4

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@ui-v2/src/components/blocks/block-document-combobox/block-document-combobox.tsx`:
- Around line 73-77: selectedBlockDocument is currently derived from
filteredData so when the user searches and the selected document is excluded it
shows "Select a block..."; change the lookup to use the unfiltered data array
instead of filteredData by finding the item in data by selectedBlockDocumentId
(keep the same memoization hook/identifier selectedBlockDocument and dependency
on data and selectedBlockDocumentId) so the selected item remains shown even
when it's not matched by the current search filter.

In
`@ui-v2/src/components/blocks/block-document-create-dialog/block-document-create-dialog.tsx`:
- Around line 151-173: The onSave flow is passing user values to validateForm
and then immediately checking the async-updated errors array; change
validateForm call to pass the actual schema definition (blockSchemaFields)
instead of values, and update validateForm usage to return a synchronous
validation result (e.g., { valid, errors }) or await that result before
proceeding; then check the returned valid flag or returned errors (instead of
reading the component-level errors immediately) before calling
createBlockDocument. Update references in useSchemaForm/validateForm, and adjust
callers (onSave in block-document-create-dialog's onSave, and the similar
handlers in block-document-create-page and block-document-edit-page) to rely on
the returned validation outcome rather than the asynchronously setErrors state.
🧹 Nitpick comments (3)
ui-v2/src/components/schemas/stories/properties.stories.tsx (1)

645-653: Consider extracting duplicated MSW handlers.

The MSW handler for /block_documents/filter is identical in both blockTypeSlugEmpty and blockTypeSlugWithValue stories. You could define it once and reuse it.

♻️ Optional: Extract common handler
+const blockDocumentsFilterHandler = http.post(
+	buildApiUrl("/block_documents/filter"),
+	() => HttpResponse.json(MOCK_BLOCK_DOCUMENTS),
+);
+
 export const blockTypeSlugEmpty: Story = {
 	// ...
 	parameters: {
 		msw: {
-			handlers: [
-				http.post(buildApiUrl("/block_documents/filter"), () => {
-					return HttpResponse.json(MOCK_BLOCK_DOCUMENTS);
-				}),
-			],
+			handlers: [blockDocumentsFilterHandler],
 		},
 	},
 };

Also applies to: 675-683

ui-v2/src/components/blocks/block-document-combobox/block-document-combobox.tsx (2)

30-30: Provide a fallback for the Suspense boundary.

The <Suspense> wrapper has no fallback, which means nothing is rendered while the query is loading. Consider adding a loading indicator or skeleton.

♻️ Add a fallback
-		<Suspense>
+		<Suspense fallback={<ComboboxTrigger disabled>Loading...</ComboboxTrigger>}>

50-71: Redundant client-side filtering.

The query already includes a server-side name filter (line 61: name: { like_: deferredSearch }), but filteredData (lines 67-71) applies the same filter client-side. This is unnecessary and could be removed.

♻️ Remove redundant filtering
-  const filteredData = useMemo(() => {
-    return data.filter((blockDocument) =>
-      blockDocument.name?.toLowerCase().includes(deferredSearch.toLowerCase()),
-    );
-  }, [data, deferredSearch]);
+  const filteredData = data;

Or simply use data directly in the component.

Comment on lines +73 to +77
const selectedBlockDocument = useMemo(() => {
return filteredData.find(
(blockDocument) => blockDocument.id === selectedBlockDocumentId,
);
}, [filteredData, selectedBlockDocumentId]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Selected document may not be found when searching.

selectedBlockDocument is derived from filteredData, which is filtered by the search term. If the user searches for something that doesn't match the currently selected document's name, the selected document won't be found, and the trigger will show "Select a block..." instead of the actual selection.

Use the unfiltered data array to find the selected document:

🐛 Proposed fix
 	const selectedBlockDocument = useMemo(() => {
-		return filteredData.find(
+		return data.find(
 			(blockDocument) => blockDocument.id === selectedBlockDocumentId,
 		);
-	}, [filteredData, selectedBlockDocumentId]);
+	}, [data, selectedBlockDocumentId]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const selectedBlockDocument = useMemo(() => {
return filteredData.find(
(blockDocument) => blockDocument.id === selectedBlockDocumentId,
);
}, [filteredData, selectedBlockDocumentId]);
const selectedBlockDocument = useMemo(() => {
return data.find(
(blockDocument) => blockDocument.id === selectedBlockDocumentId,
);
}, [data, selectedBlockDocumentId]);
🤖 Prompt for AI Agents
In
`@ui-v2/src/components/blocks/block-document-combobox/block-document-combobox.tsx`
around lines 73 - 77, selectedBlockDocument is currently derived from
filteredData so when the user searches and the selected document is excluded it
shows "Select a block..."; change the lookup to use the unfiltered data array
instead of filteredData by finding the item in data by selectedBlockDocumentId
(keep the same memoization hook/identifier selectedBlockDocument and dependency
on data and selectedBlockDocumentId) so the selected item remains shown even
when it's not matched by the current search filter.

Comment on lines +151 to +173
const { values, setValues, errors, validateForm } = useSchemaForm();
const { createBlockDocument, isPending } = useCreateBlockDocument();

const form = useForm({
resolver: zodResolver(BlockNameFormSchema),
defaultValues: DEFAULT_VALUES,
});

const onSave = async (zodFormValues: BlockNameFormSchema) => {
try {
await validateForm({ schema: values });
if (errors.length > 0) {
return;
}
createBlockDocument(
{
block_schema_id: blockSchemaId,
block_type_id: blockTypeId,
is_anonymous: false,
data: values,
name: zodFormValues.blockName,
},
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for useSchemaForm hook definition
echo "=== Searching for useSchemaForm hook definition ==="
rg -n "useSchemaForm" --type=ts --type=tsx -A 3 | head -50

echo -e "\n=== Searching for validateForm definition/usage ==="
rg -n "validateForm" --type=ts --type=tsx -B 2 -A 2 | head -100

echo -e "\n=== Checking the hook implementation file ==="
fd "useSchemaForm" --type=ts --type=tsx

Repository: agentic-review-benchmarks/prefect-combined-coderabbit

Length of output: 491


🏁 Script executed:

#!/bin/bash
# Search for useSchemaForm hook definition without type flags
echo "=== Searching for useSchemaForm hook ==="
rg -n "useSchemaForm" -A 10 | head -80

echo -e "\n=== Searching for validateForm function ==="
rg -n "validateForm" -B 2 -A 3 | head -100

echo -e "\n=== Listing TypeScript/TSX files in components ==="
fd -e ts -e tsx | grep -i schema | head -20

echo -e "\n=== Reading the specific file mentioned in the review ==="
head -200 "ui-v2/src/components/blocks/block-document-create-dialog/block-document-create-dialog.tsx" | tail -100

Repository: agentic-review-benchmarks/prefect-combined-coderabbit

Length of output: 21450


🏁 Script executed:

#!/bin/bash
# Read the full useSchemaForm.ts implementation
echo "=== Full useSchemaForm.ts implementation ==="
cat "ui-v2/src/components/schemas/hooks/useSchemaForm.ts"

Repository: agentic-review-benchmarks/prefect-combined-coderabbit

Length of output: 1676


🏁 Script executed:

#!/bin/bash
# Find and read the validateSchemaValues function
echo "=== Searching for validateSchemaValues ==="
fd -e ts -e tsx | xargs grep -l "validateSchemaValues" | head -10

echo -e "\n=== Reading validate utility ==="
cat "ui-v2/src/components/schemas/utilities/validate.ts"

Repository: agentic-review-benchmarks/prefect-combined-coderabbit

Length of output: 688


🏁 Script executed:

#!/bin/bash
# Verify blockSchemaFields usage in the file to confirm it's never passed to validation
echo "=== Check blockSchemaFields usage in block-document-create-dialog ==="
grep -n "blockSchemaFields" "ui-v2/src/components/blocks/block-document-create-dialog/block-document-create-dialog.tsx"

echo -e "\n=== Check if similar issue exists in other files ==="
grep -n "await validateForm" ui-v2/src/components/blocks/block-document-*.tsx

Repository: agentic-review-benchmarks/prefect-combined-coderabbit

Length of output: 504


🏁 Script executed:

#!/bin/bash
# Check the full context of SchemaForm rendering and validation flow
echo "=== Check SchemaForm usage in block-document-create-dialog ==="
sed -n '200,250p' "ui-v2/src/components/blocks/block-document-create-dialog/block-document-create-dialog.tsx"

echo -e "\n=== Check how other components use validateForm correctly ==="
grep -B 2 -A 5 "await validateForm" ui-v2/src/components/blocks/block-document-create-page/block-document-create-page.tsx | head -20

Repository: agentic-review-benchmarks/prefect-combined-coderabbit

Length of output: 1186


Pass blockSchemaFields to validateForm and handle the asynchronous error state correctly.

Line 161 passes values (user data) as the schema parameter to validateForm, but it should pass blockSchemaFields (the actual schema definition). Additionally, errors is updated asynchronously via setErrors(), so checking errors.length > 0 immediately after await validateForm will not reflect the validation result. Either await the state update separately or refactor to return the validation status from validateForm for synchronous checking.

This same issue appears in block-document-create-page.tsx (line 62) and block-document-edit-page.tsx (line 39).

🤖 Prompt for AI Agents
In
`@ui-v2/src/components/blocks/block-document-create-dialog/block-document-create-dialog.tsx`
around lines 151 - 173, The onSave flow is passing user values to validateForm
and then immediately checking the async-updated errors array; change
validateForm call to pass the actual schema definition (blockSchemaFields)
instead of values, and update validateForm usage to return a synchronous
validation result (e.g., { valid, errors }) or await that result before
proceeding; then check the returned valid flag or returned errors (instead of
reading the component-level errors immediately) before calling
createBlockDocument. Update references in useSchemaForm/validateForm, and adjust
callers (onSave in block-document-create-dialog's onSave, and the similar
handlers in block-document-create-page and block-document-edit-page) to rely on
the returned validation outcome rather than the asynchronously setErrors state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant