diff --git a/apps/client/app/api-client/types.gen.ts b/apps/client/app/api-client/types.gen.ts
index f7366ea..eade818 100644
--- a/apps/client/app/api-client/types.gen.ts
+++ b/apps/client/app/api-client/types.gen.ts
@@ -13,7 +13,7 @@ export type ListVolumesResponses = {
*/
200: {
volumes: Array<{
- autoRemount: 0 | 1;
+ autoRemount: boolean;
config:
| {
backend: "directory";
@@ -209,7 +209,7 @@ export type GetVolumeResponses = {
used: number;
};
volume: {
- autoRemount: 0 | 1;
+ autoRemount: boolean;
config:
| {
backend: "directory";
diff --git a/apps/client/app/components/onoff.tsx b/apps/client/app/components/onoff.tsx
new file mode 100644
index 0000000..90089fd
--- /dev/null
+++ b/apps/client/app/components/onoff.tsx
@@ -0,0 +1,25 @@
+import { cn } from "~/lib/utils";
+import { Switch } from "./ui/switch";
+
+type Props = {
+ isOn: boolean;
+ toggle: (v: boolean) => void;
+ enabledLabel: string;
+ disabledLabel: string;
+};
+
+export const OnOff = ({ isOn, toggle, enabledLabel, disabledLabel }: Props) => {
+ return (
+
+ {isOn ? enabledLabel : disabledLabel}
+
+
+ );
+};
diff --git a/apps/client/app/components/ui/switch.tsx b/apps/client/app/components/ui/switch.tsx
index a9cecb6..02392c0 100644
--- a/apps/client/app/components/ui/switch.tsx
+++ b/apps/client/app/components/ui/switch.tsx
@@ -1,29 +1,26 @@
-import * as React from "react"
-import * as SwitchPrimitive from "@radix-ui/react-switch"
+import * as SwitchPrimitive from "@radix-ui/react-switch";
+import type * as React from "react";
-import { cn } from "~/lib/utils"
+import { cn } from "~/lib/utils";
-function Switch({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
+function Switch({ className, ...props }: React.ComponentProps) {
+ return (
+
+
+
+ );
}
-export { Switch }
+export { Switch };
diff --git a/apps/client/app/modules/details/components/healthchecks-card.tsx b/apps/client/app/modules/details/components/healthchecks-card.tsx
index 616f4c4..0ef7329 100644
--- a/apps/client/app/modules/details/components/healthchecks-card.tsx
+++ b/apps/client/app/modules/details/components/healthchecks-card.tsx
@@ -1,10 +1,9 @@
import { formatDistanceToNow } from "date-fns";
import { HeartIcon } from "lucide-react";
+import { OnOff } from "~/components/onoff";
import { Button } from "~/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
-import { Switch } from "~/components/ui/switch";
import type { Volume } from "~/lib/types";
-import { cn } from "~/lib/utils";
type Props = {
volume: Volume;
@@ -34,17 +33,7 @@ export const HealthchecksCard = ({ volume }: Props) => {
Remount on error
-
- {volume.autoRemount ? "Enabled" : "Paused"}
- {}} />
-
+ {}} enabledLabel="Enabled" disabledLabel="Paused" />
{volume.status !== "unmounted" && (
diff --git a/apps/client/app/modules/details/tabs/backups.tsx b/apps/client/app/modules/details/tabs/backups.tsx
index 1720b56..8c7c921 100644
--- a/apps/client/app/modules/details/tabs/backups.tsx
+++ b/apps/client/app/modules/details/tabs/backups.tsx
@@ -1,5 +1,6 @@
import { useMemo } from "react";
import { useForm } from "react-hook-form";
+import { OnOff } from "~/components/onoff";
import { Button } from "~/components/ui/button";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "~/components/ui/card";
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "~/components/ui/form";
@@ -152,17 +153,12 @@ export const VolumeBackupsTabContent = ({ volume }: Props) => {
render={({ field }) => (
-
- {field.value ? "Enabled" : "Paused"}
-
-
+
)}
diff --git a/apps/client/app/modules/details/tabs/docker.tsx b/apps/client/app/modules/details/tabs/docker.tsx
index 4af2c2a..bfbfc29 100644
--- a/apps/client/app/modules/details/tabs/docker.tsx
+++ b/apps/client/app/modules/details/tabs/docker.tsx
@@ -5,6 +5,7 @@ import { CodeBlock } from "~/components/ui/code-block";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/components/ui/table";
import type { Volume } from "~/lib/types";
import { getContainersUsingVolumeOptions } from "../../../api-client/@tanstack/react-query.gen";
+import { Unplug } from "lucide-react";
type Props = {
volume: Volume;
@@ -78,39 +79,44 @@ export const DockerTabContent = ({ volume }: Props) => {
List of Docker containers mounting this volume.
-
+
{isLoading && Loading containers...
}
{error && Failed to load containers: {String(error)}
}
{!isLoading && !error && containers.length === 0 && (
- No containers are currently using this volume.
+
+
+
No Docker containers are currently using this volume.
+
)}
{!isLoading && !error && containers.length > 0 && (
-
-
-
- Name
- ID
- State
- Image
-
-
-
- {containers.map((container) => (
-
- {container.name}
- {container.id.slice(0, 12)}
-
-
- {container.state}
-
-
- {container.image}
+
+
+
+
+ Name
+ ID
+ State
+ Image
- ))}
-
-
+
+
+ {containers.map((container) => (
+
+ {container.name}
+ {container.id.slice(0, 12)}
+
+
+ {container.state}
+
+
+ {container.image}
+
+ ))}
+
+
+
)}
diff --git a/apps/server/drizzle/0004_wealthy_tomas.sql b/apps/server/drizzle/0004_wealthy_tomas.sql
new file mode 100644
index 0000000..b99a187
--- /dev/null
+++ b/apps/server/drizzle/0004_wealthy_tomas.sql
@@ -0,0 +1,20 @@
+PRAGMA foreign_keys=OFF;--> statement-breakpoint
+CREATE TABLE `__new_volumes_table` (
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
+ `name` text NOT NULL,
+ `path` text NOT NULL,
+ `type` text NOT NULL,
+ `status` text DEFAULT 'unmounted' NOT NULL,
+ `last_error` text,
+ `last_health_check` integer DEFAULT (unixepoch()) NOT NULL,
+ `created_at` integer DEFAULT (unixepoch()) NOT NULL,
+ `updated_at` integer DEFAULT (unixepoch()) NOT NULL,
+ `config` text NOT NULL,
+ `auto_remount` integer DEFAULT true NOT NULL
+);
+--> statement-breakpoint
+INSERT INTO `__new_volumes_table`("id", "name", "path", "type", "status", "last_error", "last_health_check", "created_at", "updated_at", "config", "auto_remount") SELECT "id", "name", "path", "type", "status", "last_error", "last_health_check", "created_at", "updated_at", "config", "auto_remount" FROM `volumes_table`;--> statement-breakpoint
+DROP TABLE `volumes_table`;--> statement-breakpoint
+ALTER TABLE `__new_volumes_table` RENAME TO `volumes_table`;--> statement-breakpoint
+PRAGMA foreign_keys=ON;--> statement-breakpoint
+CREATE UNIQUE INDEX `volumes_table_name_unique` ON `volumes_table` (`name`);
\ No newline at end of file
diff --git a/apps/server/drizzle/meta/0004_snapshot.json b/apps/server/drizzle/meta/0004_snapshot.json
new file mode 100644
index 0000000..4aa90ca
--- /dev/null
+++ b/apps/server/drizzle/meta/0004_snapshot.json
@@ -0,0 +1,118 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "0b087a68-fbc6-4647-a6dc-e6322a3d4ee3",
+ "prevId": "b7f1ccb8-7bb3-486f-a103-b95b331a121f",
+ "tables": {
+ "volumes_table": {
+ "name": "volumes_table",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "path": {
+ "name": "path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'unmounted'"
+ },
+ "last_error": {
+ "name": "last_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_health_check": {
+ "name": "last_health_check",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch())"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch())"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "(unixepoch())"
+ },
+ "config": {
+ "name": "config",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "auto_remount": {
+ "name": "auto_remount",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": true
+ }
+ },
+ "indexes": {
+ "volumes_table_name_unique": {
+ "name": "volumes_table_name_unique",
+ "columns": [
+ "name"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/apps/server/drizzle/meta/_journal.json b/apps/server/drizzle/meta/_journal.json
index 5664a51..ecb66bb 100644
--- a/apps/server/drizzle/meta/_journal.json
+++ b/apps/server/drizzle/meta/_journal.json
@@ -29,6 +29,13 @@
"when": 1758653407064,
"tag": "0003_mature_hellcat",
"breakpoints": true
+ },
+ {
+ "idx": 4,
+ "version": "6",
+ "when": 1758961535488,
+ "tag": "0004_wealthy_tomas",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/apps/server/src/db/schema.ts b/apps/server/src/db/schema.ts
index 833e92e..8918f18 100644
--- a/apps/server/src/db/schema.ts
+++ b/apps/server/src/db/schema.ts
@@ -13,7 +13,7 @@ export const volumesTable = sqliteTable("volumes_table", {
createdAt: int("created_at", { mode: "timestamp" }).notNull().default(sql`(unixepoch())`),
updatedAt: int("updated_at", { mode: "timestamp" }).notNull().default(sql`(unixepoch())`),
config: text("config", { mode: "json" }).$type().notNull(),
- autoRemount: int("auto_remount").$type<1 | 0>().notNull().default(1),
+ autoRemount: int("auto_remount", { mode: "boolean" }).notNull().default(true),
});
export type Volume = typeof volumesTable.$inferSelect;
diff --git a/apps/server/src/modules/volumes/volume.dto.ts b/apps/server/src/modules/volumes/volume.dto.ts
index bf015a3..7cf29f4 100644
--- a/apps/server/src/modules/volumes/volume.dto.ts
+++ b/apps/server/src/modules/volumes/volume.dto.ts
@@ -13,7 +13,7 @@ const volumeSchema = type({
updatedAt: "number",
lastHealthCheck: "number",
config: volumeConfigSchema,
- autoRemount: "0 | 1",
+ autoRemount: "boolean",
});
export type VolumeDto = typeof volumeSchema.infer;
diff --git a/apps/server/src/modules/volumes/volume.service.ts b/apps/server/src/modules/volumes/volume.service.ts
index f9633d6..ea16f53 100644
--- a/apps/server/src/modules/volumes/volume.service.ts
+++ b/apps/server/src/modules/volumes/volume.service.ts
@@ -155,7 +155,7 @@ const testConnection = async (backendConfig: BackendConfig) => {
type: backendConfig.backend,
status: "unmounted" as const,
lastError: null,
- autoRemount: 0 as const,
+ autoRemount: true,
};
const backend = createVolumeBackend(mockVolume);