import { useState } from "react"; import { Camera, Loader2, Plus, RefreshCw } from "lucide-react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { createDatabaseSnapshot, listDatabaseSnapshots } from "@/api/cloudProxyClient"; import { HttpError } from "@/api/HttpClient"; import { EmptyState } from "@/components/EmptyState"; import { capabilityEnabled } from "@/lib/capabilities"; import type { CloudProvider } from "@/types/cloud"; import type { CloudResource } from "@/types/resource"; import type { CapabilitySchema, DatabaseActionName } from "@/types/schema"; export interface DatabaseSnapshotsPanelProps { cloud: CloudProvider; instances: CloudResource[]; listCapability?: CapabilitySchema; createCapability?: CapabilitySchema; runtimeReachable: boolean; } export function DatabaseSnapshotsPanel({ cloud, instances, listCapability, createCapability, runtimeReachable, }: DatabaseSnapshotsPanelProps) { const qc = useQueryClient(); const [sourceInstance, setSourceInstance] = useState(""); const [snapshotId, setSnapshotId] = useState(""); const [createOpen, setCreateOpen] = useState(false); const canList = runtimeReachable && capabilityEnabled(listCapability); const canCreate = runtimeReachable && capabilityEnabled(createCapability); const snapshotsQuery = useQuery({ queryKey: ["database-snapshots", cloud], queryFn: ({ signal }) => listDatabaseSnapshots(cloud, undefined, signal), enabled: canList, }); const createMut = useMutation({ mutationFn: (input: { instanceIdentifier: string; snapshotIdentifier: string }) => createDatabaseSnapshot(cloud, input), onSuccess: () => { setSourceInstance(""); setSnapshotId(""); setCreateOpen(false); void qc.invalidateQueries({ queryKey: ["database-snapshots", cloud] }); }, }); const handleSourceChange = (newInstance: string) => { setSourceInstance(newInstance); if (newInstance) { setSnapshotId(`${newInstance}-snapshot-${Date.now()}`); } else { setSnapshotId(""); } }; const isFormValid = Boolean(sourceInstance.trim() && snapshotId.trim()); const handleCreateSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!isFormValid || !canCreate || createMut.isPending) return; createMut.mutate({ instanceIdentifier: sourceInstance.trim(), snapshotIdentifier: snapshotId.trim(), }); }; const getErrorMessage = (error: unknown): string => { if ( error instanceof HttpError && typeof error.body === "object" && error.body !== null && "code" in error.body && (error.body as { code?: unknown }).code === "operation_not_implemented" ) { return "Snapshot creation is available in Floci UI, but the selected Floci runtime does not implement CreateDBSnapshot."; } if (error instanceof Error) { return error.message; } return "Snapshot creation failed."; }; return (

Database Snapshots

{snapshotsQuery.data ? `${snapshotsQuery.data.length} snapshots` : "Snapshots"}
{createOpen && (
setSnapshotId(e.target.value)} placeholder="e.g. my-db-snapshot-1" />
{createMut.isError && (
{getErrorMessage(createMut.error)}
)}
)} {!canList ? (

{listCapability?.reason ?? "Snapshot listing is not available."}

) : snapshotsQuery.isLoading ? (

Loading snapshots…

) : snapshotsQuery.isError ? (
{snapshotsQuery.error instanceof Error ? snapshotsQuery.error.message : "Failed to load database snapshots."}
) : (snapshotsQuery.data?.length ?? 0) === 0 ? ( ) : (
{snapshotsQuery.data?.map((snapshot) => (
{snapshot.name} {snapshot.instanceIdentifier ? `Instance: ${snapshot.instanceIdentifier}` : "Unknown instance"} {snapshot.createdAt ? ` · ${snapshot.createdAt}` : " · No creation timestamp"} {snapshot.engine ? ` · ${snapshot.engine}` : ""} {snapshot.version ? ` (${snapshot.version})` : ""}
{snapshot.status ?? "unknown"}
))}
)}
); }