Files
supabase/apps/studio/components/interfaces/Storage/StorageProtection.constants.ts
T
Claude b1184b3a99 feat(studio): Storage Snapshots & Versioning demo (mock data)
Implements the five Claude Design mockups as real Studio components behind a
single prototype flag (STORAGE_PROTECTION_ENABLED), wired to an in-memory mock
data layer since no platform API exists yet:

- Data protection section in create/edit bucket modals (versioning + snapshots
  toggles + lifecycle policies)
- Snapshots: new bucket-scoped nav page with Pre-backup/Manual triggers, take
  snapshot, and restore-with-diff
- Versions tab in the storage explorer preview pane (restore an older version)
- Storage size retention breakdown on the org usage page (live / versions /
  snapshots, retained-data callout, per-bucket table)
- Trash: new bucket-scoped nav page for soft-deletes with held-by-snapshot state

Adds mock query/mutation hooks under data/storage/protection, Snapshots + Trash
nav items, and new pages/routes (+ TANSTACK_MIGRATION entries).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiUEvmC84bRsteqsWXHY2p
2026-07-25 00:37:12 +00:00

67 lines
2.2 KiB
TypeScript

/**
* Shared constants + gating for the Storage Snapshots & Versioning prototype.
*/
// Prototype flag: force-enabled so the surfaces are visible via `pnpm dev:studio`.
// A real rollout would replace this with `useFlag('storageObjectVersioning')`.
export const STORAGE_PROTECTION_ENABLED = true
export const useIsStorageProtectionEnabled = () => STORAGE_PROTECTION_ENABLED
export type BucketVersioningState = 'enabled' | 'suspended' | 'disabled'
export interface BucketProtection {
versioning: BucketVersioningState
snapshots: boolean
snapshotOnDatabaseBackup: boolean
/** Expire noncurrent versions after N days (null = keep indefinitely). */
versionExpiryDays: number | null
/** Cap on retained newer noncurrent versions (max 100). */
maxNoncurrentVersions: number | null
/** Expire snapshots after N days (null = keep indefinitely). */
snapshotExpiryDays: number | null
}
const PROTECTED_BUCKETS: Record<string, BucketProtection> = {
'match-media': {
versioning: 'enabled',
snapshots: true,
snapshotOnDatabaseBackup: true,
versionExpiryDays: 30,
maxNoncurrentVersions: 100,
snapshotExpiryDays: 90,
},
avatars: {
versioning: 'enabled',
snapshots: false,
snapshotOnDatabaseBackup: false,
versionExpiryDays: 30,
maxNoncurrentVersions: 10,
snapshotExpiryDays: null,
},
}
const DEFAULT_PROTECTION: BucketProtection = {
versioning: 'disabled',
snapshots: false,
snapshotOnDatabaseBackup: false,
versionExpiryDays: null,
maxNoncurrentVersions: null,
snapshotExpiryDays: null,
}
/** Prototype: derive a bucket's protection config from its name. */
export const getMockBucketProtection = (bucketName: string | undefined): BucketProtection =>
(bucketName && PROTECTED_BUCKETS[bucketName]) || DEFAULT_PROTECTION
export const isBucketVersioned = (bucketName: string | undefined) =>
getMockBucketProtection(bucketName).versioning === 'enabled'
// Colours for the retention breakdown (Tailwind-independent so the chart + legend
// stay in lockstep). Live = brand green, versions = amber, snapshots = blue.
export const RETENTION_COLORS = {
live: 'hsl(var(--brand-default))',
versions: 'hsl(var(--warning-default))',
snapshots: 'hsl(217, 91%, 60%)',
} as const