refactor: move api-client to client

This commit is contained in:
Nicolas Meienberger 2025-11-13 19:50:46 +01:00
parent 44c62a9c7e
commit 8eb0f24585
35 changed files with 71 additions and 71 deletions

View file

@ -2,12 +2,12 @@ import { useMutation } from "@tanstack/react-query";
import { Plus } from "lucide-react"; import { Plus } from "lucide-react";
import { useId } from "react"; import { useId } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { createRepositoryMutation } from "~/api-client/@tanstack/react-query.gen";
import { parseError } from "~/client/lib/errors"; import { parseError } from "~/client/lib/errors";
import { CreateRepositoryForm } from "./create-repository-form"; import { CreateRepositoryForm } from "./create-repository-form";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog";
import { ScrollArea } from "./ui/scroll-area"; import { ScrollArea } from "./ui/scroll-area";
import { createRepositoryMutation } from "../api-client/@tanstack/react-query.gen";
type Props = { type Props = {
open: boolean; open: boolean;

View file

@ -8,13 +8,13 @@ import { Button } from "./ui/button";
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "./ui/form"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "./ui/form";
import { Input } from "./ui/input"; import { Input } from "./ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
import { listRcloneRemotesOptions } from "~/api-client/@tanstack/react-query.gen";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { Alert, AlertDescription } from "./ui/alert"; import { Alert, AlertDescription } from "./ui/alert";
import { ExternalLink } from "lucide-react"; import { ExternalLink } from "lucide-react";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
import { useSystemInfo } from "~/client/hooks/use-system-info"; import { useSystemInfo } from "~/client/hooks/use-system-info";
import { COMPRESSION_MODES, repositoryConfigSchema } from "~/schemas/restic"; import { COMPRESSION_MODES, repositoryConfigSchema } from "~/schemas/restic";
import { listRcloneRemotesOptions } from "../api-client/@tanstack/react-query.gen";
export const formSchema = type({ export const formSchema = type({
name: "2<=string<=32", name: "2<=string<=32",

View file

@ -2,12 +2,12 @@ import { useMutation } from "@tanstack/react-query";
import { Plus } from "lucide-react"; import { Plus } from "lucide-react";
import { useId } from "react"; import { useId } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { createVolumeMutation } from "~/api-client/@tanstack/react-query.gen";
import { parseError } from "~/client/lib/errors"; import { parseError } from "~/client/lib/errors";
import { CreateVolumeForm } from "./create-volume-form"; import { CreateVolumeForm } from "./create-volume-form";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog";
import { ScrollArea } from "./ui/scroll-area"; import { ScrollArea } from "./ui/scroll-area";
import { createVolumeMutation } from "../api-client/@tanstack/react-query.gen";
type Props = { type Props = {
open: boolean; open: boolean;

View file

@ -4,7 +4,6 @@ import { type } from "arktype";
import { CheckCircle, Loader2, XCircle } from "lucide-react"; import { CheckCircle, Loader2, XCircle } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { testConnectionMutation } from "~/api-client/@tanstack/react-query.gen";
import { cn, slugify } from "~/client/lib/utils"; import { cn, slugify } from "~/client/lib/utils";
import { deepClean } from "~/utils/object"; import { deepClean } from "~/utils/object";
import { DirectoryBrowser } from "./directory-browser"; import { DirectoryBrowser } from "./directory-browser";
@ -13,6 +12,7 @@ import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, For
import { Input } from "./ui/input"; import { Input } from "./ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
import { volumeConfigSchema } from "~/schemas/volumes"; import { volumeConfigSchema } from "~/schemas/volumes";
import { testConnectionMutation } from "../api-client/@tanstack/react-query.gen";
export const formSchema = type({ export const formSchema = type({
name: "2<=string<=32", name: "2<=string<=32",

View file

@ -1,8 +1,8 @@
import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { browseFilesystemOptions } from "~/api-client/@tanstack/react-query.gen";
import { FileTree, type FileEntry } from "./file-tree"; import { FileTree, type FileEntry } from "./file-tree";
import { ScrollArea } from "./ui/scroll-area"; import { ScrollArea } from "./ui/scroll-area";
import { browseFilesystemOptions } from "../api-client/@tanstack/react-query.gen";
type Props = { type Props = {
onSelectPath: (path: string) => void; onSelectPath: (path: string) => void;

View file

@ -17,7 +17,7 @@ export function EmptyState(props: EmptyStateProps) {
<div className="absolute inset-0 animate-pulse"> <div className="absolute inset-0 animate-pulse">
<div className="w-32 h-32 rounded-full bg-primary/10 blur-2xl" /> <div className="w-32 h-32 rounded-full bg-primary/10 blur-2xl" />
</div> </div>
<div className="relative flex items-center justify-center w-32 h-32 rounded-full bg-gradient-to-br from-primary/20 to-primary/5 border-2 border-primary/20"> <div className="relative flex items-center justify-center w-32 h-32 rounded-full bg-linear-to-br from-primary/20 to-primary/5 border-2 border-primary/20">
<Cicon className="w-16 h-16 text-primary/70" strokeWidth={1.5} /> <Cicon className="w-16 h-16 text-primary/70" strokeWidth={1.5} />
</div> </div>
</div> </div>

View file

@ -12,9 +12,9 @@ export function GridBackground({ children, className, containerClassName }: Grid
<div <div
className={cn( className={cn(
"relative min-h-full w-full overflow-x-hidden", "relative min-h-full w-full overflow-x-hidden",
"[background-size:20px_20px] sm:[background-size:40px_40px]", "bg-size-[20px_20px] sm:bg-size-[40px_40px]",
"[background-image:linear-gradient(to_right,#e4e4e7_1px,transparent_1px),linear-gradient(to_bottom,#e4e4e7_1px,transparent_1px)]", "bg-[linear-gradient(to_right,#e4e4e7_1px,transparent_1px),linear-gradient(to_bottom,#e4e4e7_1px,transparent_1px)]",
"dark:[background-image:linear-gradient(to_right,#262626_1px,transparent_1px),linear-gradient(to_bottom,#262626_1px,transparent_1px)]", "dark:bg-[linear-gradient(to_right,#262626_1px,transparent_1px),linear-gradient(to_bottom,#262626_1px,transparent_1px)]",
containerClassName, containerClassName,
)} )}
> >

View file

@ -2,7 +2,6 @@ import { useMutation } from "@tanstack/react-query";
import { LifeBuoy } from "lucide-react"; import { LifeBuoy } from "lucide-react";
import { Outlet, redirect, useNavigate } from "react-router"; import { Outlet, redirect, useNavigate } from "react-router";
import { toast } from "sonner"; import { toast } from "sonner";
import { logoutMutation } from "~/api-client/@tanstack/react-query.gen";
import { appContext } from "~/context"; import { appContext } from "~/context";
import { authMiddleware } from "~/middleware/auth"; import { authMiddleware } from "~/middleware/auth";
import type { Route } from "./+types/layout"; import type { Route } from "./+types/layout";
@ -11,6 +10,7 @@ import { GridBackground } from "./grid-background";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { SidebarProvider, SidebarTrigger } from "./ui/sidebar"; import { SidebarProvider, SidebarTrigger } from "./ui/sidebar";
import { AppSidebar } from "./app-sidebar"; import { AppSidebar } from "./app-sidebar";
import { logoutMutation } from "../api-client/@tanstack/react-query.gen";
export const clientMiddleware = [authMiddleware]; export const clientMiddleware = [authMiddleware];
@ -42,7 +42,7 @@ export default function Layout({ loaderData }: Route.ComponentProps) {
<SidebarProvider defaultOpen={true}> <SidebarProvider defaultOpen={true}>
<AppSidebar /> <AppSidebar />
<div className="w-full relative flex flex-col h-screen overflow-hidden"> <div className="w-full relative flex flex-col h-screen overflow-hidden">
<header className="z-50 bg-card-header border-b border-border/50 flex-shrink-0"> <header className="z-50 bg-card-header border-b border-border/50 shrink-0">
<div className="flex items-center justify-between py-3 sm:py-4 px-2 sm:px-8 mx-auto container"> <div className="flex items-center justify-between py-3 sm:py-4 px-2 sm:px-8 mx-auto container">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<SidebarTrigger /> <SidebarTrigger />

View file

@ -1,10 +1,10 @@
import { Calendar, Clock, Database, FolderTree, HardDrive } from "lucide-react"; import { Calendar, Clock, Database, FolderTree, HardDrive } from "lucide-react";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import type { ListSnapshotsResponse } from "~/api-client/types.gen";
import { ByteSize } from "~/client/components/bytes-size"; import { ByteSize } from "~/client/components/bytes-size";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table";
import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip";
import { formatDuration } from "~/utils/utils"; import { formatDuration } from "~/utils/utils";
import type { ListSnapshotsResponse } from "../api-client";
type Snapshot = ListSnapshotsResponse[number]; type Snapshot = ListSnapshotsResponse[number];

View file

@ -1,8 +1,8 @@
import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import { FolderOpen } from "lucide-react"; import { FolderOpen } from "lucide-react";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { listFilesOptions } from "~/api-client/@tanstack/react-query.gen";
import { FileTree } from "~/client/components/file-tree"; import { FileTree } from "~/client/components/file-tree";
import { listFilesOptions } from "../api-client/@tanstack/react-query.gen";
interface FileEntry { interface FileEntry {
name: string; name: string;

View file

@ -1,5 +1,5 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { getSystemInfoOptions } from "~/api-client/@tanstack/react-query.gen"; import { getSystemInfoOptions } from "../api-client/@tanstack/react-query.gen";
export function useSystemInfo() { export function useSystemInfo() {
const { data, isLoading, error } = useQuery({ const { data, isLoading, error } = useQuery({

View file

@ -4,7 +4,7 @@ import type {
GetRepositoryResponse, GetRepositoryResponse,
GetVolumeResponse, GetVolumeResponse,
ListSnapshotsResponse, ListSnapshotsResponse,
} from "~/api-client"; } from "../api-client";
export type Volume = GetVolumeResponse["volume"]; export type Volume = GetVolumeResponse["volume"];
export type StatFs = GetVolumeResponse["statfs"]; export type StatFs = GetVolumeResponse["statfs"];

View file

@ -3,7 +3,6 @@ import { AlertTriangle, Download } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { toast } from "sonner"; import { toast } from "sonner";
import { downloadResticPasswordMutation } from "~/api-client/@tanstack/react-query.gen";
import { AuthLayout } from "~/client/components/auth-layout"; import { AuthLayout } from "~/client/components/auth-layout";
import { Alert, AlertDescription, AlertTitle } from "~/client/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "~/client/components/ui/alert";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
@ -11,6 +10,7 @@ import { Input } from "~/client/components/ui/input";
import { Label } from "~/client/components/ui/label"; import { Label } from "~/client/components/ui/label";
import { authMiddleware } from "~/middleware/auth"; import { authMiddleware } from "~/middleware/auth";
import type { Route } from "./+types/download-recovery-key"; import type { Route } from "./+types/download-recovery-key";
import { downloadResticPasswordMutation } from "~/client/api-client/@tanstack/react-query.gen";
export const clientMiddleware = [authMiddleware]; export const clientMiddleware = [authMiddleware];

View file

@ -4,13 +4,13 @@ import { type } from "arktype";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { toast } from "sonner"; import { toast } from "sonner";
import { loginMutation } from "~/api-client/@tanstack/react-query.gen";
import { AuthLayout } from "~/client/components/auth-layout"; import { AuthLayout } from "~/client/components/auth-layout";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "~/client/components/ui/form"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "~/client/components/ui/form";
import { Input } from "~/client/components/ui/input"; import { Input } from "~/client/components/ui/input";
import { authMiddleware } from "~/middleware/auth"; import { authMiddleware } from "~/middleware/auth";
import type { Route } from "./+types/login"; import type { Route } from "./+types/login";
import { loginMutation } from "~/client/api-client/@tanstack/react-query.gen";
export const clientMiddleware = [authMiddleware]; export const clientMiddleware = [authMiddleware];

View file

@ -4,7 +4,6 @@ import { type } from "arktype";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { toast } from "sonner"; import { toast } from "sonner";
import { registerMutation } from "~/api-client/@tanstack/react-query.gen";
import { import {
Form, Form,
FormControl, FormControl,
@ -19,6 +18,7 @@ import type { Route } from "./+types/onboarding";
import { AuthLayout } from "~/client/components/auth-layout"; import { AuthLayout } from "~/client/components/auth-layout";
import { Input } from "~/client/components/ui/input"; import { Input } from "~/client/components/ui/input";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { registerMutation } from "~/client/api-client/@tanstack/react-query.gen";
export const clientMiddleware = [authMiddleware]; export const clientMiddleware = [authMiddleware];

View file

@ -3,7 +3,7 @@ import { useQuery } from "@tanstack/react-query";
import { type } from "arktype"; import { type } from "arktype";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { listRepositoriesOptions } from "~/api-client/@tanstack/react-query.gen"; import { listRepositoriesOptions } from "~/client/api-client/@tanstack/react-query.gen";
import { RepositoryIcon } from "~/client/components/repository-icon"; import { RepositoryIcon } from "~/client/components/repository-icon";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
import { import {
@ -136,7 +136,7 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }:
<Form {...form}> <Form {...form}>
<form <form
onSubmit={form.handleSubmit(handleSubmit)} onSubmit={form.handleSubmit(handleSubmit)}
className="grid gap-4 xl:grid-cols-[minmax(0,_2.3fr)_minmax(320px,_1fr)]" className="grid gap-4 xl:grid-cols-[minmax(0,2.3fr)_minmax(320px,1fr)]"
id={formId} id={formId}
> >
<div className="grid gap-4"> <div className="grid gap-4">

View file

@ -1,7 +1,6 @@
import { useCallback, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { FileIcon } from "lucide-react"; import { FileIcon } from "lucide-react";
import { listSnapshotFilesOptions, restoreSnapshotMutation } from "~/api-client/@tanstack/react-query.gen";
import { FileTree, type FileEntry } from "~/client/components/file-tree"; import { FileTree, type FileEntry } from "~/client/components/file-tree";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
@ -20,6 +19,7 @@ import {
import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip";
import type { Snapshot, Volume } from "~/client/lib/types"; import type { Snapshot, Volume } from "~/client/lib/types";
import { toast } from "sonner"; import { toast } from "sonner";
import { listSnapshotFilesOptions, restoreSnapshotMutation } from "~/client/api-client/@tanstack/react-query.gen";
interface Props { interface Props {
snapshot: Snapshot; snapshot: Snapshot;

View file

@ -1,8 +1,8 @@
import type { ListSnapshotsResponse } from "~/api-client/types.gen";
import { cn } from "~/client/lib/utils"; import { cn } from "~/client/lib/utils";
import { Card } from "~/client/components/ui/card"; import { Card } from "~/client/components/ui/card";
import { ByteSize } from "~/client/components/bytes-size"; import { ByteSize } from "~/client/components/bytes-size";
import { useEffect } from "react"; import { useEffect } from "react";
import type { ListSnapshotsResponse } from "~/client/api-client";
interface Props { interface Props {
snapshots: ListSnapshotsResponse; snapshots: ListSnapshotsResponse;
@ -56,7 +56,7 @@ export const SnapshotTimeline = (props: Props) => {
<div className="w-full bg-card"> <div className="w-full bg-card">
<div className="relative flex items-center"> <div className="relative flex items-center">
<div className="flex-1 overflow-hidden"> <div className="flex-1 overflow-hidden">
<div className="flex gap-4 overflow-x-auto pb-2 [&>:first-child]:ml-2 [&>:last-child]:mr-2"> <div className="flex gap-4 overflow-x-auto pb-2 *:first:ml-2 *:last:mr-2">
{snapshots.map((snapshot, index) => { {snapshots.map((snapshot, index) => {
const date = new Date(snapshot.time); const date = new Date(snapshot.time);
const isSelected = snapshotId === snapshot.short_id; const isSelected = snapshotId === snapshot.short_id;

View file

@ -10,15 +10,15 @@ import {
listSnapshotsOptions, listSnapshotsOptions,
updateBackupScheduleMutation, updateBackupScheduleMutation,
stopBackupMutation, stopBackupMutation,
} from "~/api-client/@tanstack/react-query.gen"; } from "~/client/api-client/@tanstack/react-query.gen";
import { parseError } from "~/client/lib/errors"; import { parseError } from "~/client/lib/errors";
import { getCronExpression } from "~/utils/utils"; import { getCronExpression } from "~/utils/utils";
import { CreateScheduleForm, type BackupScheduleFormValues } from "../components/create-schedule-form"; import { CreateScheduleForm, type BackupScheduleFormValues } from "../components/create-schedule-form";
import { ScheduleSummary } from "../components/schedule-summary"; import { ScheduleSummary } from "../components/schedule-summary";
import { getBackupSchedule } from "~/api-client";
import type { Route } from "./+types/backup-details"; import type { Route } from "./+types/backup-details";
import { SnapshotFileBrowser } from "../components/snapshot-file-browser"; import { SnapshotFileBrowser } from "../components/snapshot-file-browser";
import { SnapshotTimeline } from "../components/snapshot-timeline"; import { SnapshotTimeline } from "../components/snapshot-timeline";
import { getBackupSchedule } from "~/client/api-client";
export function meta(_: Route.MetaArgs) { export function meta(_: Route.MetaArgs) {
return [ return [

View file

@ -1,13 +1,13 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { CalendarClock, Database, HardDrive, Plus } from "lucide-react"; import { CalendarClock, Database, HardDrive, Plus } from "lucide-react";
import { Link } from "react-router"; import { Link } from "react-router";
import { listBackupSchedules } from "~/api-client";
import { listBackupSchedulesOptions } from "~/api-client/@tanstack/react-query.gen";
import { BackupStatusDot } from "../components/backup-status-dot"; import { BackupStatusDot } from "../components/backup-status-dot";
import { EmptyState } from "~/client/components/empty-state"; import { EmptyState } from "~/client/components/empty-state";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
import type { Route } from "./+types/backups"; import type { Route } from "./+types/backups";
import { listBackupSchedules } from "~/client/api-client";
import { listBackupSchedulesOptions } from "~/client/api-client/@tanstack/react-query.gen";
export function meta(_: Route.MetaArgs) { export function meta(_: Route.MetaArgs) {
return [ return [
@ -68,7 +68,7 @@ export default function Backups({ loaderData }: Route.ComponentProps) {
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<div className="flex items-center gap-2 flex-1 min-w-0"> <div className="flex items-center gap-2 flex-1 min-w-0">
<HardDrive className="h-5 w-5 text-muted-foreground flex-shrink-0" /> <HardDrive className="h-5 w-5 text-muted-foreground shrink-0" />
<CardTitle className="text-lg truncate"> <CardTitle className="text-lg truncate">
Volume <span className="text-strong-accent">{schedule.volume.name}</span> Volume <span className="text-strong-accent">{schedule.volume.name}</span>
</CardTitle> </CardTitle>

View file

@ -7,7 +7,7 @@ import {
createBackupScheduleMutation, createBackupScheduleMutation,
listRepositoriesOptions, listRepositoriesOptions,
listVolumesOptions, listVolumesOptions,
} from "~/api-client/@tanstack/react-query.gen"; } from "~/client/api-client/@tanstack/react-query.gen";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { Card, CardContent } from "~/client/components/ui/card"; import { Card, CardContent } from "~/client/components/ui/card";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select";
@ -16,7 +16,7 @@ import { EmptyState } from "~/client/components/empty-state";
import { getCronExpression } from "~/utils/utils"; import { getCronExpression } from "~/utils/utils";
import { CreateScheduleForm, type BackupScheduleFormValues } from "../components/create-schedule-form"; import { CreateScheduleForm, type BackupScheduleFormValues } from "../components/create-schedule-form";
import type { Route } from "./+types/create-backup"; import type { Route } from "./+types/create-backup";
import { listRepositories, listVolumes } from "~/api-client"; import { listRepositories, listVolumes } from "~/client/api-client";
export function meta(_: Route.MetaArgs) { export function meta(_: Route.MetaArgs) {
return [ return [
@ -168,7 +168,7 @@ export default function CreateBackup({ loaderData }: Route.ComponentProps) {
<div className="absolute inset-0 animate-pulse"> <div className="absolute inset-0 animate-pulse">
<div className="w-24 h-24 rounded-full bg-primary/10 blur-2xl" /> <div className="w-24 h-24 rounded-full bg-primary/10 blur-2xl" />
</div> </div>
<div className="relative flex items-center justify-center w-24 h-24 rounded-full bg-gradient-to-br from-primary/20 to-primary/5 border-2 border-primary/20"> <div className="relative flex items-center justify-center w-24 h-24 rounded-full bg-linear-to-br from-primary/20 to-primary/5 border-2 border-primary/20">
<Database className="w-12 h-12 text-primary/70" strokeWidth={1.5} /> <Database className="w-12 h-12 text-primary/70" strokeWidth={1.5} />
</div> </div>
</div> </div>

View file

@ -2,7 +2,7 @@ import { useMutation } from "@tanstack/react-query";
import { RotateCcw } from "lucide-react"; import { RotateCcw } from "lucide-react";
import { useId, useState } from "react"; import { useId, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { restoreSnapshotMutation } from "~/api-client/@tanstack/react-query.gen"; import { restoreSnapshotMutation } from "~/client/api-client/@tanstack/react-query.gen";
import { parseError } from "~/client/lib/errors"; import { parseError } from "~/client/lib/errors";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { import {

View file

@ -2,8 +2,8 @@ import { useQuery } from "@tanstack/react-query";
import { Database, RotateCcw } from "lucide-react"; import { Database, RotateCcw } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { listRepositories } from "~/api-client/sdk.gen"; import { listRepositories } from "~/client/api-client/sdk.gen";
import { listRepositoriesOptions } from "~/api-client/@tanstack/react-query.gen"; import { listRepositoriesOptions } from "~/client/api-client/@tanstack/react-query.gen";
import { CreateRepositoryDialog } from "~/client/components/create-repository-dialog"; import { CreateRepositoryDialog } from "~/client/components/create-repository-dialog";
import { RepositoryIcon } from "~/client/components/repository-icon"; import { RepositoryIcon } from "~/client/components/repository-icon";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
@ -79,13 +79,13 @@ export default function Repositories({ loaderData }: Route.ComponentProps) {
<div className="flex flex-col lg:flex-row items-stretch lg:items-center gap-2 md:justify-between p-4 bg-card-header py-4"> <div className="flex flex-col lg:flex-row items-stretch lg:items-center gap-2 md:justify-between p-4 bg-card-header py-4">
<span className="flex flex-col sm:flex-row items-stretch md:items-center gap-0 flex-wrap "> <span className="flex flex-col sm:flex-row items-stretch md:items-center gap-0 flex-wrap ">
<Input <Input
className="w-full lg:w-[180px] min-w-[180px] mr-[-1px] mt-[-1px]" className="w-full lg:w-[180px] min-w-[180px] -mr-px -mt-px"
placeholder="Search repositories…" placeholder="Search repositories…"
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
/> />
<Select value={statusFilter} onValueChange={setStatusFilter}> <Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="w-full lg:w-[180px] min-w-[180px] mr-[-1px] mt-[-1px]"> <SelectTrigger className="w-full lg:w-[180px] min-w-[180px] -mr-px -mt-px">
<SelectValue placeholder="All status" /> <SelectValue placeholder="All status" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@ -95,7 +95,7 @@ export default function Repositories({ loaderData }: Route.ComponentProps) {
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={backendFilter} onValueChange={setBackendFilter}> <Select value={backendFilter} onValueChange={setBackendFilter}>
<SelectTrigger className="w-full lg:w-[180px] min-w-[180px] mt-[-1px]"> <SelectTrigger className="w-full lg:w-[180px] min-w-[180px] -mt-px">
<SelectValue placeholder="All backends" /> <SelectValue placeholder="All backends" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>

View file

@ -7,7 +7,7 @@ import {
doctorRepositoryMutation, doctorRepositoryMutation,
getRepositoryOptions, getRepositoryOptions,
listSnapshotsOptions, listSnapshotsOptions,
} from "~/api-client/@tanstack/react-query.gen"; } from "~/client/api-client/@tanstack/react-query.gen";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { import {
AlertDialog, AlertDialog,
@ -19,7 +19,7 @@ import {
AlertDialogTitle, AlertDialogTitle,
} from "~/client/components/ui/alert-dialog"; } from "~/client/components/ui/alert-dialog";
import { parseError } from "~/client/lib/errors"; import { parseError } from "~/client/lib/errors";
import { getRepository } from "~/api-client/sdk.gen"; import { getRepository } from "~/client/api-client/sdk.gen";
import type { Route } from "./+types/repository-details"; import type { Route } from "./+types/repository-details";
import { cn } from "~/client/lib/utils"; import { cn } from "~/client/lib/utils";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";

View file

@ -1,10 +1,10 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { redirect, useParams } from "react-router"; import { redirect, useParams } from "react-router";
import { listSnapshotFilesOptions } from "~/api-client/@tanstack/react-query.gen"; import { listSnapshotFilesOptions } from "~/client/api-client/@tanstack/react-query.gen";
import { Card, CardContent, CardHeader, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "~/client/components/ui/card";
import { RestoreSnapshotDialog } from "../components/restore-snapshot-dialog"; import { RestoreSnapshotDialog } from "../components/restore-snapshot-dialog";
import { SnapshotFileBrowser } from "~/client/modules/backups/components/snapshot-file-browser"; import { SnapshotFileBrowser } from "~/client/modules/backups/components/snapshot-file-browser";
import { getSnapshotDetails } from "~/api-client"; import { getSnapshotDetails } from "~/client/api-client";
import type { Route } from "./+types/snapshot-details"; import type { Route } from "./+types/snapshot-details";
export function meta({ params }: Route.MetaArgs) { export function meta({ params }: Route.MetaArgs) {

View file

@ -1,7 +1,7 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { Database } from "lucide-react"; import { Database } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { listSnapshotsOptions } from "~/api-client/@tanstack/react-query.gen"; import { listSnapshotsOptions } from "~/client/api-client/@tanstack/react-query.gen";
import { SnapshotsTable } from "~/client/components/snapshots-table"; import { SnapshotsTable } from "~/client/components/snapshots-table";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
@ -83,7 +83,7 @@ export const RepositorySnapshotsTabContent = ({ repository }: Props) => {
<div className="absolute inset-0 animate-pulse"> <div className="absolute inset-0 animate-pulse">
<div className="w-32 h-32 rounded-full bg-primary/10 blur-2xl" /> <div className="w-32 h-32 rounded-full bg-primary/10 blur-2xl" />
</div> </div>
<div className="relative flex items-center justify-center w-32 h-32 rounded-full bg-gradient-to-br from-primary/20 to-primary/5 border-2 border-primary/20"> <div className="relative flex items-center justify-center w-32 h-32 rounded-full bg-linear-to-br from-primary/20 to-primary/5 border-2 border-primary/20">
<Database className="w-16 h-16 text-primary/70" strokeWidth={1.5} /> <Database className="w-16 h-16 text-primary/70" strokeWidth={1.5} />
</div> </div>
</div> </div>
@ -110,7 +110,7 @@ export const RepositorySnapshotsTabContent = ({ repository }: Props) => {
</div> </div>
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">
<Input <Input
className="w-full lg:w-[240px]" className="w-full lg:w-60"
placeholder="Search snapshots..." placeholder="Search snapshots..."
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}

View file

@ -3,11 +3,6 @@ import { Download, KeyRound, User } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { toast } from "sonner"; import { toast } from "sonner";
import {
changePasswordMutation,
downloadResticPasswordMutation,
logoutMutation,
} from "~/api-client/@tanstack/react-query.gen";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { Card, CardContent, CardDescription, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardDescription, CardTitle } from "~/client/components/ui/card";
import { import {
@ -23,6 +18,11 @@ import { Input } from "~/client/components/ui/input";
import { Label } from "~/client/components/ui/label"; import { Label } from "~/client/components/ui/label";
import { appContext } from "~/context"; import { appContext } from "~/context";
import type { Route } from "./+types/settings"; import type { Route } from "./+types/settings";
import {
changePasswordMutation,
downloadResticPasswordMutation,
logoutMutation,
} from "~/client/api-client/@tanstack/react-query.gen";
export function meta(_: Route.MetaArgs) { export function meta(_: Route.MetaArgs) {
return [ return [

View file

@ -2,7 +2,7 @@ import { useMutation } from "@tanstack/react-query";
import { formatDistanceToNow } from "date-fns"; import { formatDistanceToNow } from "date-fns";
import { HeartIcon } from "lucide-react"; import { HeartIcon } from "lucide-react";
import { toast } from "sonner"; import { toast } from "sonner";
import { healthCheckVolumeMutation, updateVolumeMutation } from "~/api-client/@tanstack/react-query.gen"; import { healthCheckVolumeMutation, updateVolumeMutation } from "~/client/api-client/@tanstack/react-query.gen";
import { OnOff } from "~/client/components/onoff"; import { OnOff } from "~/client/components/onoff";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
@ -54,7 +54,7 @@ export const HealthchecksCard = ({ volume }: Props) => {
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="flex flex-col flex-1 justify-start"> <div className="flex flex-col flex-1 justify-start">
{volume.lastError && <span className="text-sm text-red-500 break-words">{volume.lastError}</span>} {volume.lastError && <span className="text-sm text-red-500 wrap-break-word">{volume.lastError}</span>}
{volume.status === "mounted" && <span className="text-md text-emerald-500">Healthy</span>} {volume.status === "mounted" && <span className="text-md text-emerald-500">Healthy</span>}
{volume.status !== "unmounted" && ( {volume.status !== "unmounted" && (
<span className="text-xs text-muted-foreground mb-4">Checked {timeAgo || "never"}</span> <span className="text-xs text-muted-foreground mb-4">Checked {timeAgo || "never"}</span>

View file

@ -2,12 +2,6 @@ import { useMutation, useQuery } from "@tanstack/react-query";
import { useNavigate, useParams, useSearchParams } from "react-router"; import { useNavigate, useParams, useSearchParams } from "react-router";
import { toast } from "sonner"; import { toast } from "sonner";
import { useState } from "react"; import { useState } from "react";
import {
deleteVolumeMutation,
getVolumeOptions,
mountVolumeMutation,
unmountVolumeMutation,
} from "~/api-client/@tanstack/react-query.gen";
import { StatusDot } from "~/client/components/status-dot"; import { StatusDot } from "~/client/components/status-dot";
import { Button } from "~/client/components/ui/button"; import { Button } from "~/client/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
@ -24,12 +18,18 @@ import { VolumeIcon } from "~/client/components/volume-icon";
import { parseError } from "~/client/lib/errors"; import { parseError } from "~/client/lib/errors";
import { cn } from "~/client/lib/utils"; import { cn } from "~/client/lib/utils";
import type { Route } from "./+types/volume-details"; import type { Route } from "./+types/volume-details";
import { getVolume } from "~/api-client";
import { VolumeInfoTabContent } from "../tabs/info"; import { VolumeInfoTabContent } from "../tabs/info";
import { FilesTabContent } from "../tabs/files"; import { FilesTabContent } from "../tabs/files";
import { DockerTabContent } from "../tabs/docker"; import { DockerTabContent } from "../tabs/docker";
import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip";
import { useSystemInfo } from "~/client/hooks/use-system-info"; import { useSystemInfo } from "~/client/hooks/use-system-info";
import { getVolume } from "~/client/api-client";
import {
deleteVolumeMutation,
getVolumeOptions,
mountVolumeMutation,
unmountVolumeMutation,
} from "~/client/api-client/@tanstack/react-query.gen";
export function meta({ params }: Route.MetaArgs) { export function meta({ params }: Route.MetaArgs) {
return [ return [

View file

@ -2,8 +2,6 @@ import { useQuery } from "@tanstack/react-query";
import { HardDrive, RotateCcw } from "lucide-react"; import { HardDrive, RotateCcw } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { listVolumes } from "~/api-client";
import { listVolumesOptions } from "~/api-client/@tanstack/react-query.gen";
import { CreateVolumeDialog } from "~/client/components/create-volume-dialog"; import { CreateVolumeDialog } from "~/client/components/create-volume-dialog";
import { EmptyState } from "~/client/components/empty-state"; import { EmptyState } from "~/client/components/empty-state";
import { StatusDot } from "~/client/components/status-dot"; import { StatusDot } from "~/client/components/status-dot";
@ -14,6 +12,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table";
import { VolumeIcon } from "~/client/components/volume-icon"; import { VolumeIcon } from "~/client/components/volume-icon";
import type { Route } from "./+types/volumes"; import type { Route } from "./+types/volumes";
import { listVolumes } from "~/client/api-client";
import { listVolumesOptions } from "~/client/api-client/@tanstack/react-query.gen";
export function meta(_: Route.MetaArgs) { export function meta(_: Route.MetaArgs) {
return [ return [
@ -79,13 +79,13 @@ export default function Volumes({ loaderData }: Route.ComponentProps) {
<div className="flex flex-col lg:flex-row items-stretch lg:items-center gap-2 md:justify-between p-4 bg-card-header py-4"> <div className="flex flex-col lg:flex-row items-stretch lg:items-center gap-2 md:justify-between p-4 bg-card-header py-4">
<span className="flex flex-col sm:flex-row items-stretch md:items-center gap-0 flex-wrap "> <span className="flex flex-col sm:flex-row items-stretch md:items-center gap-0 flex-wrap ">
<Input <Input
className="w-full lg:w-[180px] min-w-[180px] mr-[-1px] mt-[-1px]" className="w-full lg:w-[180px] min-w-[180px] -mr-px -mt-px"
placeholder="Search volumes…" placeholder="Search volumes…"
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
/> />
<Select value={statusFilter} onValueChange={setStatusFilter}> <Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="w-full lg:w-[180px] min-w-[180px] mr-[-1px] mt-[-1px]"> <SelectTrigger className="w-full lg:w-[180px] min-w-[180px] -mr-px -mt-px">
<SelectValue placeholder="All status" /> <SelectValue placeholder="All status" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@ -95,7 +95,7 @@ export default function Volumes({ loaderData }: Route.ComponentProps) {
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={backendFilter} onValueChange={setBackendFilter}> <Select value={backendFilter} onValueChange={setBackendFilter}>
<SelectTrigger className="w-full lg:w-[180px] min-w-[180px] mt-[-1px]"> <SelectTrigger className="w-full lg:w-[180px] min-w-[180px] -mt-px">
<SelectValue placeholder="All backends" /> <SelectValue placeholder="All backends" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>

View file

@ -1,7 +1,7 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { Unplug } from "lucide-react"; import { Unplug } from "lucide-react";
import * as YML from "yaml"; import * as YML from "yaml";
import { getContainersUsingVolumeOptions } from "~/api-client/@tanstack/react-query.gen"; import { getContainersUsingVolumeOptions } from "~/client/api-client/@tanstack/react-query.gen";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
import { CodeBlock } from "~/client/components/ui/code-block"; import { CodeBlock } from "~/client/components/ui/code-block";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table";

View file

@ -1,7 +1,6 @@
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { useState } from "react"; import { useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { updateVolumeMutation } from "~/api-client/@tanstack/react-query.gen";
import { CreateVolumeForm, type FormValues } from "~/client/components/create-volume-form"; import { CreateVolumeForm, type FormValues } from "~/client/components/create-volume-form";
import { import {
AlertDialog, AlertDialog,
@ -17,6 +16,7 @@ import { Card } from "~/client/components/ui/card";
import type { StatFs, Volume } from "~/client/lib/types"; import type { StatFs, Volume } from "~/client/lib/types";
import { HealthchecksCard } from "../components/healthchecks-card"; import { HealthchecksCard } from "../components/healthchecks-card";
import { StorageChart } from "../components/storage-chart"; import { StorageChart } from "../components/storage-chart";
import { updateVolumeMutation } from "~/client/api-client/@tanstack/react-query.gen";
type Props = { type Props = {
volume: Volume; volume: Volume;

View file

@ -1,5 +1,5 @@
import { redirect, type MiddlewareFunction } from "react-router"; import { redirect, type MiddlewareFunction } from "react-router";
import { getMe, getStatus } from "~/api-client"; import { getMe, getStatus } from "~/client/api-client";
import { appContext } from "~/context"; import { appContext } from "~/context";
export const authMiddleware: MiddlewareFunction = async ({ context, request }) => { export const authMiddleware: MiddlewareFunction = async ({ context, request }) => {

View file

@ -3,9 +3,9 @@ import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration }
import type { Route } from "./+types/root"; import type { Route } from "./+types/root";
import "./app.css"; import "./app.css";
import { client } from "./api-client/client.gen";
import { Toaster } from "./client/components/ui/sonner"; import { Toaster } from "./client/components/ui/sonner";
import { useServerEvents } from "./client/hooks/use-server-events"; import { useServerEvents } from "./client/hooks/use-server-events";
import { client } from "./client/api-client/client.gen";
client.setConfig({ client.setConfig({
baseUrl: "/", baseUrl: "/",

View file

@ -48,10 +48,10 @@ const app = new Hono()
.route("/api/v1/repositories", repositoriesController.use(requireAuth)) .route("/api/v1/repositories", repositoriesController.use(requireAuth))
.route("/api/v1/backups", backupScheduleController.use(requireAuth)) .route("/api/v1/backups", backupScheduleController.use(requireAuth))
.route("/api/v1/system", systemController.use(requireAuth)) .route("/api/v1/system", systemController.use(requireAuth))
.route("/api/v1/events", eventsController.use(requireAuth)) .route("/api/v1/events", eventsController.use(requireAuth));
.get("/assets/*", serveStatic({ root: "./assets/frontend" })) // .get("/assets/*", serveStatic({ root: "./assets/frontend" }))
.get("/images/*", serveStatic({ root: "./assets/frontend" })) // .get("/images/*", serveStatic({ root: "./assets/frontend" }))
.get("*", serveStatic({ path: "./assets/frontend/index.html" })); // .get("*", serveStatic({ path: "./assets/frontend/index.html" }));
app.get("/api/v1/openapi.json", generalDescriptor(app)); app.get("/api/v1/openapi.json", generalDescriptor(app));
app.get("/api/v1/docs", scalarDescriptor); app.get("/api/v1/docs", scalarDescriptor);