Some refactoring in database and projects side.

This commit is contained in:
charlesgauthereau
2025-11-29 22:31:32 +01:00
parent 934e635cdb
commit ac951378e8
7 changed files with 102 additions and 43 deletions
@@ -15,7 +15,9 @@ export function TablePagination(props: tablePaginationProps) {
const {className, table, maxVisiblePages = 3, pageSizeOptions = [10, 20, 30, 40, 50]} = props; const {className, table, maxVisiblePages = 3, pageSizeOptions = [10, 20, 30, 40, 50]} = props;
return ( return (
<div className={cn("flex gap-x-4 flex-row w-full", className)}> <div
className={cn("flex gap-x-4", className)}
>
<TablePaginationSize table={table} pageSizeOptions={pageSizeOptions}/> <TablePaginationSize table={table} pageSizeOptions={pageSizeOptions}/>
<TablePaginationNavigation table={table} maxVisiblePages={maxVisiblePages} className="justify-end mt-0"/> <TablePaginationNavigation table={table} maxVisiblePages={maxVisiblePages} className="justify-end mt-0"/>
</div> </div>
@@ -1,9 +1,8 @@
import {Form, FormControl, FormField, FormItem, FormMessage, useZodForm} from "@/components/ui/form"; import {Form, FormControl, FormField, FormItem, FormMessage, useZodForm} from "@/components/ui/form";
import {Plus, Trash2} from "lucide-react"; import {InfoIcon, Plus, Trash2} from "lucide-react";
import {useFieldArray} from "react-hook-form"; import {useFieldArray} from "react-hook-form";
import { import {
AlertPoliciesSchema, AlertPoliciesType, AlertPolicySchema, AlertPolicyType, AlertPoliciesSchema, AlertPoliciesType, AlertPolicyType,
EVENT_KIND_OPTIONS EVENT_KIND_OPTIONS
} from "@/components/wrappers/dashboard/database/alert-policy/alert-policy.schema"; } from "@/components/wrappers/dashboard/database/alert-policy/alert-policy.schema";
import {DatabaseWith} from "@/db/schema/07_database"; import {DatabaseWith} from "@/db/schema/07_database";
@@ -16,13 +15,14 @@ import {Separator} from "@/components/ui/separator";
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select"; import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select";
import {MultiSelect} from "@/components/wrappers/common/multiselect/multi-select"; import {MultiSelect} from "@/components/wrappers/common/multiselect/multi-select";
import {useMutation} from "@tanstack/react-query"; import {useMutation} from "@tanstack/react-query";
import {deleteBackupAction} from "@/features/dashboard/restore/restore.action";
import {toast} from "sonner"; import {toast} from "sonner";
import { import {
createAlertPoliciesAction, deleteAlertPoliciesAction, createAlertPoliciesAction, deleteAlertPoliciesAction,
updateAlertPoliciesAction updateAlertPoliciesAction
} from "@/components/wrappers/dashboard/database/alert-policy/alert-policy.action"; } from "@/components/wrappers/dashboard/database/alert-policy/alert-policy.action";
import {useRouter} from "next/navigation"; import {useRouter} from "next/navigation";
import {Switch} from "@/components/ui/switch";
import {Tooltip, TooltipContent, TooltipTrigger} from "@/components/ui/tooltip";
type AlertPolicyFormProps = { type AlertPolicyFormProps = {
onSuccess?: () => void; onSuccess?: () => void;
@@ -33,13 +33,13 @@ type AlertPolicyFormProps = {
export const AlertPolicyForm = ({database, notificationChannels, organizationId, onSuccess}: AlertPolicyFormProps) => { export const AlertPolicyForm = ({database, notificationChannels, organizationId, onSuccess}: AlertPolicyFormProps) => {
const router = useRouter() const router = useRouter()
console.log("database",database)
const organizationNotificationChannels = notificationChannels.map(channel => channel.id) ?? []; const organizationNotificationChannels = notificationChannels.map(channel => channel.id) ?? [];
const formattedAlertPoliciesList = (alertPolicies: AlertPolicy[]) => { const formattedAlertPoliciesList = (alertPolicies: AlertPolicy[]) => {
return alertPolicies.map((alertPolicy) => ({ return alertPolicies.map((alertPolicy) => ({
notificationChannelId: alertPolicy.notificationChannelId, notificationChannelId: alertPolicy.notificationChannelId,
eventKinds: alertPolicy.eventKinds eventKinds: alertPolicy.eventKinds,
enabled: alertPolicy.enabled
})); }));
}; };
@@ -49,6 +49,7 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
alertPolicies: database.alertPolicies && database.alertPolicies.length > 0 ? formattedAlertPoliciesList(database.alertPolicies) : [{ alertPolicies: database.alertPolicies && database.alertPolicies.length > 0 ? formattedAlertPoliciesList(database.alertPolicies) : [{
notificationChannelId: "", notificationChannelId: "",
eventKinds: [], eventKinds: [],
enabled: true,
}], }],
}, },
}); });
@@ -60,7 +61,7 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
const addAlertPolicy = () => { const addAlertPolicy = () => {
append({id: "", eventKinds: []}) append({id: "", eventKinds: [], enabled: true});
} }
const removeAlertPolicy = (index: number) => { const removeAlertPolicy = (index: number) => {
@@ -76,6 +77,9 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
const mutation = useMutation({ const mutation = useMutation({
mutationFn: async ({alertPolicies}: AlertPoliciesType) => { mutationFn: async ({alertPolicies}: AlertPoliciesType) => {
console.log(alertPolicies) console.log(alertPolicies)
const defaultFormatedAlertPolicies = formattedAlertPoliciesList(database?.alertPolicies ?? []); const defaultFormatedAlertPolicies = formattedAlertPoliciesList(database?.alertPolicies ?? []);
@@ -149,7 +153,7 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
}, },
onSuccess: () => { onSuccess: () => {
toast.success("Alert policies saved successfully"); toast.success("Alert policies saved successfully");
onSuccess?.(); // onSuccess?.();
router.refresh(); router.refresh();
}, },
onError: (error: any) => { onError: (error: any) => {
@@ -199,8 +203,6 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
control={form.control} control={form.control}
name={`alertPolicies.${index}.notificationChannelId`} name={`alertPolicies.${index}.notificationChannelId`}
render={({field}) => { render={({field}) => {
const selectedIds = form const selectedIds = form
.watch("alertPolicies") .watch("alertPolicies")
.map((a: AlertPolicyType) => a.notificationChannelId) .map((a: AlertPolicyType) => a.notificationChannelId)
@@ -239,6 +241,7 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
}} }}
/> />
<FormField <FormField
control={form.control} control={form.control}
name={`alertPolicies.${index}.eventKinds`} name={`alertPolicies.${index}.eventKinds`}
@@ -251,19 +254,58 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
defaultValue={field.value ?? []} defaultValue={field.value ?? []}
placeholder="Select event kinds" placeholder="Select event kinds"
variant="inverted" variant="inverted"
animation={2} animation={0}
/> />
</FormControl> </FormControl>
</FormItem> </FormItem>
)} )}
/> />
</div> </div>
<div> <div className="flex flex-col gap-3 justify-between items-center ">
<Button type="button" variant="outline" <Button type="button" variant="outline"
onClick={() => removeAlertPolicy(index)}> onClick={() => removeAlertPolicy(index)}>
<Trash2 className="w-4 h-4"/> <Trash2 className="w-4 h-4"/>
</Button> </Button>
<div className="flex h-full justify-center items-center">
<Tooltip>
<TooltipTrigger asChild>
<div tabIndex={0} className="inline-flex rounded-md">
{/*<Switch*/}
{/* checked={true}*/}
{/* onCheckedChange={async () => {*/}
{/* }}*/}
{/*/>*/}
<FormField
control={form.control}
name={`alertPolicies.${index}.enabled`}
render={({field}) => (
<FormItem>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
</div>
</TooltipTrigger>
<TooltipContent className="max-w-64 text-pretty">
<div className="flex items-center gap-1.5">
<InfoIcon className="size-4"/>
<p>This is for activating the alert policy</p>
</div>
</TooltipContent>
</Tooltip>
</div>
</div> </div>
</div> </div>
@@ -279,7 +321,7 @@ export const AlertPolicyForm = ({database, notificationChannels, organizationId,
Cancel Cancel
</ButtonWithLoading> </ButtonWithLoading>
<ButtonWithLoading isPending={false}> <ButtonWithLoading isPending={false}>
Submit Save
</ButtonWithLoading> </ButtonWithLoading>
</div> </div>
</Form> </Form>
@@ -27,6 +27,7 @@ export const createAlertPoliciesAction = userAction
databaseId: parsedInput.databaseId, databaseId: parsedInput.databaseId,
notificationChannelId: policy.notificationChannelId, notificationChannelId: policy.notificationChannelId,
eventKinds: policy.eventKinds, eventKinds: policy.eventKinds,
enabled: policy.enabled,
})); }));
const insertedPolicies = await db const insertedPolicies = await db
@@ -5,6 +5,7 @@ export const AlertPolicySchema =
z.object({ z.object({
notificationChannelId: z.string().min(1, "Please select a notification channel"), notificationChannelId: z.string().min(1, "Please select a notification channel"),
eventKinds: z.enum(['error_backup', 'error_restore', 'success_restore', 'success_backup', 'weekly_report']).array().nonempty(), eventKinds: z.enum(['error_backup', 'error_restore', 'success_restore', 'success_backup', 'weekly_report']).array().nonempty(),
enabled: z.boolean().default(true),
} }
) )
@@ -4,19 +4,28 @@ import {userAction} from "@/lib/safe-actions/actions";
import {z} from "zod"; import {z} from "zod";
import {v4 as uuidv4} from "uuid"; import {v4 as uuidv4} from "uuid";
import {ServerActionResult} from "@/types/action-type"; import {ServerActionResult} from "@/types/action-type";
import {and, eq} from "drizzle-orm"; import {and, eq, inArray} from "drizzle-orm";
import {db} from "@/db"; import {db} from "@/db";
import * as drizzleDb from "@/db"; import * as drizzleDb from "@/db";
export const deleteProjectAction = userAction.schema(z.string()).action(async ({parsedInput}): Promise<ServerActionResult<typeof drizzleDb.schemas.project.$inferSelect>> => { export const deleteProjectAction = userAction.schema(z.string()).action(async ({parsedInput}): Promise<ServerActionResult<typeof drizzleDb.schemas.project.$inferSelect>> => {
try { try {
const uuid = uuidv4(); const uuid = uuidv4();
await db const databasesUpdated = await db
.update(drizzleDb.schemas.database) .update(drizzleDb.schemas.database)
.set({ .set({
projectId: null, projectId: null,
backupPolicy: null
}) })
.where(eq(drizzleDb.schemas.database.projectId, parsedInput)); .where(eq(drizzleDb.schemas.database.projectId, parsedInput)).returning();
const databasesToRemove = databasesUpdated.map((db) => db.id);
console.log(databasesUpdated);
console.log(databasesToRemove);
await db.delete(drizzleDb.schemas.retentionPolicy)
.where(inArray(drizzleDb.schemas.retentionPolicy.databaseId, databasesToRemove)).execute();
const updatedProjects = await db const updatedProjects = await db
.update(drizzleDb.schemas.project) .update(drizzleDb.schemas.project)
@@ -109,7 +109,6 @@ export const DatabaseBackupList = (props: DatabaseBackupListProps) => {
enablePagination enablePagination
selectedActions={(rows) => ( selectedActions={(rows) => (
<> <>
<div className="flex justify-start md:justify-between gap-3 md:gap-0 items-center w-full ml-0"> <div className="flex justify-start md:justify-between gap-3 md:gap-0 items-center w-full ml-0">
<div className="flex gap-2"> <div className="flex gap-2">
{!isMember && ( {!isMember && (
@@ -76,8 +76,6 @@ export const createProjectAction = userAction
}); });
export const updateProjectAction = userAction export const updateProjectAction = userAction
.schema( .schema(
z.object({ z.object({
@@ -110,7 +108,14 @@ export const updateProjectAction = userAction
} }
if (databasesToRemove.length > 0) { if (databasesToRemove.length > 0) {
await db.update(drizzleDb.schemas.database).set({ projectId: null }).where(inArray(drizzleDb.schemas.database.id, databasesToRemove)); await db.update(drizzleDb.schemas.database).set({
projectId: null,
backupPolicy: null
}).where(inArray(drizzleDb.schemas.database.id, databasesToRemove));
await db.delete(drizzleDb.schemas.retentionPolicy)
.where(inArray(drizzleDb.schemas.retentionPolicy.databaseId, databasesToRemove)).execute();
} }
// const slug = slugify(parsedInput.data.name); // const slug = slugify(parsedInput.data.name);