diff --git a/apps/client/app/modules/repositories/routes/repository-details.tsx b/apps/client/app/modules/repositories/routes/repository-details.tsx index dc15d17..c2cf51a 100644 --- a/apps/client/app/modules/repositories/routes/repository-details.tsx +++ b/apps/client/app/modules/repositories/routes/repository-details.tsx @@ -1,9 +1,10 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { useNavigate, useParams, useSearchParams } from "react-router"; +import { redirect, useNavigate, useSearchParams } from "react-router"; import { toast } from "sonner"; import { useState, useEffect } from "react"; import { deleteRepositoryMutation, + doctorRepositoryMutation, getRepositoryOptions, listSnapshotsOptions, } from "~/api-client/@tanstack/react-query.gen"; @@ -24,6 +25,7 @@ import { cn } from "~/lib/utils"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; import { RepositoryInfoTabContent } from "../tabs/info"; import { RepositorySnapshotsTabContent } from "../tabs/snapshots"; +import { Loader2 } from "lucide-react"; export function meta({ params }: Route.MetaArgs) { return [ @@ -38,10 +40,13 @@ export function meta({ params }: Route.MetaArgs) { export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => { const repository = await getRepository({ path: { name: params.name ?? "" } }); if (repository.data) return repository.data; + + return redirect("/repositories"); }; export default function RepositoryDetailsPage({ loaderData }: Route.ComponentProps) { - const { name } = useParams<{ name: string }>(); + const [showDoctorResults, setShowDoctorResults] = useState(false); + const navigate = useNavigate(); const queryClient = useQueryClient(); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); @@ -50,17 +55,15 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro const activeTab = searchParams.get("tab") || "info"; const { data } = useQuery({ - ...getRepositoryOptions({ path: { name: name ?? "" } }), + ...getRepositoryOptions({ path: { name: loaderData.name } }), initialData: loaderData, refetchInterval: 10000, refetchOnWindowFocus: true, }); useEffect(() => { - if (name) { - queryClient.prefetchQuery(listSnapshotsOptions({ path: { name } })); - } - }, [name, queryClient]); + queryClient.prefetchQuery(listSnapshotsOptions({ path: { name: data.name } })); + }, [queryClient, data.name]); const deleteRepo = useMutation({ ...deleteRepositoryMutation(), @@ -75,18 +78,48 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro }, }); + const doctorMutation = useMutation({ + ...doctorRepositoryMutation(), + onSuccess: (data) => { + if (data) { + setShowDoctorResults(true); + + if (data.success) { + toast.success("Repository doctor completed successfully"); + } else { + toast.warning("Doctor completed with some issues", { + description: "Check the details for more information", + richColors: true, + }); + } + } + }, + onError: (error) => { + toast.error("Failed to run doctor", { + description: parseError(error)?.message, + }); + }, + }); + const handleConfirmDelete = () => { setShowDeleteConfirm(false); - deleteRepo.mutate({ path: { name: name ?? "" } }); + deleteRepo.mutate({ path: { name: data.name } }); }; - if (!name) { - return
Repository not found
; - } - - if (!data) { - return
Loading...
; - } + const getStepLabel = (step: string) => { + switch (step) { + case "unlock": + return "Unlock Repository"; + case "check": + return "Check Repository"; + case "repair_index": + return "Repair Index"; + case "recheck": + return "Re-check Repository"; + default: + return step; + } + }; return ( <> @@ -103,6 +136,20 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro {data.type}
+ @@ -127,8 +174,8 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro Delete repository? - Are you sure you want to delete the repository {name}? This action cannot be undone and - will remove all backup data. + Are you sure you want to delete the repository {data.name}? This action cannot be undone + and will remove all backup data.
@@ -142,6 +189,46 @@ export default function RepositoryDetailsPage({ loaderData }: Route.ComponentPro
+ + + + + Doctor Results + Repository doctor operation completed + + + {doctorMutation.data && ( +
+ {doctorMutation.data.steps.map((step) => ( +
+
+ {getStepLabel(step.step)} + + {step.success ? "Success" : "Warning"} + +
+ {step.error &&

{step.error}

} +
+ ))} +
+ )} + +
+ +
+
+
); } diff --git a/apps/client/app/modules/repositories/tabs/info.tsx b/apps/client/app/modules/repositories/tabs/info.tsx index 0dd3f42..d2d8507 100644 --- a/apps/client/app/modules/repositories/tabs/info.tsx +++ b/apps/client/app/modules/repositories/tabs/info.tsx @@ -1,175 +1,63 @@ -import { useMutation } from "@tanstack/react-query"; -import { useState } from "react"; -import { toast } from "sonner"; import { Card } from "~/components/ui/card"; -import { Button } from "~/components/ui/button"; -import { - AlertDialog, - AlertDialogContent, - AlertDialogDescription, - AlertDialogHeader, - AlertDialogTitle, -} from "~/components/ui/alert-dialog"; -import { Loader2 } from "lucide-react"; import type { Repository } from "~/lib/types"; -import { parseError } from "~/lib/errors"; -import { doctorRepositoryMutation } from "~/api-client/@tanstack/react-query.gen"; -import { cn } from "~/lib/utils"; type Props = { repository: Repository; }; export const RepositoryInfoTabContent = ({ repository }: Props) => { - const [showDoctorResults, setShowDoctorResults] = useState(false); - - const doctorMutation = useMutation({ - ...doctorRepositoryMutation(), - onSuccess: (data) => { - if (data) { - setShowDoctorResults(true); - - if (data.success) { - toast.success("Repository doctor completed successfully"); - } else { - toast.warning("Doctor completed with some issues", { - description: "Check the details for more information", - richColors: true, - }); - } - } - }, - onError: (error) => { - toast.error("Failed to run doctor", { - description: parseError(error)?.message, - }); - }, - }); - - const handleDoctor = () => { - doctorMutation.mutate({ path: { name: repository.name } }); - }; - - const getStepLabel = (step: string) => { - switch (step) { - case "unlock": - return "Unlock Repository"; - case "check": - return "Check Repository"; - case "repair_index": - return "Repair Index"; - case "recheck": - return "Re-check Repository"; - default: - return step; - } - }; - 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 && ( + +
+
+

Repository Information

+
-
-

Last Error

- -
-
-

{repository.lastError}

-
+
Name
+

{repository.name}

- )} - -
-

Configuration

-
-
{JSON.stringify(repository.config, null, 2)}
+
+
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"} +

- - - - - - Doctor Results - Repository doctor operation completed - - - {doctorMutation.data && ( -
- {doctorMutation.data.steps.map((step) => ( -
-
- {getStepLabel(step.step)} - - {step.success ? "Success" : "Warning"} - -
- {step.error &&

{step.error}

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

Last Error

- )} -
- +
+

{repository.lastError}

+
- - - + )} +
+

Configuration

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