mirror of
https://github.com/supabase/supabase.git
synced 2026-10-19 16:19:10 +03:00
- Move min/max/required validation for version_expiry_days and
max_noncurrent_versions into a shared superRefine (BucketDataProtectionFields.schema.ts),
called from each modal's own superRefine, instead of imperative
validateVersioningFields() + form.setError() calls in onSubmit. Errors
now surface the same way as the rest of the form (FormItemLayout/FormMessage),
matching Studio's established form-error convention.
- Switch the fields to the '' empty-sentinel + z.coerce.number() union
pattern (per the react-hook-form skill) instead of z.string().optional(),
keeping inputs fully controlled without special-casing undefined.
- Build each modal's schema dynamically via useMemo(() => schema(planLimits), ...)
since the versioning bounds depend on the async-loaded org plan.
- Replace destructured useFormContext().watch() with useWatch({ control, name })
in BucketDataProtectionFields, avoiding the ratcheted no-use-watch lint warning.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
import { z } from 'zod'
|
|
|
|
import type { VersioningPlanLimits } from './StorageProtection.constants'
|
|
|
|
/**
|
|
* Shared zod fields for the object-versioning controls in the create/edit
|
|
* bucket modals. `''` is the in-form empty sentinel (per the react-hook-form
|
|
* convention) so the number inputs stay fully deletable/controlled; it's
|
|
* coerced to a real number on parse.
|
|
*/
|
|
const versioningNumberField = z.union([z.literal(''), z.coerce.number().int()])
|
|
|
|
export const bucketProtectionFormFields = {
|
|
enable_versioning: z.boolean().default(false),
|
|
version_expiry_days: versioningNumberField.default(''),
|
|
max_noncurrent_versions: versioningNumberField.default(''),
|
|
}
|
|
|
|
export interface BucketProtectionFormValues {
|
|
enable_versioning: boolean
|
|
version_expiry_days: '' | number
|
|
max_noncurrent_versions: '' | number
|
|
}
|
|
|
|
/**
|
|
* Validates the versioning fields against the org's plan limits. Call this
|
|
* from the parent modal's `.superRefine` so errors surface through the usual
|
|
* `FormItemLayout`/`FormMessage` rendering.
|
|
*/
|
|
export const superRefineBucketProtection = (
|
|
data: BucketProtectionFormValues,
|
|
ctx: z.RefinementCtx,
|
|
planLimits: VersioningPlanLimits | null
|
|
) => {
|
|
if (!data.enable_versioning || !planLimits) return
|
|
|
|
if (data.version_expiry_days === '') {
|
|
ctx.addIssue({
|
|
path: ['version_expiry_days'],
|
|
code: z.ZodIssueCode.custom,
|
|
message: 'Please provide a retention period',
|
|
})
|
|
} else if (
|
|
data.version_expiry_days < planLimits.minRetentionDays ||
|
|
data.version_expiry_days > planLimits.maxRetentionDays
|
|
) {
|
|
ctx.addIssue({
|
|
path: ['version_expiry_days'],
|
|
code: z.ZodIssueCode.custom,
|
|
message: `Must be between ${planLimits.minRetentionDays} and ${planLimits.maxRetentionDays} days on your plan`,
|
|
})
|
|
}
|
|
|
|
if (data.max_noncurrent_versions === '') {
|
|
ctx.addIssue({
|
|
path: ['max_noncurrent_versions'],
|
|
code: z.ZodIssueCode.custom,
|
|
message: 'Please provide a value',
|
|
})
|
|
} else if (
|
|
data.max_noncurrent_versions < planLimits.minVersions ||
|
|
data.max_noncurrent_versions > planLimits.maxVersions
|
|
) {
|
|
ctx.addIssue({
|
|
path: ['max_noncurrent_versions'],
|
|
code: z.ZodIssueCode.custom,
|
|
message: `Must be between ${planLimits.minVersions} and ${planLimits.maxVersions} versions on your plan`,
|
|
})
|
|
}
|
|
}
|