Refactor backup components to utilize a unified DatabaseType type. Update AddBackup and UpdateBackup components to handle database type selection for compose backups. Enhance UI to allow users to select database types dynamically. Update backup schema to include databaseType field for better metadata management.

This commit is contained in:
Mauricio Siu 2025-04-27 23:00:26 -06:00
parent 8d91053c3a
commit 6b9765a26c
4 changed files with 97 additions and 59 deletions

View File

@ -60,7 +60,7 @@ type CacheType = "cache" | "fetch";
const getMetadataSchema = (
backupType: "database" | "compose",
databaseType: Props["databaseType"],
databaseType: DatabaseType,
) => {
if (backupType !== "compose") return z.object({}).optional();
@ -101,30 +101,34 @@ type Schema = z.infer<typeof Schema>;
interface Props {
id: string;
databaseType: "postgres" | "mariadb" | "mysql" | "mongo" | "web-server";
databaseType?: DatabaseType;
refetch: () => void;
backupType: "database" | "compose";
}
type DatabaseType = "postgres" | "mariadb" | "mysql" | "mongo" | "web-server";
export const AddBackup = ({
id,
databaseType,
databaseType = "postgres",
refetch,
backupType = "database",
}: Props) => {
const { data, isLoading } = api.destination.all.useQuery();
const [cacheType, setCacheType] = useState<CacheType>("cache");
const [selectedDatabaseType, setSelectedDatabaseType] =
useState<DatabaseType>(databaseType as DatabaseType);
const { mutateAsync: createBackup, isLoading: isCreatingPostgresBackup } =
api.backup.create.useMutation();
const schema = Schema.extend({
metadata: getMetadataSchema(backupType, databaseType),
metadata: getMetadataSchema(backupType, selectedDatabaseType),
});
const form = useForm<z.infer<typeof schema>>({
defaultValues: {
database: "",
database: databaseType === "web-server" ? "dokploy" : "",
destinationId: "",
enabled: true,
prefix: "/",
@ -209,7 +213,8 @@ export const AddBackup = ({
enabled: data.enabled,
database: data.database,
keepLatestCount: data.keepLatestCount,
databaseType: databaseType,
databaseType:
backupType === "compose" ? selectedDatabaseType : databaseType,
serviceName: data.serviceName,
...getDatabaseId,
backupType,
@ -248,6 +253,27 @@ export const AddBackup = ({
{errorServices?.message}
</AlertBlock>
)}
{backupType === "compose" && (
<FormItem>
<FormLabel>Database Type</FormLabel>
<Select
value={selectedDatabaseType}
onValueChange={(value) =>
setSelectedDatabaseType(value as DatabaseType)
}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a database type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="postgres">PostgreSQL</SelectItem>
<SelectItem value="mariadb">MariaDB</SelectItem>
<SelectItem value="mysql">MySQL</SelectItem>
<SelectItem value="mongo">MongoDB</SelectItem>
</SelectContent>
</Select>
</FormItem>
)}
<FormField
control={form.control}
name="destinationId"
@ -526,7 +552,7 @@ export const AddBackup = ({
/>
{backupType === "compose" && (
<>
{databaseType === "postgres" && (
{selectedDatabaseType === "postgres" && (
<FormField
control={form.control}
name="metadata.postgres.databaseUser"
@ -542,7 +568,7 @@ export const AddBackup = ({
/>
)}
{databaseType === "mariadb" && (
{selectedDatabaseType === "mariadb" && (
<>
<FormField
control={form.control}
@ -577,7 +603,7 @@ export const AddBackup = ({
</>
)}
{databaseType === "mongo" && (
{selectedDatabaseType === "mongo" && (
<>
<FormField
control={form.control}
@ -612,7 +638,7 @@ export const AddBackup = ({
</>
)}
{databaseType === "mysql" && (
{selectedDatabaseType === "mysql" && (
<FormField
control={form.control}
name="metadata.mysql.databaseRootPassword"

View File

@ -65,7 +65,7 @@ type CacheType = "cache" | "fetch";
const getMetadataSchema = (
backupType: "database" | "compose",
databaseType: string,
databaseType: DatabaseType,
) => {
if (backupType !== "compose") return z.object({}).optional();
@ -108,9 +108,12 @@ interface Props {
refetch: () => void;
}
type DatabaseType = "postgres" | "mariadb" | "mysql" | "mongo" | "web-server";
export const UpdateBackup = ({ backupId, refetch }: Props) => {
const [isOpen, setIsOpen] = useState(false);
const [cacheType, setCacheType] = useState<CacheType>("cache");
const { data, isLoading } = api.destination.all.useQuery();
const { data: backup } = api.backup.one.useQuery(
{
@ -120,7 +123,10 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
enabled: !!backupId,
},
);
const [selectedDatabaseType, setSelectedDatabaseType] =
useState<DatabaseType>(
(backup?.databaseType as DatabaseType) || "postgres",
);
const {
data: services,
isFetching: isLoadingServices,
@ -142,11 +148,12 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
const { mutateAsync, isLoading: isLoadingUpdate } =
api.backup.update.useMutation();
const schema = backup
? Schema.extend({
metadata: getMetadataSchema(backup.backupType, backup.databaseType),
})
: Schema;
const schema = Schema.extend({
metadata: getMetadataSchema(
backup?.backupType || "database",
selectedDatabaseType,
),
});
const form = useForm<z.infer<typeof schema>>({
defaultValues: {
@ -179,6 +186,19 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
}
}, [form, form.reset, backup]);
useEffect(() => {
if (backup?.backupType === "compose") {
const currentValues = form.getValues();
form.reset(
{
...currentValues,
metadata: {},
},
{ keepDefaultValues: true },
);
}
}, [selectedDatabaseType, backup?.backupType, form]);
const onSubmit = async (data: z.infer<typeof schema>) => {
if (backup?.backupType === "compose" && !data.serviceName) {
form.setError("serviceName", {
@ -198,6 +218,10 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
serviceName: data.serviceName,
keepLatestCount: data.keepLatestCount as number | null,
metadata: data.metadata || {},
databaseType:
backup?.backupType === "compose"
? selectedDatabaseType
: backup?.databaseType,
})
.then(async () => {
toast.success("Backup Updated");
@ -215,12 +239,12 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
<Button
variant="ghost"
size="icon"
className="group hover:bg-blue-500/10 "
className="group hover:bg-blue-500/10"
>
<PenBoxIcon className="size-3.5 text-primary group-hover:text-blue-500" />
<PenBoxIcon className="size-3.5 text-primary group-hover:text-blue-500" />
</Button>
</DialogTrigger>
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-lg">
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-lg">
<DialogHeader>
<DialogTitle>Update Backup</DialogTitle>
<DialogDescription>Update the backup</DialogDescription>
@ -238,6 +262,27 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
{errorServices?.message}
</AlertBlock>
)}
{backup?.backupType === "compose" && (
<FormItem>
<FormLabel>Database Type</FormLabel>
<Select
value={selectedDatabaseType}
onValueChange={(value) => {
setSelectedDatabaseType(value as DatabaseType);
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a database type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="postgres">PostgreSQL</SelectItem>
<SelectItem value="mariadb">MariaDB</SelectItem>
<SelectItem value="mysql">MySQL</SelectItem>
<SelectItem value="mongo">MongoDB</SelectItem>
</SelectContent>
</Select>
</FormItem>
)}
<FormField
control={form.control}
name="destinationId"
@ -512,7 +557,7 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
/>
{backup?.backupType === "compose" && (
<>
{backup.databaseType === "postgres" && (
{selectedDatabaseType === "postgres" && (
<FormField
control={form.control}
name="metadata.postgres.databaseUser"
@ -528,7 +573,7 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
/>
)}
{backup.databaseType === "mariadb" && (
{selectedDatabaseType === "mariadb" && (
<>
<FormField
control={form.control}
@ -563,7 +608,7 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
</>
)}
{backup.databaseType === "mongo" && (
{selectedDatabaseType === "mongo" && (
<>
<FormField
control={form.control}
@ -598,7 +643,7 @@ export const UpdateBackup = ({ backupId, refetch }: Props) => {
</>
)}
{backup.databaseType === "mysql" && (
{selectedDatabaseType === "mysql" && (
<FormField
control={form.control}
name="metadata.mysql.databaseRootPassword"

View File

@ -31,13 +31,6 @@ import {
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";
import { appRouter } from "@/server/api/root";
import { api } from "@/utils/api";
@ -65,8 +58,6 @@ type TabState =
| "domains"
| "monitoring";
type DatabaseType = "postgres" | "mariadb" | "mysql" | "mongo";
const Service = (
props: InferGetServerSidePropsType<typeof getServerSideProps>,
) => {
@ -75,8 +66,6 @@ const Service = (
const router = useRouter();
const { projectId } = router.query;
const [tab, setTab] = useState<TabState>(activeTab);
const [selectedDatabaseType, setSelectedDatabaseType] =
useState<DatabaseType>("postgres");
useEffect(() => {
if (router.query.tab) {
@ -260,30 +249,7 @@ const Service = (
</TabsContent>
<TabsContent value="backups">
<div className="flex flex-col gap-4 pt-2.5">
<div className="flex flex-row items-center gap-2">
<Label>Database Type</Label>
<Select
value={selectedDatabaseType}
onValueChange={(value) =>
setSelectedDatabaseType(value as DatabaseType)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select a database type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="postgres">PostgreSQL</SelectItem>
<SelectItem value="mariadb">MariaDB</SelectItem>
<SelectItem value="mysql">MySQL</SelectItem>
<SelectItem value="mongo">MongoDB</SelectItem>
</SelectContent>
</Select>
</div>
<ShowBackups
id={composeId}
databaseType={selectedDatabaseType}
backupType="compose"
/>
<ShowBackups id={composeId} backupType="compose" />
</div>
</TabsContent>

View File

@ -178,5 +178,6 @@ export const apiUpdateBackup = createSchema
keepLatestCount: true,
serviceName: true,
metadata: true,
databaseType: true,
})
.required();