Working on the retention system.

This commit is contained in:
charlesgauthereau
2025-08-27 21:38:58 +02:00
parent 2f9e33f4db
commit 0f7b3eae11
6 changed files with 130 additions and 109 deletions
@@ -13,6 +13,7 @@ import * as drizzleDb from "@/db";
import {getOrganizationProjectDatabases} from "@/lib/services"; import {getOrganizationProjectDatabases} from "@/lib/services";
import {getOrganization} from "@/lib/auth/auth"; import {getOrganization} from "@/lib/auth/auth";
import {RetentionPolicySheet} from "@/components/wrappers/dashboard/database/retention-policy/retention-policy-sheet"; import {RetentionPolicySheet} from "@/components/wrappers/dashboard/database/retention-policy/retention-policy-sheet";
import {capitalizeFirstLetter} from "@/utils/text";
export default async function RoutePage(props: PageParams<{ export default async function RoutePage(props: PageParams<{
projectId: string; projectId: string;
@@ -87,7 +88,7 @@ export default async function RoutePage(props: PageParams<{
<Page> <Page>
<div className="justify-between gap-2 sm:flex"> <div className="justify-between gap-2 sm:flex">
<PageTitle className="flex items-center"> <PageTitle className="flex items-center">
{dbItem.name} {capitalizeFirstLetter(dbItem.name)}
<EditButton/> <EditButton/>
<CronButton database={dbItem}/> <CronButton database={dbItem}/>
<RetentionPolicySheet/> <RetentionPolicySheet/>
@@ -3,7 +3,9 @@ import { Page, PageActions, PageContent, PageDescription, PageTitle } from "@/fe
import {buttonVariants} from "@/components/ui/button"; import {buttonVariants} from "@/components/ui/button";
import {GearIcon} from "@radix-ui/react-icons"; import {GearIcon} from "@radix-ui/react-icons";
import Link from "next/link"; import Link from "next/link";
import { ButtonDeleteProject } from "@/components/wrappers/dashboard/projects/button-delete-project/button-delete-project"; import {
ButtonDeleteProject
} from "@/components/wrappers/dashboard/projects/button-delete-project/button-delete-project";
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination"; import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
import {ProjectDatabaseCard} from "@/components/wrappers/dashboard/projects/project-card/project-database-card"; import {ProjectDatabaseCard} from "@/components/wrappers/dashboard/projects/project-card/project-database-card";
import {notFound, redirect} from "next/navigation"; import {notFound, redirect} from "next/navigation";
@@ -12,12 +14,14 @@ import { db } from "@/db";
import {eq} from "drizzle-orm"; import {eq} from "drizzle-orm";
import {getOrganization} from "@/lib/auth/auth"; import {getOrganization} from "@/lib/auth/auth";
import * as drizzleDb from "@/db"; import * as drizzleDb from "@/db";
import {capitalizeFirstLetter} from "@/utils/text";
export default async function RoutePage(props: PageParams<{ export default async function RoutePage(props: PageParams<{
projectId: string projectId: string
}>) { }>) {
const { const {
projectId } = await props.params; projectId
} = await props.params;
const organization = await getOrganization({}); const organization = await getOrganization({});
if (!organization) { if (!organization) {
@@ -30,7 +34,11 @@ export default async function RoutePage(props: PageParams<{
if (!org) notFound(); if (!org) notFound();
const proj = await db.query.project.findFirst({ const proj = await db.query.project.findFirst({
where: (proj, { and, eq, not }) => and(eq(proj.id, projectId), eq(proj.organizationId, org.id), not(eq(proj.isArchived, true))), where: (proj, {
and,
eq,
not
}) => and(eq(proj.id, projectId), eq(proj.organizationId, org.id), not(eq(proj.isArchived, true))),
with: { with: {
databases: true, databases: true,
}, },
@@ -45,7 +53,7 @@ export default async function RoutePage(props: PageParams<{
<Page> <Page>
<div className="justify-between gap-2 sm:flex"> <div className="justify-between gap-2 sm:flex">
<PageTitle className="flex items-center"> <PageTitle className="flex items-center">
{proj.name} {capitalizeFirstLetter(proj.name)}
<Link className={buttonVariants({variant: "outline"})} href={`/dashboard/projects/${proj.id}/edit`}> <Link className={buttonVariants({variant: "outline"})} href={`/dashboard/projects/${proj.id}/edit`}>
<GearIcon className="w-7 h-7"/> <GearIcon className="w-7 h-7"/>
</Link> </Link>
+4 -2
View File
@@ -60,9 +60,11 @@ function SheetContent({
className={cn( className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500", "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
side === "right" && side === "right" &&
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm", "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l",
// "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
side === "left" && side === "left" &&
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm", "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r",
// "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
side === "top" && side === "top" &&
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b", "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
side === "bottom" && side === "bottom" &&
@@ -69,18 +69,9 @@ export function BackupRetentionSettings() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<Card> <div className="flex flex-col">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-balance"> <div className="px-3 space-y-6">
<Database className="h-5 w-5" />
Backup Retention Policy
</CardTitle>
<CardDescription className="text-pretty">
Configure how long to keep your .dump backup files. Choose from simple count-based, time-based, or
enterprise GFS rotation strategies.
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="space-y-4"> <div className="space-y-4">
<Label className="text-sm font-medium">Retention Policy Type</Label> <Label className="text-sm font-medium">Retention Policy Type</Label>
<RadioGroup <RadioGroup
@@ -314,8 +305,8 @@ export function BackupRetentionSettings() {
<Save className="h-4 w-4 mr-2" /> <Save className="h-4 w-4 mr-2" />
{isLoading ? "Saving Policy..." : "Save Retention Policy"} {isLoading ? "Saving Policy..." : "Save Retention Policy"}
</Button> </Button>
</CardContent> </div>
</Card> </div>
</div> </div>
) )
} }
@@ -1,6 +1,9 @@
import {Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger} from "@/components/ui/sheet"; import {Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger} from "@/components/ui/sheet";
import {Button} from "@/components/ui/button"; import {Button} from "@/components/ui/button";
import {DatabaseZap} from "lucide-react"; import {Database, DatabaseZap} from "lucide-react";
import {
BackupRetentionSettings
} from "@/components/wrappers/dashboard/database/retention-policy/backup-retention-settings";
export const RetentionPolicySheet = () => { export const RetentionPolicySheet = () => {
@@ -11,14 +14,20 @@ export const RetentionPolicySheet = () => {
<DatabaseZap/> <DatabaseZap/>
</Button> </Button>
</SheetTrigger> </SheetTrigger>
<SheetContent className="w-[400px] sm:w-[540px]"> <SheetContent
className="flex gap-4 p-4 w-[540px] sm:w-[800px] max-w-[800px] max-h-screen overflow-y-scroll"
>
<SheetHeader> <SheetHeader>
<SheetTitle>Are you absolutely sure?</SheetTitle> <SheetTitle className="flex items-center gap-2 text-balance">
<SheetDescription> <Database className="h-5 w-5" />
This action cannot be undone. This will permanently delete your account Backup Retention Policy
and remove your data from our servers. </SheetTitle>
<SheetDescription className="text-pretty">
Configure how long to keep your .dump backup files. Choose from simple count-based, time-based, or
enterprise GFS rotation strategies.
</SheetDescription> </SheetDescription>
</SheetHeader> </SheetHeader>
<BackupRetentionSettings/>
</SheetContent> </SheetContent>
</Sheet> </Sheet>
) )
+10
View File
@@ -0,0 +1,10 @@
export function truncateWords(text: string, wordLimit: number = 10): string {
if (!text) return "";
const words = text.trim().split(/\s+/);
if (words.length <= wordLimit) return text;
return words.slice(0, wordLimit).join(" ") + "…";
}
export function capitalizeFirstLetter(text: string): string {
return text ? text.charAt(0).toUpperCase() + text.slice(1) : "";
}