Skip to content

Add drag-and-drop reordering for schema form arrays#29

Open
tomerqodo wants to merge 3 commits into
coderabbit_full_base_add_drag-and-drop_reordering_for_schema_form_arrays_pr3from
coderabbit_full_head_add_drag-and-drop_reordering_for_schema_form_arrays_pr3
Open

Add drag-and-drop reordering for schema form arrays#29
tomerqodo wants to merge 3 commits into
coderabbit_full_base_add_drag-and-drop_reordering_for_schema_form_arrays_pr3from
coderabbit_full_head_add_drag-and-drop_reordering_for_schema_form_arrays_pr3

Conversation

@tomerqodo

@tomerqodo tomerqodo commented Jan 29, 2026

Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#3

Summary by CodeRabbit

  • New Features

    • Added drag-and-drop functionality for reordering array items in schema forms.
    • Visual drag handles appear for items that can be reordered.
    • Supports keyboard and pointer interactions for accessible reordering.
  • Tests

    • Added snapshot tests covering array form rendering and reordering scenarios.

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

devin-ai-integration Bot and others added 3 commits January 25, 2026 12:09
Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
- Add snapshot tests for arrays with drag handles visible
- Add snapshot tests for prefixItems without drag handles
- Add behavioral tests for move up/down menu options
- Add test verifying prefix items cannot be moved

Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
@coderabbitai

coderabbitai Bot commented Jan 29, 2026

Copy link
Copy Markdown

Walkthrough

This pull request adds drag-and-drop reordering functionality to the schema form component. Three @dnd-kit dependencies are added to support sortable lists. The array form components are modified to integrate drag-and-drop capabilities, including itemKey props and drag handles. New snapshot tests verify drag handle rendering with various configurations.

Changes

Cohort / File(s) Summary
Dependencies
ui-v2/package.json
Added three @dnd-kit packages: @dnd-kit/core, @dnd-kit/sortable, and @dnd-kit/utilities to enable drag-and-drop functionality.
Array Item Component
ui-v2/src/components/schemas/schema-form-input-array-item.tsx
Integrated useSortable hook with itemKey prop; added dynamic styling based on drag state (transform, transition, opacity); replaced static layout with three-column grid to accommodate draggable handle; renders GripVertical drag handle when canMove is true.
Array List Component
ui-v2/src/components/schemas/schema-form-input-array-list.tsx
Integrated DndContext and SortableContext with keyboard/pointer sensors; implemented handleDragEnd to reorder items and propagate changes via onValuesChange; computes sortableKeys from localKeyedValues; updated SchemaFormInputArrayItem invocations to pass itemKey prop.
Snapshot Tests
ui-v2/src/components/schemas/schema-form.snapshot.test.tsx
Added new snapshot test cases covering array property rendering, pre-populated values with drag handles, prefixItems behavior (excluding prefix items from drag handles), and enum items within arrays.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as Schema Form<br/>Array List
    participant DnD as DndContext<br/>SortableContext
    participant Item as Array Item<br/>Component
    participant State as Local State<br/>(localKeyedValues)

    User->>Item: Grabs drag handle (GripVertical)
    Item->>DnD: Drag initiated (useSortable)
    Item->>Item: Apply drag styling<br/>(transform, opacity)
    User->>DnD: Drops on new position
    DnD->>UI: handleDragEnd triggered<br/>(active, over)
    UI->>State: Swap items in array<br/>(localKeyedValues)
    State->>UI: State updated
    UI->>UI: onValuesChange called<br/>(propagate changes)
    UI->>Item: Re-render with new order
    Item->>User: List reordered visually
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop and drag, a smooth ballet,
Items dance and swap their way,
Grip the handle, watch it glide,
Reorder lists with rabbit pride! 🎪✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is minimal and does not follow the repository's template structure, missing key sections like overview, issue references, test coverage details, and checklist items. Provide a comprehensive description following the template: include an overview of changes, reference related issues, confirm test coverage, and complete the checklist items.
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 pull request title clearly and accurately summarizes the main change: adding drag-and-drop reordering functionality for schema form arrays.

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

✨ Finishing touches
  • 📝 Generate docstrings

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: 1

🤖 Fix all issues with AI agents
In `@ui-v2/src/components/schemas/schema-form-input-array-list.tsx`:
- Around line 130-145: handleDragEnd is calling moveItem with arguments reversed
which causes items to be moved in the wrong direction; locate the handleDragEnd
function handling DragEndEvent and when both oldIndex and newIndex are valid,
call moveItem with the source index first and destination second (i.e., pass
oldIndex then newIndex) so the signature moveItem(from: number, to: number) is
respected; ensure you reference localKeyedValues, active.id and over.id to
compute oldIndex/newIndex and update the single call to moveItem accordingly.
🧹 Nitpick comments (3)
ui-v2/src/components/schemas/schema-form-input-array-list.tsx (2)

45-48: Remove unused prefixItemsCount variable.

This variable is computed but never used in the component.

♻️ Proposed fix
-	const prefixItemsCount = isArray(property.prefixItems)
-		? property.prefixItems.length
-		: 0;
-

147-148: Misleading comment: sortableKeys includes all items, not just non-prefix items.

The comment states "non-prefix items" but sortableKeys contains keys for all items. The drag restriction for prefix items is correctly handled by the disabled prop in useSortable within SchemaFormInputArrayItem, so functionality is correct—but the comment should be updated or removed to avoid confusion.

♻️ Proposed fix
-	// Get the keys of items that can be dragged (non-prefix items)
+	// Keys for SortableContext; prefix items have drag disabled via useSortable
 	const sortableKeys = localKeyedValues.map((item) => item.key);
ui-v2/src/components/schemas/schema-form-input-array-item.tsx (1)

83-92: Consider adding a visible focus indicator for keyboard accessibility.

The focus:outline-none class removes the focus indicator, which can make keyboard navigation difficult for users relying on visual focus cues. Consider adding a focus-visible style instead.

♻️ Proposed fix
 			<button
 				type="button"
-				className="flex items-center justify-center cursor-grab text-muted-foreground hover:text-foreground focus:outline-none"
+				className="flex items-center justify-center cursor-grab text-muted-foreground hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
 				aria-label="Drag to reorder"
 				{...attributes}
 				{...listeners}
 			>
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 025c503 and b51b02c.

⛔ Files ignored due to path filters (2)
  • ui-v2/package-lock.json is excluded by !**/package-lock.json
  • ui-v2/src/components/schemas/__snapshots__/schema-form.snapshot.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • ui-v2/package.json
  • ui-v2/src/components/schemas/schema-form-input-array-item.tsx
  • ui-v2/src/components/schemas/schema-form-input-array-list.tsx
  • ui-v2/src/components/schemas/schema-form.snapshot.test.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
ui-v2/src/components/schemas/schema-form.snapshot.test.tsx (1)
ui-v2/src/components/schemas/stories/utilities.tsx (1)
  • TestSchemaForm (8-50)
ui-v2/src/components/schemas/schema-form-input-array-list.tsx (2)
ui-v2/src/components/schemas/utilities/guards.ts (1)
  • isArray (21-23)
ui-v2/src/components/schemas/schema-form-input-array-item.tsx (1)
  • SchemaFormInputArrayItem (29-121)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Test (4)
  • GitHub Check: Test (3)
  • GitHub Check: Test (1)
  • GitHub Check: Test (2)
  • GitHub Check: Pre-commit checks
  • GitHub Check: E2E Tests
🔇 Additional comments (6)
ui-v2/src/components/schemas/schema-form.snapshot.test.tsx (1)

488-565: LGTM! Well-structured snapshot tests for array drag-and-drop functionality.

