diff --git a/app/(customer)/dashboard/(organization)/projects/[projectId]/database/[databaseId]/page.tsx b/app/(customer)/dashboard/(organization)/projects/[projectId]/database/[databaseId]/page.tsx index fefe7c74..64d0beca 100644 --- a/app/(customer)/dashboard/(organization)/projects/[projectId]/database/[databaseId]/page.tsx +++ b/app/(customer)/dashboard/(organization)/projects/[projectId]/database/[databaseId]/page.tsx @@ -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={[]} /> diff --git a/src/components/wrappers/dashboard/backup/backup-button/backup-button.tsx b/src/components/wrappers/dashboard/backup/backup-button/backup-button.tsx index 71b15133..3ba0c5cd 100644 --- a/src/components/wrappers/dashboard/backup/backup-button/backup-button.tsx +++ b/src/components/wrappers/dashboard/backup/backup-button/backup-button.tsx @@ -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."); } diff --git a/src/components/wrappers/dashboard/database/backup/actions/backup-actions-form.tsx b/src/components/wrappers/dashboard/database/backup/actions/backup-actions-form.tsx index cbd99d26..c4d0a340 100644 --- a/src/components/wrappers/dashboard/database/backup/actions/backup-actions-form.tsx +++ b/src/components/wrappers/dashboard/database/backup/actions/backup-actions-form.tsx @@ -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); diff --git a/src/components/wrappers/dashboard/database/backup/actions/get-data.action.ts b/src/components/wrappers/dashboard/database/backup/actions/get-data.action.ts index 7e5447bc..f706c620 100644 --- a/src/components/wrappers/dashboard/database/backup/actions/get-data.action.ts +++ b/src/components/wrappers/dashboard/database/backup/actions/get-data.action.ts @@ -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, diff --git a/src/components/wrappers/dashboard/database/channels-policy/policy-form.tsx b/src/components/wrappers/dashboard/database/channels-policy/policy-form.tsx index 5c78802a..a3a856d5 100644 --- a/src/components/wrappers/dashboard/database/channels-policy/policy-form.tsx +++ b/src/components/wrappers/dashboard/database/channels-policy/policy-form.tsx @@ -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"); }, }); diff --git a/src/components/wrappers/dashboard/database/cron-button/cron-button.tsx b/src/components/wrappers/dashboard/database/cron-button/cron-button.tsx index 85c0423f..4d5026d0 100644 --- a/src/components/wrappers/dashboard/database/cron-button/cron-button.tsx +++ b/src/components/wrappers/dashboard/database/cron-button/cron-button.tsx @@ -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.`); diff --git a/src/components/wrappers/dashboard/database/cron-button/cron-input.tsx b/src/components/wrappers/dashboard/database/cron-button/cron-input.tsx index c8ded057..f3223e58 100644 --- a/src/components/wrappers/dashboard/database/cron-button/cron-input.tsx +++ b/src/components/wrappers/dashboard/database/cron-button/cron-input.tsx @@ -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(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.`); diff --git a/src/components/wrappers/dashboard/database/import/upload-backup-zone.tsx b/src/components/wrappers/dashboard/database/import/upload-backup-zone.tsx index 2ecd0ce9..0e4cea6a 100644 --- a/src/components/wrappers/dashboard/database/import/upload-backup-zone.tsx +++ b/src/components/wrappers/dashboard/database/import/upload-backup-zone.tsx @@ -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(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); } diff --git a/src/components/wrappers/dashboard/database/retention-policy/backup-retention-settings-form.tsx b/src/components/wrappers/dashboard/database/retention-policy/backup-retention-settings-form.tsx index 2e612e67..350f67f5 100644 --- a/src/components/wrappers/dashboard/database/retention-policy/backup-retention-settings-form.tsx +++ b/src/components/wrappers/dashboard/database/retention-policy/backup-retention-settings-form.tsx @@ -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."); diff --git a/src/components/wrappers/dashboard/projects/database/database-content.tsx b/src/components/wrappers/dashboard/projects/database/database-content.tsx index 3413df1a..9d8c801a 100644 --- a/src/components/wrappers/dashboard/projects/database/database-content.tsx +++ b/src/components/wrappers/dashboard/projects/database/database-content.tsx @@ -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={} - channels={props.activeOrganizationChannels} + channels={activeOrganizationChannels} organizationId={props.organizationId} /> } kind={"storage"} - channels={props.activeOrganizationStorageChannels} + channels={activeOrganizationStorageChannels} organizationId={props.organizationId} />