fix: policies reload

This commit is contained in:
Théo LAGACHE
2026-02-13 11:24:53 +01:00
parent 1c97c97fa1
commit ca9bc7ae94
10 changed files with 49 additions and 12 deletions
@@ -6,8 +6,6 @@ import {eq, and, inArray} from "drizzle-orm";
import * as drizzleDb from "@/db";
import {getOrganizationProjectDatabases} from "@/lib/services";
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
import {getOrganizationChannels} from "@/db/services/notification-channel";
import {getOrganizationStorageChannels} from "@/db/services/storage-channel";
import {BackupModalProvider} from "@/components/wrappers/dashboard/database/backup/backup-modal-context";
import {DatabaseContent} from "@/components/wrappers/dashboard/projects/database/database-content";
@@ -85,12 +83,6 @@ export default async function RoutePage(props: PageParams<{
notFound();
}
const organizationChannels = await getOrganizationChannels(organization.id);
const activeOrganizationChannels = organizationChannels.filter(channel => channel.enabled);
const organizationStorageChannels = await getOrganizationStorageChannels(organization.id);
const activeOrganizationStorageChannels = organizationStorageChannels.filter(channel => channel.enabled);
const successRate = totalBackups > 0 ? (successfulBackups / totalBackups) * 100 : null;
@@ -110,8 +102,8 @@ export default async function RoutePage(props: PageParams<{
availableBackups={availableBackups}
successRate={successRate}
organizationId={organization.id}
activeOrganizationChannels={activeOrganizationChannels}
activeOrganizationStorageChannels={activeOrganizationStorageChannels}
activeOrganizationChannels={[]}
activeOrganizationStorageChannels={[]}
/>
</BackupModalProvider>
</Page>
@@ -1,6 +1,7 @@
"use client";
import {useMutation, useQueryClient} from "@tanstack/react-query";
import {useRouter} from "next/navigation";
import {toast} from "sonner";
import {backupButtonAction} from "@/components/wrappers/dashboard/backup/backup-button/backup-button.action";
@@ -15,6 +16,7 @@ export type BackupButtonProps = {
export const BackupButton = (props: BackupButtonProps) => {
const queryClient = useQueryClient();
const router = useRouter();
const isMobile = useIsMobile()
const mutation = useMutation({
@@ -23,6 +25,7 @@ export const BackupButton = (props: BackupButtonProps) => {
if (backup?.data?.success) {
toast.success(backup.data.actionSuccess?.message || "Backup created successfully!");
queryClient.invalidateQueries({queryKey: ["database-data", props.databaseId]});
router.refresh();
} else {
toast.error(backup?.serverError || "Failed to create backup.");
}
@@ -18,6 +18,7 @@ import {TooltipProvider} from "@/components/ui/tooltip";
import {getChannelIcon} from "@/components/wrappers/dashboard/admin/channels/helpers/common";
import {Badge} from "@/components/ui/badge";
import {getStatusColor, getStatusIcon} from "@/components/wrappers/dashboard/admin/notifications/logs/columns";
import {useRouter} from "next/navigation";
import {
createRestorationBackupAction, deleteBackupAction, deleteBackupStorageAction,
downloadBackupAction
@@ -39,6 +40,7 @@ export const BackupActionsForm = ({backup, action}: BackupActionsFormProps) => {
const filteredBackupStorages = backup.storages?.filter((storage) => storage.deletedAt === null) ?? []
const {closeModal} = useBackupModal();
const queryClient = useQueryClient();
const router = useRouter();
const form = useZodForm({
schema: BackupActionsSchema,
@@ -72,6 +74,7 @@ export const BackupActionsForm = ({backup, action}: BackupActionsFormProps) => {
if (inner?.success) {
toast.success(inner.actionSuccess?.message);
queryClient.invalidateQueries({queryKey: ["database-data", backup.databaseId]});
router.refresh();
if (action === "download") {
const url = inner.value
if (typeof url === "string") {
@@ -89,6 +92,7 @@ export const BackupActionsForm = ({backup, action}: BackupActionsFormProps) => {
if (action === "delete") {
toast.success("Backup deleted successfully.")
queryClient.invalidateQueries({queryKey: ["database-data", backup.databaseId]});
router.refresh();
closeModal()
} else {
toast.error(inner?.actionError?.message ?? "An error occurred.");
@@ -110,6 +114,7 @@ export const BackupActionsForm = ({backup, action}: BackupActionsFormProps) => {
if (inner?.success) {
toast.success(inner.actionSuccess?.message);
queryClient.invalidateQueries({queryKey: ["database-data", backup.databaseId]});
router.refresh();
closeModal()
} else {
toast.error(inner?.actionError?.message);
@@ -5,6 +5,8 @@ import {db} from "@/db";
import {eq} from "drizzle-orm";
import * as drizzleDb from "@/db";
import {BackupWith, Restoration} from "@/db/schema/07_database";
import {getOrganizationChannels} from "@/db/services/notification-channel";
import {getOrganizationStorageChannels} from "@/db/services/storage-channel";
export const getDatabaseDataAction = userAction
.schema(
@@ -19,6 +21,9 @@ export const getDatabaseDataAction = userAction
where: eq(drizzleDb.schemas.database.id, databaseId),
with: {
project: true,
retentionPolicy: true,
alertPolicies: true,
storagePolicies: true
}
});
@@ -45,10 +50,23 @@ export const getDatabaseDataAction = userAction
const successfulBackups = backups.filter(b => b.status === "success").length;
const successRate = totalBackups > 0 ? (successfulBackups / totalBackups) * 100 : null;
let activeOrganizationChannels = [];
let activeOrganizationStorageChannels = [];
if (database?.project?.organizationId) {
const organizationChannels = await getOrganizationChannels(database.project.organizationId);
activeOrganizationChannels = organizationChannels.filter(channel => channel.enabled);
const organizationStorageChannels = await getOrganizationStorageChannels(database.project.organizationId);
activeOrganizationStorageChannels = organizationStorageChannels.filter(channel => channel.enabled);
}
return {
database,
backups,
restorations,
activeOrganizationChannels,
activeOrganizationStorageChannels,
stats: {
totalBackups,
availableBackups,
@@ -14,6 +14,7 @@ import {Switch} from "@/components/ui/switch";
import {Card} from "@/components/ui/card";
import Link from "next/link";
import {useIsMobile} from "@/hooks/use-mobile";
import {useRouter} from "next/navigation";
import {
ChannelKind,
getChannelIcon,
@@ -48,6 +49,7 @@ export const ChannelPoliciesForm = ({
kind
}: ChannelPoliciesFormProps) => {
const queryClient = useQueryClient();
const router = useRouter();
const isMobile = useIsMobile();
const channelText = getChannelTextBasedOnKind(kind);
@@ -130,6 +132,7 @@ export const ChannelPoliciesForm = ({
onSuccess: () => {
toast.success("Policies saved successfully");
queryClient.invalidateQueries({queryKey: ["database-data", database.id]});
router.refresh();
},
onError: (error: any) => { toast.error(error.message || "Failed to save policies"); },
});
@@ -8,6 +8,7 @@ import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
import { updateDatabaseBackupPolicyAction } from "@/components/wrappers/dashboard/database/cron-button/cron.action";
import {Database} from "@/db/schema/07_database";
@@ -18,6 +19,7 @@ export type CronButtonProps = {
export const CronButton = (props: CronButtonProps) => {
const queryClient = useQueryClient();
const router = useRouter();
const [isSwitched, setIsSwitched] = useState(props.database.backupPolicy !== null);
const [open, setOpen] = useState(false);
@@ -27,6 +29,7 @@ export const CronButton = (props: CronButtonProps) => {
onSuccess: () => {
toast.success(`Method updated successfully.`);
queryClient.invalidateQueries({ queryKey: ["database-data", props.database.id] });
router.refresh();
},
onError: () => {
toast.error(`An error occurred while updating backup method.`);
@@ -1,6 +1,7 @@
import {AdvancedCronSelect} from "./advanced-cron-select";
import {updateDatabaseBackupPolicyAction} from "@/components/wrappers/dashboard/database/cron-button/cron.action";
import {useMutation, useQueryClient} from "@tanstack/react-query";
import {useRouter} from "next/navigation";
import {useState} from "react";
import {toast} from "sonner";
import {Button} from "@/components/ui/button";
@@ -15,6 +16,7 @@ export type CronInputProps = {
export const CronInput = ({database, onSuccess}: CronInputProps) => {
const [cron, setCron] = useState<string>(database.backupPolicy ?? "* * * * *");
const queryClient = useQueryClient();
const router = useRouter();
const updateBackupPolicy = useMutation({
mutationFn: (value: string) => updateDatabaseBackupPolicyAction({databaseId: database.id, backupPolicy: value}),
@@ -22,6 +24,7 @@ export const CronInput = ({database, onSuccess}: CronInputProps) => {
toast.success(`Cron updated successfully.`);
onSuccess?.()
queryClient.invalidateQueries({queryKey: ["database-data", database.id]});
router.refresh();
},
onError: () => {
toast.error(`An error occurred while updating cron value.`);
@@ -2,6 +2,7 @@
import {DropZoneFile} from "@/components/wrappers/common/dropzone/dropzone-file";
import {useMutation, useQueryClient} from "@tanstack/react-query";
import {useRouter} from "next/navigation";
import {useState} from "react";
import {Loader2} from "lucide-react";
import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading";
@@ -16,6 +17,7 @@ type UploadRetentionZoneProps = {
export const UploadBackupZone = ({onSuccessAction, databaseId}: UploadRetentionZoneProps) => {
const queryClient = useQueryClient();
const router = useRouter();
const [isProcessing, setIsProcessing] = useState(false);
const [file, setFile] = useState<File | null>(null);
@@ -37,6 +39,7 @@ export const UploadBackupZone = ({onSuccessAction, databaseId}: UploadRetentionZ
toast.success(inner.actionSuccess?.message);
onSuccessAction?.()
queryClient.invalidateQueries({queryKey: ["database-data", databaseId]});
router.refresh();
} else {
toast.error(inner?.actionError?.message);
}
@@ -11,6 +11,7 @@ import {
} from "@/components/ui/form";
import {RetentionSettings, RetentionSettingsSchema} from "./backup-retention-settings.schema";
import {useMutation, useQueryClient} from "@tanstack/react-query";
import {useRouter} from "next/navigation";
import {updateOrCreateBackupRetentionPolicyAction} from "./backup-retention-settings.action";
import {DatabaseWith, RetentionPolicy} from "@/db/schema/07_database";
import {toast} from "sonner";
@@ -28,6 +29,7 @@ export type BackupRetentionSettingsFormProps = {
export const BackupRetentionSettingsForm = ({defaultValues, database}: BackupRetentionSettingsFormProps) => {
const queryClient = useQueryClient();
const router = useRouter();
const defaultValuesFormatted: RetentionSettings = {
type: defaultValues?.type,
@@ -55,6 +57,7 @@ export const BackupRetentionSettingsForm = ({defaultValues, database}: BackupRet
onSuccess: () => {
toast.success("Retention policy updated successfully.");
queryClient.invalidateQueries({queryKey: ["database-data", database.id]});
router.refresh();
},
onError: () => {
toast.error("An error occurred while updating retention policy.");
@@ -50,6 +50,8 @@ export const DatabaseContent = (props: DatabaseContentProps) => {
},
backups: props.backups,
restorations: props.restorations,
activeOrganizationChannels: props.activeOrganizationChannels,
activeOrganizationStorageChannels: props.activeOrganizationStorageChannels,
stats: {
totalBackups: props.totalBackups,
availableBackups: props.availableBackups,
@@ -64,6 +66,8 @@ export const DatabaseContent = (props: DatabaseContentProps) => {
const database = data?.database ?? props.database;
const backups = data?.backups ?? props.backups;
const restorations = data?.restorations ?? props.restorations;
const activeOrganizationChannels = data?.activeOrganizationChannels ?? props.activeOrganizationChannels;
const activeOrganizationStorageChannels = data?.activeOrganizationStorageChannels ?? props.activeOrganizationStorageChannels;
const stats = data?.stats ?? {
totalBackups: props.totalBackups,
availableBackups: props.availableBackups,
@@ -91,14 +95,14 @@ export const DatabaseContent = (props: DatabaseContentProps) => {
database={database}
kind={"notification"}
icon={<Megaphone/>}
channels={props.activeOrganizationChannels}
channels={activeOrganizationChannels}
organizationId={props.organizationId}
/>
<ChannelPoliciesModal
database={database}
icon={<HardDrive/>}
kind={"storage"}
channels={props.activeOrganizationStorageChannels}
channels={activeOrganizationStorageChannels}
organizationId={props.organizationId}
/>
<ImportModal database={database}/>