The tests appropriately cover key scenarios:

  • Base array rendering
  • Arrays with values (verifying drag handles appear)
  • Arrays with prefixItems (verifying drag handles don't appear on prefix items)
  • Arrays with enum items

Good adherence to the file's note about adding new tests at the end to avoid order-dependent useId issues.

ui-v2/src/components/schemas/schema-form-input-array-list.tsx (2)

49-54: LGTM! Sensor configuration follows @dnd-kit best practices.

Proper setup of both PointerSensor and KeyboardSensor with sortableKeyboardCoordinates for accessibility.


156-182: LGTM! DndContext and SortableContext integration is correct.

The drag-and-drop context properly wraps the sortable items, and the itemKey prop is correctly passed to enable sortable identification.

ui-v2/src/components/schemas/schema-form-input-array-item.tsx (2)

45-58: LGTM! Correct useSortable integration with proper drag state styling.

The hook is properly configured with disabled: !canMove for prefix items, and the style computation correctly handles transform, transition, and opacity feedback during drag operations.


77-95: LGTM! Well-structured drag handle with appropriate accessibility attributes.

The implementation correctly:

  • Uses setNodeRef for sortable DOM binding
  • Applies dynamic styles for drag feedback
  • Renders a placeholder spacer when dragging is disabled (prefix items)
  • Includes aria-label on the drag handle
ui-v2/package.json (1)

32-34: No action needed. The @dnd-kit packages are properly versioned and compatible.

The specified versions are designed to work together: @dnd-kit/sortable@10.0.0 requires @dnd-kit/core@^6.3.0, and the package.json correctly specifies @dnd-kit/core@^6.3.1. Similarly, @dnd-kit/utilities@3.2.2 is compatible with core v6. All three packages meet their peer dependencies and work with React 19.2.3.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +130 to +145
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;

if (over && active.id !== over.id) {
const oldIndex = localKeyedValues.findIndex(
(item) => item.key === active.id,
);
const newIndex = localKeyedValues.findIndex(
(item) => item.key === over.id,
);

if (oldIndex !== -1 && newIndex !== -1) {
moveItem(newIndex, oldIndex);
}
}
}

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 | 🔴 Critical

Critical: moveItem arguments are swapped, causing incorrect reorder direction.

The moveItem function signature is moveItem(from: number, to: number) (Line 117), but handleDragEnd passes arguments in reverse order: moveItem(newIndex, oldIndex). This will move the item in the wrong direction—moving FROM the drop position TO the original position instead of the intended behavior.

🐛 Proposed fix
 		if (oldIndex !== -1 && newIndex !== -1) {
-			moveItem(newIndex, oldIndex);
+			moveItem(oldIndex, newIndex);
 		}
📝 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
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (over && active.id !== over.id) {
const oldIndex = localKeyedValues.findIndex(
(item) => item.key === active.id,
);
const newIndex = localKeyedValues.findIndex(
(item) => item.key === over.id,
);
if (oldIndex !== -1 && newIndex !== -1) {
moveItem(newIndex, oldIndex);
}
}
}
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (over && active.id !== over.id) {
const oldIndex = localKeyedValues.findIndex(
(item) => item.key === active.id,
);
const newIndex = localKeyedValues.findIndex(
(item) => item.key === over.id,
);
if (oldIndex !== -1 && newIndex !== -1) {
moveItem(oldIndex, newIndex);
}
}
}
🤖 Prompt for AI Agents
In `@ui-v2/src/components/schemas/schema-form-input-array-list.tsx` around lines
130 - 145, handleDragEnd is calling moveItem with arguments reversed which
causes items to be moved in the wrong direction; locate the handleDragEnd
function handling DragEndEvent and when both oldIndex and newIndex are valid,
call moveItem with the source index first and destination second (i.e., pass
oldIndex then newIndex) so the signature moveItem(from: number, to: number) is
respected; ensure you reference localKeyedValues, active.id and over.id to
compute oldIndex/newIndex and update the single call to moveItem accordingly.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant