Files
supabase/apps/studio/components/interfaces/Integrations/Wrappers/InputField.tsx
T
Joshen Lim 9aae037dff Joshenlim/fe 4475 fdw update sql to run proper alter statements instead of (#50988)
## Context

Currently for FDWs under integrations, editing an FDW involves tearing
it down then re-creating it - which while conveniently works has a lot
of problems like:
- Blast radius is way bigger than the edit
  - Everything is recreated, including vault secrets
- Silent drops grants/comments/ownership
- Cascades on dependent objects
- Views or functions built on top of foreign tables would get dropped
along with it

Changes in this PR hence updates `getUpdateFDWSql` to diff the current
wrapper state against the form state and generate targeted `ALTER`
statements for only what actually changed

## To test
- [ ] Verify that updating an existing wrapper still works as expected

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Wrapper changes can be saved in place, including server options,
encrypted values, foreign tables, and column definitions.
* Input fields can display placeholder text, and missing server-option
values display their defaults.

* **Improvements**
* Saving is unavailable until encrypted values are ready; a waiting
message appears while they load.
* The edit panel closes after a successful save. Confirmation text
explains that table or column changes may affect dependent
functionality.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-29 19:47:57 +08:00

72 lines
2.3 KiB
TypeScript

import { HelpCircle } from 'lucide-react'
import Link from 'next/link'
import type { Control, FieldPath, FieldValues } from 'react-hook-form'
import { cn, FormControl, FormField, Input, InputVariants, Textarea } from 'ui'
import { Input as PasswordInput } from 'ui-patterns/DataInputs/Input'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import type { ServerOption } from './Wrappers.types'
interface InputFieldProps<TFieldValues extends FieldValues = FieldValues> {
option: ServerOption
control: Control<TFieldValues>
loading?: boolean
placeholder?: string
}
const InputField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
control,
option,
loading = false,
placeholder,
}: InputFieldProps<TFieldValues>) => {
return (
<FormField
control={control}
name={option.name as TName}
defaultValue={(option.defaultValue ?? '') as any}
render={({ field }) => (
<FormItemLayout
layout="vertical"
label={
<div className="flex items-center space-x-2">
<p>{option.label}</p>
{option.urlHelper !== undefined && (
<Link href={option.urlHelper} target="_blank" rel="noreferrer">
<span className="sr-only">Documentation</span>
<HelpCircle
strokeWidth={2}
size={14}
className="text-foreground-light hover:text-foreground cursor-pointer transition"
/>
</Link>
)}
</div>
}
labelOptional={!option.required ? 'Optional' : undefined}
description={option.description}
>
<FormControl>
{loading ? (
<span className={cn(InputVariants({ size: 'small' }))}>
Fetching value from Vault...
</span>
) : option.isTextArea ? (
<Textarea {...field} rows={6} className="input-mono resize-none" />
) : option.secureEntry ? (
<PasswordInput copy reveal {...field} />
) : (
<Input {...field} placeholder={placeholder} />
)}
</FormControl>
</FormItemLayout>
)}
/>
)
}
export default InputField