Paths:
- {data.snapshot.paths.slice(0, showAllPaths ? undefined : 20).map((path) => (
+ {data.paths.slice(0, showAllPaths ? undefined : 20).map((path) => (
{path}
))}
- {data.snapshot.paths.length > 20 && (
+ {data.paths.length > 20 && (
)}
diff --git a/app/client/modules/repositories/tabs/info.tsx b/app/client/modules/repositories/tabs/info.tsx
index f71572a1..41c1c66a 100644
--- a/app/client/modules/repositories/tabs/info.tsx
+++ b/app/client/modules/repositories/tabs/info.tsx
@@ -30,7 +30,7 @@ import {
import type { CompressionMode, RepositoryConfig } from "~/schemas/restic";
import { DoctorReport } from "../components/doctor-report";
import { parseError } from "~/client/lib/errors";
-import { useNavigate } from "react-router";
+import { useNavigate } from "@tanstack/react-router";
type Props = {
repository: Repository;
@@ -73,7 +73,7 @@ export const RepositoryInfoTabContent = ({ repository }: Props) => {
...deleteRepositoryMutation(),
onSuccess: () => {
toast.success("Repository deleted successfully");
- void navigate("/repositories");
+ void navigate({ to: "/repositories" });
},
onError: (error) => {
toast.error("Failed to delete repository", {
@@ -115,7 +115,7 @@ export const RepositoryInfoTabContent = ({ repository }: Props) => {
},
});
- const handleSubmit = (e: React.FormEvent) => {
+ const handleSubmit = (e: React.SubmitEvent) => {
e.preventDefault();
setShowConfirmDialog(true);
};
diff --git a/app/client/modules/settings/routes/settings.tsx b/app/client/modules/settings/routes/settings.tsx
index 21832daa..d46d2360 100644
--- a/app/client/modules/settings/routes/settings.tsx
+++ b/app/client/modules/settings/routes/settings.tsx
@@ -1,7 +1,6 @@
import { useMutation, useQuery } from "@tanstack/react-query";
import { Download, KeyRound, User, X, Users, Settings as SettingsIcon } from "lucide-react";
import { useState } from "react";
-import { useNavigate, useSearchParams } from "react-router";
import { toast } from "sonner";
import {
downloadResticPasswordMutation,
@@ -24,31 +23,16 @@ import { Label } from "~/client/components/ui/label";
import { Switch } from "~/client/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
import { authClient } from "~/client/lib/auth-client";
-import { appContext } from "~/context";
+import { type AppContext } from "~/context";
import { TwoFactorSection } from "../components/two-factor-section";
import { UserManagement } from "../components/user-management";
-import type { Route } from "./+types/settings";
+import { useNavigate, useSearch } from "@tanstack/react-router";
-export const handle = {
- breadcrumb: () => [{ label: "Settings" }],
+type Props = {
+ appContext: AppContext;
};
-export function meta(_: Route.MetaArgs) {
- return [
- { title: "Zerobyte - Settings" },
- {
- name: "description",
- content: "Manage your account settings and preferences.",
- },
- ];
-}
-
-export async function clientLoader({ context }: Route.LoaderArgs) {
- const ctx = context.get(appContext);
- return ctx;
-}
-
-export default function Settings({ loaderData }: Route.ComponentProps) {
+export function SettingsPage({ appContext }: Props) {
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
@@ -56,11 +40,11 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
const [downloadPassword, setDownloadPassword] = useState("");
const [isChangingPassword, setIsChangingPassword] = useState(false);
- const [searchParams, setSearchParams] = useSearchParams();
- const activeTab = searchParams.get("tab") || "account";
+ const { tab } = useSearch({ from: "/(dashboard)/settings/" });
+ const activeTab = tab || "account";
const navigate = useNavigate();
- const isAdmin = loaderData.user?.role === "admin";
+ const isAdmin = appContext.user?.role === "admin";
const registrationStatusQuery = useQuery({
...getRegistrationStatusOptions(),
@@ -84,7 +68,7 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
await authClient.signOut({
fetchOptions: {
onSuccess: () => {
- void navigate("/login", { replace: true });
+ void navigate({ to: "/login", replace: true });
},
onError: ({ error }) => {
console.error(error);
@@ -118,7 +102,7 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
},
});
- const handleChangePassword = async (e: React.FormEvent) => {
+ const handleChangePassword = async (e: React.SubmitEvent) => {
e.preventDefault();
if (newPassword !== confirmPassword) {
@@ -157,7 +141,7 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
});
};
- const handleDownloadResticPassword = (e: React.FormEvent) => {
+ const handleDownloadResticPassword = (e: React.SubmitEvent) => {
e.preventDefault();
if (!downloadPassword) {
@@ -173,7 +157,7 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
};
const onTabChange = (value: string) => {
- setSearchParams({ tab: value });
+ void navigate({ to: ".", search: () => ({ tab: value }) });
};
return (
@@ -198,7 +182,7 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
-
+
@@ -318,7 +302,7 @@ export default function Settings({ loaderData }: Route.ComponentProps) {
-
+
diff --git a/app/client/modules/volumes/routes/create-volume.tsx b/app/client/modules/volumes/routes/create-volume.tsx
index 8d5bbaca..a6bb98c2 100644
--- a/app/client/modules/volumes/routes/create-volume.tsx
+++ b/app/client/modules/volumes/routes/create-volume.tsx
@@ -1,31 +1,16 @@
import { useMutation } from "@tanstack/react-query";
import { HardDrive, Plus } from "lucide-react";
import { useId } from "react";
-import { useNavigate } from "react-router";
import { toast } from "sonner";
import { createVolumeMutation } from "~/client/api-client/@tanstack/react-query.gen";
import { CreateVolumeForm, type FormValues } from "~/client/modules/volumes/components/create-volume-form";
import { Button } from "~/client/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "~/client/components/ui/card";
import { parseError } from "~/client/lib/errors";
-import type { Route } from "./+types/create-volume";
import { Alert, AlertDescription } from "~/client/components/ui/alert";
+import { useNavigate } from "@tanstack/react-router";
-export const handle = {
- breadcrumb: () => [{ label: "Volumes", href: "/volumes" }, { label: "Create" }],
-};
-
-export function meta(_: Route.MetaArgs) {
- return [
- { title: "Zerobyte - Create Volume" },
- {
- name: "description",
- content: "Create a new storage volume with automatic mounting and health checks.",
- },
- ];
-}
-
-export default function CreateVolume() {
+export function CreateVolumePage() {
const navigate = useNavigate();
const formId = useId();
@@ -33,7 +18,7 @@ export default function CreateVolume() {
...createVolumeMutation(),
onSuccess: (data) => {
toast.success("Volume created successfully");
- void navigate(`/volumes/${data.shortId}`);
+ void navigate({ to: `/volumes/${data.shortId}` });
},
});
@@ -69,7 +54,7 @@ export default function CreateVolume() {
)}
-
mountVol.mutate({ path: { id } })}
+ onClick={() => mountVol.mutate({ path: { id: volumeId } })}
loading={mountVol.isPending}
className={cn({ hidden: volume.status === "mounted" })}
>
@@ -148,7 +129,7 @@ export default function VolumeDetails({ loaderData }: Route.ComponentProps) {
unmountVol.mutate({ path: { id } })}
+ onClick={() => unmountVol.mutate({ path: { id: volumeId } })}
loading={unmountVol.isPending}
className={cn({ hidden: volume.status !== "mounted" })}
>
@@ -160,7 +141,11 @@ export default function VolumeDetails({ loaderData }: Route.ComponentProps) {
-