mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 20:35:07 +03:00
Task A: Add ExpirationMode (and/or) toggle between retention-days and max-versions fields in bucket settings. 'and' = single S3 lifecycle policy (both conditions must be met), 'or' = two independent rules (either triggers). Wired into form schema, create/edit bucket modals, and mock store. Task B: Move 'Show deleted versions' toggle from breadcrumb bar into the file explorer table header, right of the search input. Switch is on the left of the label text. Task C: Add noncurrent version rows beneath each deleted object in TrashList. Nested rows have left indentation with a CornerDownRight icon and lighter background. Added DeletedObjectVersion interface and mock data to protection-mocks.ts. Updated all user-facing terminology from 'files' to 'versions' across Trash, TrashList, TrashSelectionBar, DeletedFilesList, DeletedFilesHeaderSelection, DeletedFilePreviewPane, and bucket page tabs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
73 lines
2.4 KiB
TypeScript
73 lines
2.4 KiB
TypeScript
import { z } from 'zod'
|
|
|
|
import type { ExpirationMode, 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(''),
|
|
expiration_mode: z.enum(['and', 'or']).default('and'),
|
|
}
|
|
|
|
export interface BucketProtectionFormValues {
|
|
enable_versioning: boolean
|
|
version_expiry_days: '' | number
|
|
max_noncurrent_versions: '' | number
|
|
expiration_mode: ExpirationMode
|
|
}
|
|
|
|
/**
|
|
* 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`,
|
|
})
|
|
}
|
|
}
|