mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Working on the retention system.
This commit is contained in:
+2
-1
@@ -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>
|
||||||
|
|||||||
@@ -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" &&
|
||||||
|
|||||||
+5
-14
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-6
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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) : "";
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user