From 0dfe000148c9b59f472b1d121a7ca3c393331ccd Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Fri, 28 Nov 2025 20:47:27 +0100 Subject: [PATCH] feat: rename volumes & repositories --- .../components/create-repository-form.tsx | 2 - app/client/components/create-volume-form.tsx | 2 - .../components/create-notification-form.tsx | 2 - app/client/modules/repositories/tabs/info.tsx | 205 +++++++++++++----- app/client/modules/volumes/tabs/info.tsx | 12 +- 5 files changed, 166 insertions(+), 57 deletions(-) diff --git a/app/client/components/create-repository-form.tsx b/app/client/components/create-repository-form.tsx index 1685c8e..255dd7a 100644 --- a/app/client/components/create-repository-form.tsx +++ b/app/client/components/create-repository-form.tsx @@ -115,8 +115,6 @@ export const CreateRepositoryForm = ({ onChange={(e) => field.onChange(slugify(e.target.value))} max={32} min={2} - disabled={mode === "update"} - className={mode === "update" ? "bg-gray-50" : ""} /> Unique identifier for the repository. diff --git a/app/client/components/create-volume-form.tsx b/app/client/components/create-volume-form.tsx index 669bd2e..a4fa692 100644 --- a/app/client/components/create-volume-form.tsx +++ b/app/client/components/create-volume-form.tsx @@ -104,8 +104,6 @@ export const CreateVolumeForm = ({ onSubmit, mode = "create", initialValues, for onChange={(e) => field.onChange(slugify(e.target.value))} max={32} min={1} - disabled={mode === "update"} - className={mode === "update" ? "bg-gray-50" : ""} /> Unique identifier for the volume. diff --git a/app/client/modules/notifications/components/create-notification-form.tsx b/app/client/modules/notifications/components/create-notification-form.tsx index 7f97e59..ee05948 100644 --- a/app/client/modules/notifications/components/create-notification-form.tsx +++ b/app/client/modules/notifications/components/create-notification-form.tsx @@ -114,8 +114,6 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue onChange={(e) => field.onChange(slugify(e.target.value))} max={32} min={2} - disabled={mode === "update"} - className={mode === "update" ? "bg-gray-50" : ""} /> Unique identifier for this notification destination. diff --git a/app/client/modules/repositories/tabs/info.tsx b/app/client/modules/repositories/tabs/info.tsx index afb096f..4b4a652 100644 --- a/app/client/modules/repositories/tabs/info.tsx +++ b/app/client/modules/repositories/tabs/info.tsx @@ -1,63 +1,170 @@ +import { useMutation } from "@tanstack/react-query"; +import { useState } from "react"; +import { toast } from "sonner"; +import { useNavigate } from "react-router"; import { Card } from "~/client/components/ui/card"; +import { Button } from "~/client/components/ui/button"; +import { Input } from "~/client/components/ui/input"; +import { Label } from "~/client/components/ui/label"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "~/client/components/ui/alert-dialog"; import type { Repository } from "~/client/lib/types"; +import { slugify } from "~/client/lib/utils"; +import { updateRepositoryMutation } from "~/client/api-client/@tanstack/react-query.gen"; +import type { UpdateRepositoryResponse } from "~/client/api-client/types.gen"; + +type CompressionMode = "off" | "auto" | "fastest" | "better" | "max"; type Props = { repository: Repository; }; export const RepositoryInfoTabContent = ({ repository }: Props) => { - return ( - -
-
-

Repository Information

-
-
-
Name
-

{repository.name}

-
-
-
Backend
-

{repository.type}

-
-
-
Compression Mode
-

{repository.compressionMode || "off"}

-
-
-
Status
-

{repository.status || "unknown"}

-
-
-
Created At
-

{new Date(repository.createdAt).toLocaleString()}

-
-
-
Last Checked
-

- {repository.lastChecked ? new Date(repository.lastChecked).toLocaleString() : "Never"} -

-
-
-
- {repository.lastError && ( -
-
-

Last Error

-
+ const navigate = useNavigate(); + const [name, setName] = useState(repository.name); + const [compressionMode, setCompressionMode] = useState( + (repository.compressionMode as CompressionMode) || "off", + ); + const [showConfirmDialog, setShowConfirmDialog] = useState(false); -
-

{repository.lastError}

+ const updateMutation = useMutation({ + ...updateRepositoryMutation(), + onSuccess: (data: UpdateRepositoryResponse) => { + toast.success("Repository updated successfully"); + setShowConfirmDialog(false); + + if (data.name !== repository.name) { + navigate(`/repositories/${data.name}`); + } + }, + onError: (error) => { + toast.error("Failed to update repository", { description: error.message, richColors: true }); + setShowConfirmDialog(false); + }, + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setShowConfirmDialog(true); + }; + + const confirmUpdate = () => { + updateMutation.mutate({ + path: { name: repository.name }, + body: { name, compressionMode }, + }); + }; + + const hasChanges = + name !== repository.name || compressionMode !== ((repository.compressionMode as CompressionMode) || "off"); + + return ( + <> + +
+
+

Repository Settings

+
+
+ + setName(slugify(e.target.value))} + placeholder="Repository name" + maxLength={32} + minLength={2} + /> +

Unique identifier for the repository.

+
+
+ + +

Compression level for new data.

+
- )} -
-

Configuration

-
-
{JSON.stringify(repository.config, null, 2)}
+ +
+

Repository Information

+
+
+
Backend
+

{repository.type}

+
+
+
Status
+

{repository.status || "unknown"}

+
+
+
Created At
+

{new Date(repository.createdAt * 1000).toLocaleString()}

+
+
+
Last Checked
+

+ {repository.lastChecked ? new Date(repository.lastChecked).toLocaleString() : "Never"} +

+
+
-
-
- + + {repository.lastError && ( +
+
+

Last Error

+
+
+

{repository.lastError}

+
+
+ )} + +
+

Configuration

+
+
{JSON.stringify(repository.config, null, 2)}
+
+
+ +
+ +
+
+
+ + + + + Update Repository + Are you sure you want to update the repository settings? + + + Cancel + Update + + + + ); }; diff --git a/app/client/modules/volumes/tabs/info.tsx b/app/client/modules/volumes/tabs/info.tsx index 5b8a451..2b21307 100644 --- a/app/client/modules/volumes/tabs/info.tsx +++ b/app/client/modules/volumes/tabs/info.tsx @@ -1,5 +1,6 @@ import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; +import { useNavigate } from "react-router"; import { toast } from "sonner"; import { CreateVolumeForm, type FormValues } from "~/client/components/create-volume-form"; import { @@ -17,6 +18,7 @@ import type { StatFs, Volume } from "~/client/lib/types"; import { HealthchecksCard } from "../components/healthchecks-card"; import { StorageChart } from "../components/storage-chart"; import { updateVolumeMutation } from "~/client/api-client/@tanstack/react-query.gen"; +import type { UpdateVolumeResponse } from "~/client/api-client/types.gen"; type Props = { volume: Volume; @@ -24,12 +26,18 @@ type Props = { }; export const VolumeInfoTabContent = ({ volume, statfs }: Props) => { + const navigate = useNavigate(); + const updateMutation = useMutation({ ...updateVolumeMutation(), - onSuccess: (_) => { + onSuccess: (data: UpdateVolumeResponse) => { toast.success("Volume updated successfully"); setOpen(false); setPendingValues(null); + + if (data.name !== volume.name) { + navigate(`/volumes/${data.name}`); + } }, onError: (error) => { toast.error("Failed to update volume", { description: error.message }); @@ -50,7 +58,7 @@ export const VolumeInfoTabContent = ({ volume, statfs }: Props) => { if (pendingValues) { updateMutation.mutate({ path: { name: volume.name }, - body: { config: pendingValues }, + body: { name: pendingValues.name, config: pendingValues }, }); } };