diff --git a/apps/client/app/components/create-volume-form.tsx b/apps/client/app/components/create-volume-form.tsx index dc2b80e..2f0e138 100644 --- a/apps/client/app/components/create-volume-form.tsx +++ b/apps/client/app/components/create-volume-form.tsx @@ -450,7 +450,7 @@ export const CreateVolumeForm = ({ onSubmit, mode = "create", initialValues, for {testMessage && (
{mode === "update" && ( - )} diff --git a/apps/client/app/components/empty-state.tsx b/apps/client/app/components/empty-state.tsx new file mode 100644 index 0000000..2cf983c --- /dev/null +++ b/apps/client/app/components/empty-state.tsx @@ -0,0 +1,56 @@ +import { Database, HardDrive, HeartPulse, Plus } from "lucide-react"; +import { CreateVolumeDialog } from "./create-volume-dialog"; +import { useState } from "react"; + +export function EmptyState() { + const [createVolumeOpen, setCreateVolumeOpen] = useState(false); + + return ( +
+
+
+
+
+ +
+ +
+
+ +
+

No volumes yet

+

+ Get started by creating your first volume. Manage and monitor all your storage backends in one place with + advanced features like automatic mounting and health checks. +

+
+ + +
+
+
+ +
+

Multiple Backends

+

Support for local, NFS, and SMB storage

+
+ +
+
+ +
+

Auto Mounting

+

Automatic lifecycle management

+
+ +
+
+ +
+

Real-time Monitoring

+

Live status and health checks

+
+
+
+ ); +} diff --git a/apps/client/app/routes/home.tsx b/apps/client/app/routes/home.tsx index 0ab88ab..92070a5 100644 --- a/apps/client/app/routes/home.tsx +++ b/apps/client/app/routes/home.tsx @@ -5,6 +5,7 @@ import { useNavigate } from "react-router"; import { listVolumes } from "~/api-client"; import { listVolumesOptions } from "~/api-client/@tanstack/react-query.gen"; import { CreateVolumeDialog } from "~/components/create-volume-dialog"; +import { EmptyState } from "~/components/empty-state"; import { StatusDot } from "~/components/status-dot"; import { Button } from "~/components/ui/button"; import { Card } from "~/components/ui/card"; @@ -59,6 +60,17 @@ export default function Home({ loaderData }: Route.ComponentProps) { return matchesSearch && matchesStatus && matchesBackend; }) || []; + const hasNoVolumes = data?.volumes.length === 0; + const hasNoFilteredVolumes = filteredVolumes.length === 0 && !hasNoVolumes; + + if (hasNoVolumes) { + return ( + + + + ); + } + return (
@@ -109,35 +121,49 @@ export default function Home({ loaderData }: Route.ComponentProps) { - {filteredVolumes.map((volume) => ( - navigate(`/volumes/${volume.name}`)} - > - {volume.name} - - - - - - - {volume.path} - - - - - - + {hasNoFilteredVolumes ? ( + + +
+

No volumes match your filters.

+ +
- ))} + ) : ( + filteredVolumes.map((volume) => ( + navigate(`/volumes/${volume.name}`)} + > + {volume.name} + + + + + + + {volume.path} + + + + + + + + + )) + )}
- {filteredVolumes.length === 0 ? ( - "No volumes found." + {hasNoFilteredVolumes ? ( + "No volumes match filters." ) : ( {filteredVolumes.length} volume