diff --git a/.dockerignore b/.dockerignore index 7cac851b..7015b036 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,12 +12,10 @@ !**/build.ts !**/components.json -!apps/**/src/** -!apps/**/drizzle/** -!apps/**/app/** -!apps/**/public/** - -!packages/**/src/** +!src/** +!drizzle/** +!app/** +!public/** # License files and attributions !LICENSE diff --git a/.gitignore b/.gitignore index 2bd0209f..4addbfe3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,47 +1,11 @@ -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib +.DS_Store +/node_modules/ -# Test binary, built with `go test -c` -*.test +# React Router +/.react-router/ +/build/ +/dist/ -# Code coverage profiles and other test artifacts -*.out -coverage.* -*.coverprofile -profile.cov - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work -go.work.sum - -# env file .env - -# Editor/IDE -# .idea/ -# .vscode/ -ironmount -out/ -*.db -tmp/ - -node_modules/ -.env* - .turbo - -mutagen.yml.lock - -data/ - CLAUDE.md diff --git a/Dockerfile b/Dockerfile index 0a7ad18a..909077ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,9 +45,6 @@ WORKDIR /app COPY --from=deps /deps/restic /usr/local/bin/restic COPY --from=deps /deps/rclone /usr/local/bin/rclone COPY ./package.json ./bun.lock ./ -COPY ./packages/schemas/package.json ./packages/schemas/package.json -COPY ./apps/client/package.json ./apps/client/package.json -COPY ./apps/server/package.json ./apps/server/package.json RUN bun install --frozen-lockfile @@ -84,14 +81,15 @@ WORKDIR /app COPY --from=deps /deps/restic /usr/local/bin/restic COPY --from=deps /deps/rclone /usr/local/bin/rclone -COPY --from=builder /app/apps/server/dist ./ -COPY --from=builder /app/apps/server/drizzle ./assets/migrations -COPY --from=builder /app/apps/client/dist/client ./assets/frontend +COPY --from=builder /app/dist/client ./dist/client +COPY --from=builder /app/dist/server ./dist/server +COPY --from=builder /app/drizzle ./assets/migrations +COPY --from=builder /app/package.json ./ # Include third-party licenses and attribution COPY ./LICENSES ./LICENSES COPY ./NOTICES.md ./NOTICES.md COPY ./LICENSE ./LICENSE.md -CMD ["bun", "./index.js"] +CMD ["bun", "run", "start"] diff --git a/apps/client/app/api-client/@tanstack/react-query.gen.ts b/app/api-client/@tanstack/react-query.gen.ts similarity index 100% rename from apps/client/app/api-client/@tanstack/react-query.gen.ts rename to app/api-client/@tanstack/react-query.gen.ts diff --git a/apps/client/app/api-client/client.gen.ts b/app/api-client/client.gen.ts similarity index 100% rename from apps/client/app/api-client/client.gen.ts rename to app/api-client/client.gen.ts diff --git a/apps/client/app/api-client/client/client.gen.ts b/app/api-client/client/client.gen.ts similarity index 100% rename from apps/client/app/api-client/client/client.gen.ts rename to app/api-client/client/client.gen.ts diff --git a/apps/client/app/api-client/client/index.ts b/app/api-client/client/index.ts similarity index 100% rename from apps/client/app/api-client/client/index.ts rename to app/api-client/client/index.ts diff --git a/apps/client/app/api-client/client/types.gen.ts b/app/api-client/client/types.gen.ts similarity index 100% rename from apps/client/app/api-client/client/types.gen.ts rename to app/api-client/client/types.gen.ts diff --git a/apps/client/app/api-client/client/utils.gen.ts b/app/api-client/client/utils.gen.ts similarity index 100% rename from apps/client/app/api-client/client/utils.gen.ts rename to app/api-client/client/utils.gen.ts diff --git a/apps/client/app/api-client/core/auth.gen.ts b/app/api-client/core/auth.gen.ts similarity index 100% rename from apps/client/app/api-client/core/auth.gen.ts rename to app/api-client/core/auth.gen.ts diff --git a/apps/client/app/api-client/core/bodySerializer.gen.ts b/app/api-client/core/bodySerializer.gen.ts similarity index 100% rename from apps/client/app/api-client/core/bodySerializer.gen.ts rename to app/api-client/core/bodySerializer.gen.ts diff --git a/apps/client/app/api-client/core/params.gen.ts b/app/api-client/core/params.gen.ts similarity index 100% rename from apps/client/app/api-client/core/params.gen.ts rename to app/api-client/core/params.gen.ts diff --git a/apps/client/app/api-client/core/pathSerializer.gen.ts b/app/api-client/core/pathSerializer.gen.ts similarity index 100% rename from apps/client/app/api-client/core/pathSerializer.gen.ts rename to app/api-client/core/pathSerializer.gen.ts diff --git a/apps/client/app/api-client/core/types.gen.ts b/app/api-client/core/types.gen.ts similarity index 100% rename from apps/client/app/api-client/core/types.gen.ts rename to app/api-client/core/types.gen.ts diff --git a/apps/client/app/api-client/index.ts b/app/api-client/index.ts similarity index 100% rename from apps/client/app/api-client/index.ts rename to app/api-client/index.ts diff --git a/apps/client/app/api-client/sdk.gen.ts b/app/api-client/sdk.gen.ts similarity index 100% rename from apps/client/app/api-client/sdk.gen.ts rename to app/api-client/sdk.gen.ts diff --git a/apps/client/app/api-client/types.gen.ts b/app/api-client/types.gen.ts similarity index 100% rename from apps/client/app/api-client/types.gen.ts rename to app/api-client/types.gen.ts diff --git a/apps/client/app/app.css b/app/app.css similarity index 100% rename from apps/client/app/app.css rename to app/app.css diff --git a/apps/client/app/components/app-breadcrumb.tsx b/app/client/components/app-breadcrumb.tsx similarity index 90% rename from apps/client/app/components/app-breadcrumb.tsx rename to app/client/components/app-breadcrumb.tsx index ca215dc5..5918651f 100644 --- a/apps/client/app/components/app-breadcrumb.tsx +++ b/app/client/components/app-breadcrumb.tsx @@ -6,8 +6,8 @@ import { BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, -} from "~/components/ui/breadcrumb"; -import { useBreadcrumbs } from "~/lib/breadcrumbs"; +} from "~/client/components/ui/breadcrumb"; +import { useBreadcrumbs } from "~/client/lib/breadcrumbs"; export function AppBreadcrumb() { const breadcrumbs = useBreadcrumbs(); diff --git a/apps/client/app/components/app-sidebar.tsx b/app/client/components/app-sidebar.tsx similarity index 94% rename from apps/client/app/components/app-sidebar.tsx rename to app/client/components/app-sidebar.tsx index 78bc14c7..9995ee1b 100644 --- a/apps/client/app/components/app-sidebar.tsx +++ b/app/client/components/app-sidebar.tsx @@ -10,9 +10,9 @@ import { SidebarMenuButton, SidebarMenuItem, useSidebar, -} from "~/components/ui/sidebar"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "~/components/ui/tooltip"; -import { cn } from "~/lib/utils"; +} from "~/client/components/ui/sidebar"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "~/client/components/ui/tooltip"; +import { cn } from "~/client/lib/utils"; const items = [ { diff --git a/apps/client/app/components/auth-layout.tsx b/app/client/components/auth-layout.tsx similarity index 100% rename from apps/client/app/components/auth-layout.tsx rename to app/client/components/auth-layout.tsx diff --git a/apps/client/app/components/bytes-size.tsx b/app/client/components/bytes-size.tsx similarity index 100% rename from apps/client/app/components/bytes-size.tsx rename to app/client/components/bytes-size.tsx diff --git a/apps/client/app/components/create-repository-dialog.tsx b/app/client/components/create-repository-dialog.tsx similarity index 97% rename from apps/client/app/components/create-repository-dialog.tsx rename to app/client/components/create-repository-dialog.tsx index 88aa1dd8..972250ac 100644 --- a/apps/client/app/components/create-repository-dialog.tsx +++ b/app/client/components/create-repository-dialog.tsx @@ -3,7 +3,7 @@ import { Plus } from "lucide-react"; import { useId } from "react"; import { toast } from "sonner"; import { createRepositoryMutation } from "~/api-client/@tanstack/react-query.gen"; -import { parseError } from "~/lib/errors"; +import { parseError } from "~/client/lib/errors"; import { CreateRepositoryForm } from "./create-repository-form"; import { Button } from "./ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog"; diff --git a/apps/client/app/components/create-repository-form.tsx b/app/client/components/create-repository-form.tsx similarity index 98% rename from apps/client/app/components/create-repository-form.tsx rename to app/client/components/create-repository-form.tsx index d925ad3e..2a645cae 100644 --- a/apps/client/app/components/create-repository-form.tsx +++ b/app/client/components/create-repository-form.tsx @@ -1,9 +1,8 @@ import { arktypeResolver } from "@hookform/resolvers/arktype"; -import { COMPRESSION_MODES, repositoryConfigSchema } from "@ironmount/schemas/restic"; import { type } from "arktype"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; -import { cn, slugify } from "~/lib/utils"; +import { cn, slugify } from "~/client/lib/utils"; import { deepClean } from "~/utils/object"; import { Button } from "./ui/button"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "./ui/form"; @@ -14,7 +13,8 @@ import { useQuery } from "@tanstack/react-query"; import { Alert, AlertDescription } from "./ui/alert"; import { ExternalLink } from "lucide-react"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; -import { useSystemInfo } from "~/hooks/use-system-info"; +import { useSystemInfo } from "~/client/hooks/use-system-info"; +import { COMPRESSION_MODES, repositoryConfigSchema } from "~/schemas/restic"; export const formSchema = type({ name: "2<=string<=32", diff --git a/apps/client/app/components/create-volume-dialog.tsx b/app/client/components/create-volume-dialog.tsx similarity index 97% rename from apps/client/app/components/create-volume-dialog.tsx rename to app/client/components/create-volume-dialog.tsx index e4d8880a..0ed77aef 100644 --- a/apps/client/app/components/create-volume-dialog.tsx +++ b/app/client/components/create-volume-dialog.tsx @@ -3,7 +3,7 @@ import { Plus } from "lucide-react"; import { useId } from "react"; import { toast } from "sonner"; import { createVolumeMutation } from "~/api-client/@tanstack/react-query.gen"; -import { parseError } from "~/lib/errors"; +import { parseError } from "~/client/lib/errors"; import { CreateVolumeForm } from "./create-volume-form"; import { Button } from "./ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./ui/dialog"; diff --git a/apps/client/app/components/create-volume-form.tsx b/app/client/components/create-volume-form.tsx similarity index 99% rename from apps/client/app/components/create-volume-form.tsx rename to app/client/components/create-volume-form.tsx index 961fdc57..7b8114ee 100644 --- a/apps/client/app/components/create-volume-form.tsx +++ b/app/client/components/create-volume-form.tsx @@ -1,18 +1,18 @@ import { arktypeResolver } from "@hookform/resolvers/arktype"; -import { volumeConfigSchema } from "@ironmount/schemas"; import { useMutation } from "@tanstack/react-query"; import { type } from "arktype"; import { CheckCircle, Loader2, XCircle } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { testConnectionMutation } from "~/api-client/@tanstack/react-query.gen"; -import { cn, slugify } from "~/lib/utils"; +import { cn, slugify } from "~/client/lib/utils"; import { deepClean } from "~/utils/object"; import { DirectoryBrowser } from "./directory-browser"; import { Button } from "./ui/button"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "./ui/form"; import { Input } from "./ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"; +import { volumeConfigSchema } from "~/schemas/volumes"; export const formSchema = type({ name: "2<=string<=32", diff --git a/apps/client/app/components/directory-browser.tsx b/app/client/components/directory-browser.tsx similarity index 100% rename from apps/client/app/components/directory-browser.tsx rename to app/client/components/directory-browser.tsx diff --git a/apps/client/app/components/empty-state.tsx b/app/client/components/empty-state.tsx similarity index 100% rename from apps/client/app/components/empty-state.tsx rename to app/client/components/empty-state.tsx diff --git a/apps/client/app/components/file-tree.tsx b/app/client/components/file-tree.tsx similarity index 99% rename from apps/client/app/components/file-tree.tsx rename to app/client/components/file-tree.tsx index 88c45c14..f7636629 100644 --- a/apps/client/app/components/file-tree.tsx +++ b/app/client/components/file-tree.tsx @@ -10,8 +10,8 @@ import { ChevronDown, ChevronRight, File as FileIcon, Folder as FolderIcon, FolderOpen, Loader2 } from "lucide-react"; import { memo, type ReactNode, useCallback, useEffect, useMemo, useState } from "react"; -import { cn } from "~/lib/utils"; -import { Checkbox } from "~/components/ui/checkbox"; +import { cn } from "~/client/lib/utils"; +import { Checkbox } from "~/client/components/ui/checkbox"; const NODE_PADDING_LEFT = 12; diff --git a/apps/client/app/components/grid-background.tsx b/app/client/components/grid-background.tsx similarity index 95% rename from apps/client/app/components/grid-background.tsx rename to app/client/components/grid-background.tsx index 945cedb7..5f8df115 100644 --- a/apps/client/app/components/grid-background.tsx +++ b/app/client/components/grid-background.tsx @@ -1,5 +1,5 @@ import type { ReactNode } from "react"; -import { cn } from "~/lib/utils"; +import { cn } from "~/client/lib/utils"; interface GridBackgroundProps { children: ReactNode; diff --git a/apps/client/app/components/layout.tsx b/app/client/components/layout.tsx similarity index 100% rename from apps/client/app/components/layout.tsx rename to app/client/components/layout.tsx diff --git a/apps/client/app/components/onoff.tsx b/app/client/components/onoff.tsx similarity index 95% rename from apps/client/app/components/onoff.tsx rename to app/client/components/onoff.tsx index a5b690da..7fe95082 100644 --- a/apps/client/app/components/onoff.tsx +++ b/app/client/components/onoff.tsx @@ -1,4 +1,4 @@ -import { cn } from "~/lib/utils"; +import { cn } from "~/client/lib/utils"; import { Switch } from "./ui/switch"; type Props = { diff --git a/apps/client/app/components/repository-icon.tsx b/app/client/components/repository-icon.tsx similarity index 87% rename from apps/client/app/components/repository-icon.tsx rename to app/client/components/repository-icon.tsx index 40d41526..aaf9d579 100644 --- a/apps/client/app/components/repository-icon.tsx +++ b/app/client/components/repository-icon.tsx @@ -1,5 +1,5 @@ -import type { RepositoryBackend } from "@ironmount/schemas/restic"; import { Database, HardDrive, Cloud } from "lucide-react"; +import type { RepositoryBackend } from "~/schemas/restic"; type Props = { backend: RepositoryBackend; diff --git a/apps/client/app/components/snapshots-table.tsx b/app/client/components/snapshots-table.tsx similarity index 94% rename from apps/client/app/components/snapshots-table.tsx rename to app/client/components/snapshots-table.tsx index 922ddde5..564b5e4a 100644 --- a/apps/client/app/components/snapshots-table.tsx +++ b/app/client/components/snapshots-table.tsx @@ -1,9 +1,9 @@ import { Calendar, Clock, Database, FolderTree, HardDrive } from "lucide-react"; import { useNavigate } from "react-router"; import type { ListSnapshotsResponse } from "~/api-client/types.gen"; -import { ByteSize } from "~/components/bytes-size"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/components/ui/table"; -import { Tooltip, TooltipContent, TooltipTrigger } from "~/components/ui/tooltip"; +import { ByteSize } from "~/client/components/bytes-size"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "~/client/components/ui/table"; +import { Tooltip, TooltipContent, TooltipTrigger } from "~/client/components/ui/tooltip"; import { formatDuration } from "~/utils/utils"; type Snapshot = ListSnapshotsResponse[number]; diff --git a/apps/client/app/components/status-dot.tsx b/app/client/components/status-dot.tsx similarity index 92% rename from apps/client/app/components/status-dot.tsx rename to app/client/components/status-dot.tsx index 9206a33c..d28d1584 100644 --- a/apps/client/app/components/status-dot.tsx +++ b/app/client/components/status-dot.tsx @@ -1,5 +1,5 @@ -import type { VolumeStatus } from "~/lib/types"; -import { cn } from "~/lib/utils"; +import type { VolumeStatus } from "~/client/lib/types"; +import { cn } from "~/client/lib/utils"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; export const StatusDot = ({ status }: { status: VolumeStatus }) => { diff --git a/apps/client/app/components/ui/alert-dialog.tsx b/app/client/components/ui/alert-dialog.tsx similarity index 97% rename from apps/client/app/components/ui/alert-dialog.tsx rename to app/client/components/ui/alert-dialog.tsx index 6bbf718b..4105ce33 100644 --- a/apps/client/app/components/ui/alert-dialog.tsx +++ b/app/client/components/ui/alert-dialog.tsx @@ -1,7 +1,7 @@ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; import type * as React from "react"; -import { buttonVariants } from "~/components/ui/button"; -import { cn } from "~/lib/utils"; +import { buttonVariants } from "~/client/components/ui/button"; +import { cn } from "~/client/lib/utils"; function AlertDialog({ ...props }: React.ComponentProps) { return ; diff --git a/apps/client/app/components/ui/alert.tsx b/app/client/components/ui/alert.tsx similarity index 97% rename from apps/client/app/components/ui/alert.tsx rename to app/client/components/ui/alert.tsx index b33dad7a..1014ae72 100644 --- a/apps/client/app/components/ui/alert.tsx +++ b/app/client/components/ui/alert.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "~/lib/utils"; +import { cn } from "~/client/lib/utils"; const alertVariants = cva( "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7", diff --git a/apps/client/app/components/ui/badge.tsx b/app/client/components/ui/badge.tsx similarity index 100% rename from apps/client/app/components/ui/badge.tsx rename to app/client/components/ui/badge.tsx diff --git a/app/client/components/ui/breadcrumb.tsx b/app/client/components/ui/breadcrumb.tsx new file mode 100644 index 00000000..138587d7 --- /dev/null +++ b/app/client/components/ui/breadcrumb.tsx @@ -0,0 +1,92 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { ChevronRight, MoreHorizontal } from "lucide-react"; + +import { cn } from "~/client/lib/utils"; + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return