-
Notifications
You must be signed in to change notification settings - Fork 151
refactor: enhance hosting form and layout functionality #75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Updated allowedEmails validation to use z.email() for better email format checking. - Simplified exampleQuestions and exampleSearchQueries handling in useHostingForm. - Added unsaved changes warning on page unload in HostingLayout. - Improved rendering logic in HostingPreview for better display of example questions. - Adjusted tab structure in HostingTabs and GeneralTab for improved navigation and user experience. - Enhanced SortableList component with button repositioning for better accessibility.
WalkthroughThis PR updates the hosting configuration UI components to add unsaved changes warnings via beforeunload handlers, reorder tab navigation, introduce a Custom domain button that programmatically switches tabs, modify form validation schema (relaxing empty string constraints), and enhance the sortable list with auto-append behavior. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.tsapps/web/src/components/sortable-list.tsx
🧰 Additional context used
📓 Path-based instructions (4)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/nextjs.mdc)
apps/web/**/*.{ts,tsx}: Use the App Router directory structure in Next.js projects
Mark client components explicitly with 'use client' directive
Place static content and interfaces at file end
When usinguseRouter, import from@bprogress/next/appto show global progress bar
Use Zod for form validation in forms
Use react-hook-form for form handling as defined inapps/web/src/components/ui/form.tsx
Files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/components/sortable-list.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.tsapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx
apps/web/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/nextjs.mdc)
apps/web/**/*.tsx: Wrap client components in Suspense with fallback
Minimize use of 'useEffect' and 'setState' hooks
Show loading states during form submission
Files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/components/sortable-list.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx
{apps/web/**/*.ts,apps/web/**/*.tsx,packages/ui/**/*.ts,packages/ui/**/*.tsx}
📄 CodeRabbit inference engine (.cursor/rules/shadcn.mdc)
{apps/web/**/*.ts,apps/web/**/*.tsx,packages/ui/**/*.ts,packages/ui/**/*.tsx}: Import Shadcn UI components from the @agentset/ui alias (e.g.,import { Button, Card } from "@agentset/ui")
Use Shadcn UI components from the packages/ui/src/components/ui directory for UI elements
Style components using the 'new-york' style variant with 'neutral' base color and CSS variables for theming as configured in components.json
The Button component supports an isLoading prop to display a loading spinner
Files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/components/sortable-list.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.tsapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Import from packages using configured aliases (e.g.,
@agentset/ui,@agentset/db/client) instead of relative paths to packages
Files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/components/sortable-list.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.tsapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx
🧠 Learnings (6)
📚 Learning: 2025-12-21T13:02:44.489Z
Learnt from: max-programming
Repo: agentset-ai/agentset PR: 73
File: apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsx:19-19
Timestamp: 2025-12-21T13:02:44.489Z
Learning: Tailwind CSS v4 supports the spacing(n) shorthand inside arbitrary values (e.g., h-[calc(...(--spacing(16))...)) to compile to calc(var(--spacing) * n). When reviewing TSX files that use Tailwind and arbitrary values, verify any usage of --spacing within calc expressions is valid per Tailwind v4 docs and that the resulting CSS is correctly applied. If you introduce or rely on such spacing syntax, ensure the syntax is supported in the specific Tailwind build configuration and that there are no typos or unsupported nested expressions.
Applied to files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/components/sortable-list.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsxapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx
📚 Learning: 2025-11-26T20:30:45.439Z
Learnt from: CR
Repo: agentset-ai/agentset PR: 0
File: .cursor/rules/nextjs.mdc:0-0
Timestamp: 2025-11-26T20:30:45.439Z
Learning: Applies to apps/web/**/*.tsx : Minimize use of 'useEffect' and 'setState' hooks
Applied to files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/components/sortable-list.tsx
📚 Learning: 2025-11-26T20:30:45.439Z
Learnt from: CR
Repo: agentset-ai/agentset PR: 0
File: .cursor/rules/nextjs.mdc:0-0
Timestamp: 2025-11-26T20:30:45.439Z
Learning: Applies to apps/web/**/*.tsx : Wrap client components in Suspense with fallback
Applied to files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsx
📚 Learning: 2025-11-26T20:30:45.439Z
Learnt from: CR
Repo: agentset-ai/agentset PR: 0
File: .cursor/rules/nextjs.mdc:0-0
Timestamp: 2025-11-26T20:30:45.439Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use react-hook-form for form handling as defined in `apps/web/src/components/ui/form.tsx`
Applied to files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsxapps/web/src/components/sortable-list.tsx
📚 Learning: 2025-11-26T20:30:45.439Z
Learnt from: CR
Repo: agentset-ai/agentset PR: 0
File: .cursor/rules/nextjs.mdc:0-0
Timestamp: 2025-11-26T20:30:45.439Z
Learning: Applies to apps/web/**/*.tsx : Show loading states during form submission
Applied to files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsx
📚 Learning: 2025-11-26T20:30:45.439Z
Learnt from: CR
Repo: agentset-ai/agentset PR: 0
File: .cursor/rules/nextjs.mdc:0-0
Timestamp: 2025-11-26T20:30:45.439Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use Zod for form validation in forms
Applied to files:
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.ts
🧬 Code graph analysis (3)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsx (3)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.ts (2)
HostingFormValues(40-40)HostingData(42-42)apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx (1)
TabValue(15-20)packages/ui/src/components/ui/form.tsx (1)
FormLabel(164-164)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsx (4)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.ts (2)
HostingData(42-42)useHostingForm(44-152)apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx (1)
TabValue(15-20)apps/web/src/lib/constants.ts (2)
APP_DOMAIN(13-18)HOSTING_PREFIX(34-34)apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsx (1)
HostingPreview(23-80)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx (1)
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsx (1)
GeneralTab(27-129)
🔇 Additional comments (13)
apps/web/src/components/sortable-list.tsx (2)
7-7: LGTM!The
useEffectimport is properly added to support the new hook introduced later in the component.
157-168: LGTM!The Add button has been repositioned below the sortable list with proper spacing. This improves the visual hierarchy and accessibility by separating the action button from the drag-and-drop area.
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-tabs.tsx (2)
47-47: LGTM! Tab reordering aligns with PR objectives.The Open Graph tab has been repositioned to appear after the Security tab, improving the navigation structure as mentioned in the PR description.
53-53: LGTM! Programmatic tab switching enabled.The
setTab={setActiveTab}prop correctly enables GeneralTab to trigger tab changes (e.g., switching to the Advanced tab via the Custom domain button). The type signature matches:setActiveTabisReact.Dispatch<React.SetStateAction<TabValue>>, which is compatible with(tab: TabValue) => void.apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-layout.tsx (2)
22-37: Unsaved changes warning implemented correctly, but note browser limitations.The
beforeunloadhandler correctly prevents accidental data loss whenisDirtyis true. The implementation properly:
- Sets
event.returnValuefor Chrome compatibility- Returns the message string
- Cleans up the event listener on unmount
However, note that modern browsers (Chrome 51+, Firefox 44+) ignore custom messages and show generic "Leave site?" dialogs. The
UNSAVED_CHANGES_MESSAGEconstant won't be displayed to users but serves as documentation.Regarding the coding guideline to minimize
useEffectusage: this is a justified exception since integrating with browser APIs likebeforeunloadrequires an effect. There's no alternative pattern for this use case.
42-43: LGTM! Simplified conditional logic.The switch-to-conditional refactor reduces complexity while maintaining the same functionality. The binary choice (Open Graph tab vs. default preview) is more clearly expressed with an if statement.
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/hosting-preview.tsx (3)
33-33: LGTM! Header text simplified.The change from "Live Preview" to "Preview" is cleaner and aligns with the PR's UI refinements.
46-46: LGTM! Logo fallback simplified.Removing the placeholder div when no logo is present simplifies the UI. The logo now only renders when explicitly provided.
57-66: LGTM! Critical filter for empty strings added.The
.filter(Boolean)is essential given the validation schema changes inuse-hosting-form.ts(lines 29, 101-102) that now allow empty strings in theexampleQuestionsarray. Without this filter, empty suggestion buttons would render in the preview.The restructured wrapper with
mx-4 mb-4classes improves spacing consistency.apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsx (3)
19-19: LGTM! Type import added for tab switching.The
TabValueimport supports the newsetTabprop, enabling type-safe programmatic tab navigation.
24-24: LGTM! Interface extended to support tab switching.The
setTabcallback prop enables the Custom domain button to programmatically switch to the Advanced tab, improving UX by guiding users to the custom domain configuration.Also applies to: 27-27
63-72: LGTM! Custom domain navigation button implemented correctly.The button implementation is solid:
type="button"correctly prevents form submissionsetTab("other")switches to the Advanced tab where custom domain settings reside- Positioned contextually next to the Slug field for discoverability
- Link-like styling (
underline,text-primary) indicates navigation actionapps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.ts (1)
26-26: Update Zod email validation syntax to v4 standard.The change from
z.array(z.string().email())toz.array(z.email())is correct for Zod v4. Both syntaxes are functionally equivalent—z.email()is the idiomatic v4 approach and provides identical validation behavior and error messages. No compatibility concerns.
| exampleQuestions: z.array(z.string()).max(4), | ||
| exampleSearchQueries: z.array(z.string()).max(4), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Find the form file and examine the validation schema
find . -type f -name "use-hosting-form.ts" | head -5Repository: agentset-ai/agentset
Length of output: 161
🏁 Script executed:
# Search for backend hosting handlers and API routes
rg "hosting.*update|exampleQuestions|exampleSearchQueries" --type ts --type tsx -g '!node_modules' | head -50Repository: agentset-ai/agentset
Length of output: 91
🏁 Script executed:
# Find hosting-preview.tsx to verify the UI filtering
find . -type f -name "hosting-preview.tsx" | head -5Repository: agentset-ai/agentset
Length of output: 172
🏁 Script executed:
# Read the form validation file to see the schema
cat -n ./apps/web/src/app/app.agentset.ai/\(dashboard\)/\[slug\]/\[namespaceSlug\]/hosting/use-hosting-form.tsRepository: agentset-ai/agentset
Length of output: 6359
🏁 Script executed:
# Read hosting-preview.tsx to verify the filtering logic
cat -n ./apps/web/src/app/app.agentset.ai/\(dashboard\)/\[slug\]/\[namespaceSlug\]/hosting/components/hosting-preview.tsx | head -80Repository: agentset-ai/agentset
Length of output: 3065
🏁 Script executed:
# Search for backend handling - look in server, api, and packages directories
rg "exampleQuestions|exampleSearchQueries" --type ts -g '!node_modules' -C 3Repository: agentset-ai/agentset
Length of output: 14687
🏁 Script executed:
# Read the backend update service to see if filtering happens
cat -n ./apps/web/src/services/hosting/update.tsRepository: agentset-ai/agentset
Length of output: 4587
🏁 Script executed:
# Search for the TRPC hosting update handler in server directories
find . -type f -name "*.ts" -path "*/server/*" -o -path "*/api/*" | xargs rg -l "hosting.*update" 2>/dev/null | head -10Repository: agentset-ai/agentset
Length of output: 671
🏁 Script executed:
# Look for the TRPC procedure definition for hosting.update
rg "hosting.*update|\.update\(" --type ts -g '!node_modules' -B 2 -A 10 | grep -A 10 "trpc.*hosting" | head -50Repository: agentset-ai/agentset
Length of output: 1636
Backend persists empty strings without filtering—add validation to sanitize arrays.
The backend service (apps/web/src/services/hosting/update.ts lines 83-84) passes exampleQuestions and exampleSearchQueries directly to the database without filtering empty or whitespace-only strings. Combined with the form's removal of .min(1) validation and the UI-only filtering in the preview component, empty strings like ["", "valid question", ""] will be persisted to the database.
Implement backend filtering to remove empty/whitespace-only strings before the Prisma update, or add stricter validation to reject submissions with empty array elements.
| exampleQuestions: | ||
| data.exampleQuestions.length === 0 ? [""] : data.exampleQuestions, | ||
| exampleSearchQueries: | ||
| data.exampleSearchQueries.length === 0 | ||
| ? [""] | ||
| : data.exampleSearchQueries, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, read the file to understand the full context
wc -l apps/web/src/app/app.agentset.ai/\(dashboard\)/\[slug\]/\[namespaceSlug\]/hosting/use-hosting-form.tsRepository: agentset-ai/agentset
Length of output: 163
🏁 Script executed:
# Since we need to handle special characters in the path, let's find the file first
fd "use-hosting-form.ts" apps/web/Repository: agentset-ai/agentset
Length of output: 159
🏁 Script executed:
cat -n "apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.ts"Repository: agentset-ai/agentset
Length of output: 6359
🏁 Script executed:
# Search for the TRPC hosting.update mutation
find apps/web -type f -name "*.ts" -o -name "*.tsx" | xargs grep -l "hosting.update" | head -5Repository: agentset-ai/agentset
Length of output: 371
🏁 Script executed:
# Also search in packages for backend logic
find packages -type f -name "*.ts" | xargs grep -l "exampleQuestions" | head -10Repository: agentset-ai/agentset
Length of output: 46
🏁 Script executed:
cat -n "apps/web/src/server/api/routers/hosting.ts"Repository: agentset-ai/agentset
Length of output: 2673
🏁 Script executed:
fd "hosting.ts" packages/ | grep -i schemaRepository: agentset-ai/agentset
Length of output: 46
🏁 Script executed:
# Find the schema file
find apps/web -path "*schemas/api/hosting*" -type fRepository: agentset-ai/agentset
Length of output: 99
🏁 Script executed:
cat -n "apps/web/src/schemas/api/hosting.ts"Repository: agentset-ai/agentset
Length of output: 5326
🏁 Script executed:
find apps/web/src/services -name "*hosting*" -type fRepository: agentset-ai/agentset
Length of output: 46
🏁 Script executed:
find apps/web/src/services -type f -name "*.ts" | xargs grep -l "exampleQuestions" 2>/dev/nullRepository: agentset-ai/agentset
Length of output: 103
🏁 Script executed:
# Also search for updateHosting function
rg "export.*updateHosting" apps/web/src --type tsRepository: agentset-ai/agentset
Length of output: 331
🏁 Script executed:
cat -n "apps/web/src/services/hosting/update.ts"Repository: agentset-ai/agentset
Length of output: 4587
🏁 Script executed:
# Verify if there's any filtering elsewhere in the codebase
rg "filter.*empty" apps/web/src/services/hosting/ --type tsRepository: agentset-ai/agentset
Length of output: 46
🏁 Script executed:
# Check if there's any normalization in the API layer
rg "exampleQuestions" apps/web/src/app/api/ --type ts -A 3Repository: agentset-ai/agentset
Length of output: 46
Filter empty strings before submission to prevent backend round-trip inconsistency.
The logic initializes empty arrays as [""] to display an empty input field in the UI, but submits them as-is without filtering. When the backend stores [""] and returns it on next fetch, the data becomes inconsistent—the ternary check at lines 101-106 only transforms when length === 0, so [""] (length 1) won't be transformed back to [].
Filter empty strings in onSubmit before submitting:
exampleQuestions: newData.exampleQuestions.filter(q => q.trim() !== ""),
exampleSearchQueries: newData.exampleSearchQueries.filter(q => q.trim() !== ""),
🤖 Prompt for AI Agents
In
apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/hosting/use-hosting-form.ts
around lines 101 to 106, the form initializes empty inputs as [""] for UI but
currently submits these unchanged, causing backend-store/round-trip
inconsistency because the length check only handles true empty arrays; update
the onSubmit handler to filter out empty/whitespace-only strings before sending
(e.g., replace submitted exampleQuestions and exampleSearchQueries with filtered
arrays using .filter(q => q.trim() !== "") so [""] becomes [] while preserving
real entries).
| useEffect(() => { | ||
| if (virtualIds.length === 1 && fields.length === 0) { | ||
| append("" as any); | ||
| } | ||
| }, [virtualIds, fields, append]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's read the file to understand the full context
cat -n apps/web/src/components/sortable-list.tsx | head -100Repository: agentset-ai/agentset
Length of output: 3415
🏁 Script executed:
# Let's see more of the file to understand the complete render and usage
cat -n apps/web/src/components/sortable-list.tsx | tail -80Repository: agentset-ai/agentset
Length of output: 2242
🏁 Script executed:
# Let's check the context around how form values are passed and initialized
# Look for uses of this SortableList component
rg "SortableList" apps/web --type tsx -B 2 -A 2Repository: agentset-ai/agentset
Length of output: 91
🏁 Script executed:
# Search for SortableList usage without specifying file type
rg "SortableList" apps/web -B 2 -A 2Repository: agentset-ai/agentset
Length of output: 2887
🏁 Script executed:
# Let's examine how the form is initialized and passed to SortableList
cat -n apps/web/src/app/app.agentset.ai/'(dashboard)'/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsx | grep -A 30 "exampleQuestions"Repository: agentset-ai/agentset
Length of output: 288
🏁 Script executed:
# Let's look at the full form initialization in general-tab.tsx to understand
# when exampleQuestions might be empty or out of sync
head -100 apps/web/src/app/app.agentset.ai/'(dashboard)'/[slug]/[namespaceSlug]/hosting/components/tabs/general-tab.tsxRepository: agentset-ai/agentset
Length of output: 3106
🏁 Script executed:
# Find the use-hosting-form file to understand form initialization
fd "use-hosting-form" apps/webRepository: agentset-ai/agentset
Length of output: 159
🏁 Script executed:
# Let's examine the form initialization to see how exampleQuestions is set
cat -n apps/web/src/app/app.agentset.ai/'(dashboard)'/[slug]/[namespaceSlug]/hosting/use-hosting-form.ts | head -150Repository: agentset-ai/agentset
Length of output: 6338
Avoid useEffect for managing minimum item count; enforce this through explicit component logic instead.
This useEffect violates the explicit coding guideline to minimize useEffect hooks in apps/web/**/*.tsx files. The condition virtualIds.length === 1 && fields.length === 0 detects a synchronization issue when items are deleted, but this constraint should be enforced through component logic rather than a side effect.
The form initialization already ensures at least one empty item exists when the data is empty (see use-hosting-form.ts). To maintain this requirement:
- Prevent removal of the last item directly in
handleRemoveby checkingfields.length === 1 - Add a
minItemsprop and validate it explicitly - Remove the useEffect entirely
🤖 Prompt for AI Agents
In apps/web/src/components/sortable-list.tsx around lines 61 to 65, remove the
useEffect that appends an item when virtualIds.length === 1 && fields.length ===
0 and instead enforce a minimum item count via component logic: delete the
useEffect block entirely, add a minItems prop (default 1) and validate it at
component entry, and update the handleRemove function to prevent removing the
last allowed item by checking if fields.length <= minItems before calling
remove; ensure any initialization relies on the existing form initialization
(use-hosting-form) so no append side-effect is needed.
Summary by CodeRabbit
Release Notes
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.