refactor: server constants
This commit is contained in:
parent
c1c8138197
commit
ed80131a9b
8 changed files with 43 additions and 18 deletions
|
|
@ -1,2 +0,0 @@
|
||||||
export const REPOSITORY_BASE = "/var/lib/zerobyte/repositories";
|
|
||||||
export const REGISTRATION_ENABLED_KEY = "registrations_enabled";
|
|
||||||
|
|
@ -33,7 +33,9 @@ import {
|
||||||
SftpRepositoryForm,
|
SftpRepositoryForm,
|
||||||
AdvancedForm,
|
AdvancedForm,
|
||||||
} from "./repository-forms";
|
} from "./repository-forms";
|
||||||
import { REPOSITORY_BASE } from "~/client/lib/constants";
|
import { useServerFn } from "@tanstack/react-start";
|
||||||
|
import { getServerConstants } from "~/server/core/constants";
|
||||||
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
export const formSchema = type({
|
export const formSchema = type({
|
||||||
name: "2<=string<=32",
|
name: "2<=string<=32",
|
||||||
|
|
@ -52,8 +54,8 @@ type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValuesForType = {
|
const defaultValuesForType = (repoBase: string) => ({
|
||||||
local: { backend: "local" as const, compressionMode: "auto" as const, path: REPOSITORY_BASE },
|
local: { backend: "local" as const, compressionMode: "auto" as const, path: repoBase },
|
||||||
s3: { backend: "s3" as const, compressionMode: "auto" as const },
|
s3: { backend: "s3" as const, compressionMode: "auto" as const },
|
||||||
r2: { backend: "r2" as const, compressionMode: "auto" as const },
|
r2: { backend: "r2" as const, compressionMode: "auto" as const },
|
||||||
gcs: { backend: "gcs" as const, compressionMode: "auto" as const },
|
gcs: { backend: "gcs" as const, compressionMode: "auto" as const },
|
||||||
|
|
@ -61,7 +63,7 @@ const defaultValuesForType = {
|
||||||
rclone: { backend: "rclone" as const, compressionMode: "auto" as const },
|
rclone: { backend: "rclone" as const, compressionMode: "auto" as const },
|
||||||
rest: { backend: "rest" as const, compressionMode: "auto" as const },
|
rest: { backend: "rest" as const, compressionMode: "auto" as const },
|
||||||
sftp: { backend: "sftp" as const, compressionMode: "auto" as const, port: 22, skipHostKeyCheck: false },
|
sftp: { backend: "sftp" as const, compressionMode: "auto" as const, port: 22, skipHostKeyCheck: false },
|
||||||
};
|
});
|
||||||
|
|
||||||
export const CreateRepositoryForm = ({
|
export const CreateRepositoryForm = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
|
@ -71,6 +73,12 @@ export const CreateRepositoryForm = ({
|
||||||
loading,
|
loading,
|
||||||
className,
|
className,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const getConstants = useServerFn(getServerConstants);
|
||||||
|
const { data: constants } = useSuspenseQuery({
|
||||||
|
queryKey: ["server-constants"],
|
||||||
|
queryFn: getConstants,
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm<RepositoryFormValues>({
|
const form = useForm<RepositoryFormValues>({
|
||||||
resolver: arktypeResolver(cleanSchema as unknown as typeof formSchema),
|
resolver: arktypeResolver(cleanSchema as unknown as typeof formSchema),
|
||||||
defaultValues: initialValues,
|
defaultValues: initialValues,
|
||||||
|
|
@ -125,7 +133,9 @@ export const CreateRepositoryForm = ({
|
||||||
name: form.getValues().name,
|
name: form.getValues().name,
|
||||||
isExistingRepository: form.getValues().isExistingRepository,
|
isExistingRepository: form.getValues().isExistingRepository,
|
||||||
customPassword: form.getValues().customPassword,
|
customPassword: form.getValues().customPassword,
|
||||||
...defaultValuesForType[value as keyof typeof defaultValuesForType],
|
...defaultValuesForType(constants.REPOSITORY_BASE)[
|
||||||
|
value as keyof ReturnType<typeof defaultValuesForType>
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import type { UseFormReturn } from "react-hook-form";
|
import type { UseFormReturn } from "react-hook-form";
|
||||||
import { Check, Pencil, X, AlertTriangle } from "lucide-react";
|
import { Check, Pencil, X, AlertTriangle } from "lucide-react";
|
||||||
import { REPOSITORY_BASE } from "~/client/lib/constants";
|
|
||||||
import { Button } from "../../../../components/ui/button";
|
import { Button } from "../../../../components/ui/button";
|
||||||
import { FormItem, FormLabel, FormDescription, FormField, FormControl } from "../../../../components/ui/form";
|
import { FormItem, FormLabel, FormDescription, FormField, FormControl } from "../../../../components/ui/form";
|
||||||
import { DirectoryBrowser } from "../../../../components/directory-browser";
|
import { DirectoryBrowser } from "../../../../components/directory-browser";
|
||||||
|
|
@ -16,6 +15,9 @@ import {
|
||||||
AlertDialogTitle,
|
AlertDialogTitle,
|
||||||
} from "../../../../components/ui/alert-dialog";
|
} from "../../../../components/ui/alert-dialog";
|
||||||
import type { RepositoryFormValues } from "../create-repository-form";
|
import type { RepositoryFormValues } from "../create-repository-form";
|
||||||
|
import { useServerFn } from "@tanstack/react-start";
|
||||||
|
import { getServerConstants } from "~/server/core/constants";
|
||||||
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
form: UseFormReturn<RepositoryFormValues>;
|
form: UseFormReturn<RepositoryFormValues>;
|
||||||
|
|
@ -25,6 +27,12 @@ export const LocalRepositoryForm = ({ form }: Props) => {
|
||||||
const [showPathBrowser, setShowPathBrowser] = useState(false);
|
const [showPathBrowser, setShowPathBrowser] = useState(false);
|
||||||
const [showPathWarning, setShowPathWarning] = useState(false);
|
const [showPathWarning, setShowPathWarning] = useState(false);
|
||||||
|
|
||||||
|
const getConstants = useServerFn(getServerConstants);
|
||||||
|
const { data: constants } = useSuspenseQuery({
|
||||||
|
queryKey: ["server-constants"],
|
||||||
|
queryFn: getConstants,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
|
|
@ -36,7 +44,7 @@ export const LocalRepositoryForm = ({ form }: Props) => {
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex-1 text-sm font-mono bg-muted px-3 py-2 rounded-md border">
|
<div className="flex-1 text-sm font-mono bg-muted px-3 py-2 rounded-md border">
|
||||||
{field.value || REPOSITORY_BASE}
|
{field.value || constants.REPOSITORY_BASE}
|
||||||
</div>
|
</div>
|
||||||
<Button type="button" variant="outline" onClick={() => setShowPathWarning(true)} size="sm">
|
<Button type="button" variant="outline" onClick={() => setShowPathWarning(true)} size="sm">
|
||||||
<Pencil className="h-4 w-4 mr-2" />
|
<Pencil className="h-4 w-4 mr-2" />
|
||||||
|
|
@ -60,8 +68,8 @@ export const LocalRepositoryForm = ({ form }: Props) => {
|
||||||
If the path is not a host mount, you will lose your repository data when the container restarts.
|
If the path is not a host mount, you will lose your repository data when the container restarts.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
The default path <code className="bg-muted px-1 rounded">{REPOSITORY_BASE}</code> is safe to use if
|
The default path <code className="bg-muted px-1 rounded">{constants.REPOSITORY_BASE}</code> is safe
|
||||||
you followed the recommended Docker Compose setup.
|
to use if you followed the recommended Docker Compose setup.
|
||||||
</p>
|
</p>
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
|
|
@ -92,7 +100,7 @@ export const LocalRepositoryForm = ({ form }: Props) => {
|
||||||
onSelectPath={(path) => {
|
onSelectPath={(path) => {
|
||||||
field.onChange(path);
|
field.onChange(path);
|
||||||
}}
|
}}
|
||||||
selectedPath={field.value || REPOSITORY_BASE}
|
selectedPath={field.value || constants.REPOSITORY_BASE}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import {
|
||||||
AlertDialogTitle,
|
AlertDialogTitle,
|
||||||
} from "~/client/components/ui/alert-dialog";
|
} from "~/client/components/ui/alert-dialog";
|
||||||
import type { Repository } from "~/client/lib/types";
|
import type { Repository } from "~/client/lib/types";
|
||||||
import { REPOSITORY_BASE } from "~/client/lib/constants";
|
|
||||||
import { formatDateTime, formatTimeAgo } from "~/client/lib/datetime";
|
import { formatDateTime, formatTimeAgo } from "~/client/lib/datetime";
|
||||||
import {
|
import {
|
||||||
cancelDoctorMutation,
|
cancelDoctorMutation,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { createServerFn } from "@tanstack/react-start";
|
||||||
|
|
||||||
export const OPERATION_TIMEOUT = 5000;
|
export const OPERATION_TIMEOUT = 5000;
|
||||||
|
|
||||||
export const VOLUME_MOUNT_BASE = process.env.ZEROBYTE_VOLUMES_DIR || "/var/lib/zerobyte/volumes";
|
export const VOLUME_MOUNT_BASE = process.env.ZEROBYTE_VOLUMES_DIR || "/var/lib/zerobyte/volumes";
|
||||||
|
|
@ -11,3 +13,12 @@ export const RESTIC_PASS_FILE = process.env.RESTIC_PASS_FILE || "/var/lib/zeroby
|
||||||
export const RCLONE_CONFIG_DIR = process.env.RCLONE_CONFIG_DIR || "/root/.config/rclone";
|
export const RCLONE_CONFIG_DIR = process.env.RCLONE_CONFIG_DIR || "/root/.config/rclone";
|
||||||
|
|
||||||
export const DEFAULT_EXCLUDES = [DATABASE_URL, RESTIC_PASS_FILE, REPOSITORY_BASE];
|
export const DEFAULT_EXCLUDES = [DATABASE_URL, RESTIC_PASS_FILE, REPOSITORY_BASE];
|
||||||
|
|
||||||
|
export const REGISTRATION_ENABLED_KEY = "registrations_enabled";
|
||||||
|
|
||||||
|
export const getServerConstants = createServerFn({ method: "GET" }).handler(() => {
|
||||||
|
return {
|
||||||
|
REPOSITORY_BASE,
|
||||||
|
REGISTRATION_ENABLED_KEY,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { db } from "~/server/db/db";
|
||||||
import type { AuthMiddlewareContext } from "../auth";
|
import type { AuthMiddlewareContext } from "../auth";
|
||||||
import { logger } from "~/server/utils/logger";
|
import { logger } from "~/server/utils/logger";
|
||||||
import { ForbiddenError } from "http-errors-enhanced";
|
import { ForbiddenError } from "http-errors-enhanced";
|
||||||
import { REGISTRATION_ENABLED_KEY } from "~/client/lib/constants";
|
import { REGISTRATION_ENABLED_KEY } from "~/server/core/constants";
|
||||||
|
|
||||||
export const ensureOnlyOneUser = async (ctx: AuthMiddlewareContext) => {
|
export const ensureOnlyOneUser = async (ctx: AuthMiddlewareContext) => {
|
||||||
const { path } = ctx;
|
const { path } = ctx;
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ import { db } from "../../../db/db";
|
||||||
import { repositoriesTable } from "../../../db/schema";
|
import { repositoriesTable } from "../../../db/schema";
|
||||||
import { logger } from "../../../utils/logger";
|
import { logger } from "../../../utils/logger";
|
||||||
import { toMessage } from "~/server/utils/errors";
|
import { toMessage } from "~/server/utils/errors";
|
||||||
|
import { REPOSITORY_BASE } from "~/server/core/constants";
|
||||||
const DEFAULT_LOCAL_REPOSITORY_ROOT = "/var/lib/zerobyte/repositories";
|
|
||||||
|
|
||||||
type MigrationError = { name: string; error: string };
|
type MigrationError = { name: string; error: string };
|
||||||
|
|
||||||
|
|
@ -31,7 +30,7 @@ const isPathAlreadyMigrated = (path: string, name: string): boolean => {
|
||||||
|
|
||||||
const buildPath = (path: string | null, name: string): string => {
|
const buildPath = (path: string | null, name: string): string => {
|
||||||
if (path === null || path.trim() === "") {
|
if (path === null || path.trim() === "") {
|
||||||
return `${DEFAULT_LOCAL_REPOSITORY_ROOT}/${name}`;
|
return `${REPOSITORY_BASE}/${name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${trimTrailingSlashes(path)}/${name}`;
|
return `${trimTrailingSlashes(path)}/${name}`;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { cache } from "../../utils/cache";
|
||||||
import { logger } from "~/server/utils/logger";
|
import { logger } from "~/server/utils/logger";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import { appMetadataTable } from "../../db/schema";
|
import { appMetadataTable } from "../../db/schema";
|
||||||
import { REGISTRATION_ENABLED_KEY } from "~/client/lib/constants";
|
import { REGISTRATION_ENABLED_KEY } from "~/server/core/constants";
|
||||||
|
|
||||||
const CACHE_TTL = 60 * 60;
|
const CACHE_TTL = 60 * 60;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue