Files
supabase/apps/studio/components/interfaces/Storage/StorageBucketSelector.tsx
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

47 lines
1.3 KiB
TypeScript

import { useMemo } from 'react'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from 'ui'
import { usePaginatedBucketsQuery } from '@/data/storage/buckets-query'
interface StorageBucketSelectorProps {
projectRef?: string
value?: string
onChange: (bucketId: string) => void
}
/**
* Compact bucket picker shared by the Snapshots and Trash pages, both of which
* are scoped to a single bucket at a time.
*/
export const StorageBucketSelector = ({
projectRef,
value,
onChange,
}: StorageBucketSelectorProps) => {
const { data } = usePaginatedBucketsQuery({ projectRef })
const bucketNames = useMemo(() => {
const buckets = data?.pages.flatMap((page) => page) ?? []
return buckets
.filter((bucket) => !('type' in bucket) || bucket.type === 'STANDARD')
.map((bucket) => bucket.name)
}, [data])
if (bucketNames.length === 0) return null
return (
<Select value={value} onValueChange={onChange}>
<SelectTrigger className="w-44" aria-label="Select a bucket">
<SelectValue placeholder="Select a bucket" />
</SelectTrigger>
<SelectContent>
{bucketNames.map((name) => (
<SelectItem key={name} value={name}>
{name}
</SelectItem>
))}
</SelectContent>
</Select>
)
}