mirror of
https://github.com/supabase/supabase.git
synced 2026-09-08 19:08:44 +08:00
Fixes FE-4130. ## What is the current behavior? When submitting the support form with required fields missing, the form does not scroll to or focus the required empty field. Users have to manually find which field they missed. ## What is the new behavior? On submit, the form automatically scrolls to and focuses the first required field that's missing a value - including "What issue are you having?" and "Which library are you having issues with?". ## Additional context The scroll wasn't working due to a Chrome bug where scrollIntoView is blocked when overflow-x: hidden and overflow-y: auto are on the same element (the sidebar scroll container). The fix manually walks the DOM to find the scrollable parent and calls scrollTo() directly. Dropdown fields (Radix Selects) were also unfindable via the usual name attribute, so data-support-field attributes are used as a stable DOM hook for those. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Bug Fixes * Improved support form validation by automatically scrolling to the first invalid or missing required field. * Added smooth scrolling and focus behavior to help users quickly correct form errors. * Ensured the client library field is brought into view when required information is missing. * Improved field targeting for category and client library validation messages. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ali Waseem <waseema393@gmail.com>
138 lines
4.6 KiB
TypeScript
138 lines
4.6 KiB
TypeScript
// End of third-party imports
|
|
|
|
import { CLIENT_LIBRARIES } from 'common/constants'
|
|
import { ExternalLink } from 'lucide-react'
|
|
import Link from 'next/link'
|
|
import type { UseFormReturn } from 'react-hook-form'
|
|
import {
|
|
Button,
|
|
cn,
|
|
FormControl,
|
|
FormField,
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from 'ui'
|
|
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
|
|
|
import type { ExtendedSupportCategories } from './Support.constants'
|
|
import type { SupportFormValues } from './SupportForm.schema'
|
|
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
|
|
|
|
interface ClientLibraryInfoProps {
|
|
form: UseFormReturn<SupportFormValues>
|
|
category: ExtendedSupportCategories
|
|
library: string | undefined
|
|
}
|
|
|
|
export function ClientLibraryInfo({ form, category, library }: ClientLibraryInfoProps) {
|
|
const showClientLibraries = useIsFeatureEnabled('support:show_client_libraries')
|
|
|
|
if (!showClientLibraries) return null
|
|
if (category !== 'Problem') return null
|
|
|
|
return (
|
|
<div className="flex flex-col gap-y-1">
|
|
<FormField
|
|
name="library"
|
|
control={form.control}
|
|
render={({ field }) => (
|
|
<FormItemLayout layout="vertical" label="Which library are you having issues with">
|
|
<FormControl>
|
|
<Select {...field} defaultValue={field.value} onValueChange={field.onChange}>
|
|
<SelectTrigger
|
|
data-support-field="library"
|
|
className="w-full"
|
|
aria-label="Select a library"
|
|
>
|
|
<SelectValue placeholder="Select a library" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectGroup>
|
|
{CLIENT_LIBRARIES.map((option) => (
|
|
<SelectItem key={option.language} value={option.language}>
|
|
{option.language}
|
|
</SelectItem>
|
|
))}
|
|
</SelectGroup>
|
|
</SelectContent>
|
|
</Select>
|
|
</FormControl>
|
|
</FormItemLayout>
|
|
)}
|
|
/>
|
|
{library && library.length > 0 && <LibrarySuggestions library={library} />}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface LibrarySuggestionsProps {
|
|
library: string
|
|
}
|
|
|
|
const LibrarySuggestions = ({ library }: LibrarySuggestionsProps) => {
|
|
const selectedLibrary = CLIENT_LIBRARIES.find((lib) => lib.language === library)
|
|
const selectedClientLibraries = selectedLibrary?.libraries.filter((library) =>
|
|
library.name.includes('supabase-')
|
|
)
|
|
return (
|
|
<div className="flex flex-col gap-y-4">
|
|
<div className="space-y-2">
|
|
<p className="text-sm text-foreground-light">
|
|
Found an issue or a bug? Try searching our GitHub issues or submit a new one.
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center space-x-4 overflow-x-auto">
|
|
{selectedClientLibraries?.map((lib) => {
|
|
const libraryLanguage = library === 'Dart (Flutter)' ? lib.name.split('-')[1] : library
|
|
return (
|
|
<div
|
|
key={lib.name}
|
|
className="w-[230px] min-w-[230px] min-h-[128px] rounded-sm border border-control bg-surface-100 space-y-3 px-4 py-3"
|
|
>
|
|
<div className="space-y-1">
|
|
<p className="text-sm">{lib.name}</p>
|
|
<p className="text-sm text-foreground-light">
|
|
For issues regarding the {libraryLanguage} client library
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<Button
|
|
asChild
|
|
variant="default"
|
|
icon={<ExternalLink size={14} strokeWidth={1.5} />}
|
|
>
|
|
<Link href={lib.url} target="_blank" rel="noreferrer">
|
|
View GitHub issues
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)
|
|
})}
|
|
<div
|
|
className={cn(
|
|
'px-4 py-3 rounded-sm border border-control bg-surface-100',
|
|
'w-[230px] min-w-[230px] min-h-[128px] flex flex-col justify-between space-y-3'
|
|
)}
|
|
>
|
|
<div className="space-y-1">
|
|
<p className="text-sm">supabase</p>
|
|
<p className="text-sm text-foreground-light">For any issues about our API</p>
|
|
</div>
|
|
<div>
|
|
<Button asChild variant="default" icon={<ExternalLink size={14} strokeWidth={1.5} />}>
|
|
<Link href="https://github.com/supabase/supabase" target="_blank" rel="noreferrer">
|
|
View GitHub issues
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|