diff --git a/app/client/modules/backups/components/schedule-mirrors-config.tsx b/app/client/modules/backups/components/schedule-mirrors-config.tsx index 31cefb60..5dd38c28 100644 --- a/app/client/modules/backups/components/schedule-mirrors-config.tsx +++ b/app/client/modules/backups/components/schedule-mirrors-config.tsx @@ -1,6 +1,6 @@ import { useMutation, useQuery, useSuspenseQuery } from "@tanstack/react-query"; import { Copy, Plus, Trash2 } from "lucide-react"; -import { useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { toast } from "sonner"; import { Button } from "~/client/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; @@ -38,9 +38,9 @@ type MirrorAssignment = { lastCopyError: string | null; }; -export const ScheduleMirrorsConfig = ({ scheduleId, primaryRepositoryId, repositories, initialData }: Props) => { +const buildAssignments = (mirrors: GetScheduleMirrorsResponse) => { const map = new Map(); - for (const mirror of initialData) { + for (const mirror of mirrors) { map.set(mirror.repositoryId, { repositoryId: mirror.repositoryId, enabled: mirror.enabled, @@ -49,8 +49,11 @@ export const ScheduleMirrorsConfig = ({ scheduleId, primaryRepositoryId, reposit lastCopyError: mirror.lastCopyError, }); } + return map; +}; - const [assignments, setAssignments] = useState>(map); +export const ScheduleMirrorsConfig = ({ scheduleId, primaryRepositoryId, repositories, initialData }: Props) => { + const [assignments, setAssignments] = useState>(() => buildAssignments(initialData)); const [hasChanges, setHasChanges] = useState(false); const [isAddingNew, setIsAddingNew] = useState(false); @@ -58,6 +61,12 @@ export const ScheduleMirrorsConfig = ({ scheduleId, primaryRepositoryId, reposit ...getScheduleMirrorsOptions({ path: { scheduleId: scheduleId.toString() } }), }); + useEffect(() => { + if (!hasChanges) { + setAssignments(buildAssignments(currentMirrors)); + } + }, [currentMirrors, hasChanges]); + const { data: compatibility } = useQuery({ ...getMirrorCompatibilityOptions({ path: { scheduleId: scheduleId.toString() } }), }); diff --git a/app/client/modules/backups/routes/backups.tsx b/app/client/modules/backups/routes/backups.tsx index 8e26597b..8883361c 100644 --- a/app/client/modules/backups/routes/backups.tsx +++ b/app/client/modules/backups/routes/backups.tsx @@ -30,7 +30,7 @@ export const clientLoader = async () => { }; export function BackupsPage() { - const { data: schedules, isLoading } = useSuspenseQuery({ + const { data: schedules } = useSuspenseQuery({ ...listBackupSchedulesOptions(), }); @@ -69,14 +69,6 @@ export function BackupsPage() { } }; - if (isLoading) { - return ( -
-

Loading backup schedules...

-
- ); - } - if (!schedules || schedules.length === 0) { return ( (); - const { data: volumesData, isLoading: loadingVolumes } = useSuspenseQuery({ + const { data: volumesData } = useSuspenseQuery({ ...listVolumesOptions(), }); @@ -79,14 +79,6 @@ export function CreateBackupPage() { const selectedVolume = volumesData.find((v) => v.id === selectedVolumeId); - if (loadingVolumes) { - return ( -
-

Loading...

-
- ); - } - if (!volumesData.length) { return ( Time:

{formatDateTime(data.time)}

- <> -
- Backup Schedule: -

- - {backupSchedule?.name} - -

-
-
- Volume: -

- - {backupSchedule?.volume.name} - -

-
- + {backupSchedule && ( + <> +
+ Backup Schedule: +

+ + {backupSchedule?.name} + +

+
+
+ Volume: +

+ + {backupSchedule?.volume.name} + +

+
+ + )}
Paths: diff --git a/app/middleware/auth.ts b/app/middleware/auth.ts index 9068f9d5..3dcbb8c3 100644 --- a/app/middleware/auth.ts +++ b/app/middleware/auth.ts @@ -11,7 +11,7 @@ export const authMiddleware = createMiddleware().server(async ({ next, request } const isAuthRoute = ["/login", "/onboarding"].includes(new URL(request.url).pathname); if (!session?.user?.id && !isAuthRoute) { - const status = await getStatus(); + const status = await getStatus().catch(() => ({ data: { hasUsers: false } })); if (!status.data?.hasUsers) { throw redirect({ to: "/onboarding" }); } diff --git a/app/routes/(dashboard)/route.tsx b/app/routes/(dashboard)/route.tsx index 2b8a73e3..b5544592 100644 --- a/app/routes/(dashboard)/route.tsx +++ b/app/routes/(dashboard)/route.tsx @@ -2,15 +2,16 @@ import { createFileRoute } from "@tanstack/react-router"; import { createServerFn } from "@tanstack/react-start"; import { getRequestHeaders } from "@tanstack/react-start/server"; import { Layout } from "~/client/components/layout"; -import type { AppContext } from "~/context"; import { authMiddleware } from "~/middleware/auth"; import { auth } from "~/server/lib/auth"; +import { authService } from "~/server/modules/auth/auth.service"; export const fetchUser = createServerFn({ method: "GET" }).handler(async () => { const headers = getRequestHeaders(); const session = await auth.api.getSession({ headers }); + const hasUsers = await authService.hasUsers(); - return { user: session?.user, hasUsers: true }; + return { user: session?.user ?? null, hasUsers }; }); export const Route = createFileRoute("/(dashboard)")({ @@ -21,7 +22,7 @@ export const Route = createFileRoute("/(dashboard)")({ }, loader: async () => { const authContext = await fetchUser(); - return authContext as AppContext; + return authContext; }, }); diff --git a/app/server/core/config.ts b/app/server/core/config.ts index 371a8b0e..a4392dc4 100644 --- a/app/server/core/config.ts +++ b/app/server/core/config.ts @@ -48,6 +48,7 @@ const envSchema = type({ appVersion: s.APP_VERSION, trustedOrigins: s.TRUSTED_ORIGINS?.split(",") .map((origin) => origin.trim()) + .filter(Boolean) .concat(s.BASE_URL) ?? [s.BASE_URL], disableRateLimiting: s.DISABLE_RATE_LIMITING === "true", appSecret: s.APP_SECRET, diff --git a/bun.lock b/bun.lock index 51edf919..b48da9cb 100644 --- a/bun.lock +++ b/bun.lock @@ -99,7 +99,6 @@ "typescript": "^5.9.3", "vite": "^7.3.1", "vite-bundle-analyzer": "^1.2.3", - "vite-plugin-babel": "^1.4.1", "vite-tsconfig-paths": "^6.0.5", "wait-for-expect": "^4.0.0", }, @@ -1349,7 +1348,7 @@ "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], - "nf3": ["nf3@0.3.9", "", {}, "sha512-vgmoL6pUXpKXx+WepG4H1xc2nf1N/5vKgU9QerryuSFIyef8EDkj7esYcIgqMe/mE6nGsy6M6b8wfssEBQizVQ=="], + "nf3": ["nf3@0.3.10", "", {}, "sha512-UlqmHkZiHGgSkRj17yrOXEsSu5ECvtlJ3Xm1W5WsWrTKgu9m7OjrMZh9H/ME2LcWrTlMD0/vmmNVpyBG4yRdGg=="], "nitro": ["nitro@3.0.1-alpha.2", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.3", "db0": "^0.3.4", "h3": "^2.0.1-rc.11", "jiti": "^2.6.1", "nf3": "^0.3.5", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "oxc-minify": "^0.110.0", "oxc-transform": "^0.110.0", "srvx": "^0.10.1", "undici": "^7.18.2", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.5" }, "peerDependencies": { "rolldown": ">=1.0.0-beta.0", "rollup": "^4", "vite": "^7 || ^8 || >=8.0.0-0", "xml2js": "^0.6.2" }, "optionalPeers": ["rolldown", "rollup", "vite", "xml2js"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-YviDY5J/trS821qQ1fpJtpXWIdPYiOizC/meHavlm1Hfuhx//H+Egd1+4C5SegJRgtWMnRPW9n//6Woaw81cTQ=="], @@ -1621,8 +1620,6 @@ "vite-bundle-analyzer": ["vite-bundle-analyzer@1.3.6", "", { "bin": { "analyze": "dist/bin.js" } }, "sha512-elFXkF9oGy4CJEeOdP1DSEHRDKWfmaEDfT9/GuF4jmyfmUF6nC//iN+ythqMEVvrtchOEHGKLumZwnu1NjoI0w=="], - "vite-plugin-babel": ["vite-plugin-babel@1.4.1", "", { "peerDependencies": { "@babel/core": "^7.0.0", "vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-quO+viHGSv1cjbfhbeiMZ7SZpo8P29NiUh9LJfKhpmIDwy0THRiTRUbanBbkNcZcSyHFgp1n7TByd1C2kanqLQ=="], - "vite-tsconfig-paths": ["vite-tsconfig-paths@6.0.5", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-f/WvY6ekHykUF1rWJUAbCU7iS/5QYDIugwpqJA+ttwKbxSbzNlqlE8vZSrsnxNQciUW+z6lvhlXMaEyZn9MSig=="], "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], diff --git a/package.json b/package.json index ba020b79..613c2fdf 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,6 @@ "typescript": "^5.9.3", "vite": "^7.3.1", "vite-bundle-analyzer": "^1.2.3", - "vite-plugin-babel": "^1.4.1", "vite-tsconfig-paths": "^6.0.5", "wait-for-expect": "^4.0.0" }, diff --git a/vite.config.ts b/vite.config.ts index 0b2e460e..6abc6502 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,18 +4,10 @@ import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import { nitro } from "nitro/vite"; import tsconfigPaths from "vite-tsconfig-paths"; import viteReact from "@vitejs/plugin-react"; -import babel from "vite-plugin-babel"; export default defineConfig({ plugins: [ tsconfigPaths(), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], - plugins: [["babel-plugin-react-compiler"]], - }, - }), tanstackStart({ srcDirectory: "app", router: { @@ -23,7 +15,11 @@ export default defineConfig({ }, }), nitro({ preset: "bun" }), - viteReact(), + viteReact({ + babel: { + plugins: ["babel-plugin-react-compiler"], + }, + }), tailwindcss(), ], build: {