mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Finish migration prisma to drizzle.
This commit is contained in:
@@ -1,16 +1,21 @@
|
|||||||
import { PageParams } from "@/types/next";
|
import { PageParams } from "@/types/next";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
|
||||||
import { Page, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
|
import { Page, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
|
||||||
import { AdminTabs } from "@/components/wrappers/dashboard/admin/admin-tabs";
|
import { AdminTabs } from "@/components/wrappers/dashboard/admin/admin-tabs";
|
||||||
import { currentUser } from "@/lib/auth/current-user";
|
import { currentUser } from "@/lib/auth/current-user";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
|
import {eq, isNotNull, isNull} from "drizzle-orm";
|
||||||
|
|
||||||
|
|
||||||
export default async function RoutePage(props: PageParams<{}>) {
|
export default async function RoutePage(props: PageParams<{}>) {
|
||||||
const user = await currentUser()!;
|
const user = await currentUser();
|
||||||
|
|
||||||
const users = await db.query.user.findMany({
|
const users = await db.query.user.findMany({
|
||||||
where: (fields, { isNull, not }) => not(isNull(fields.deletedAt)),
|
where: (fields) => isNull(fields.deletedAt)
|
||||||
});
|
});
|
||||||
|
// const users = await db.query.user.findMany();
|
||||||
|
console.log("users",users);
|
||||||
|
|
||||||
const settings = await db.query.setting.findFirst({
|
const settings = await db.query.setting.findFirst({
|
||||||
where: (fields, { eq }) => eq(fields.name, "system"),
|
where: (fields, { eq }) => eq(fields.name, "system"),
|
||||||
@@ -22,7 +27,7 @@ export default async function RoutePage(props: PageParams<{}>) {
|
|||||||
<PageTitle>Administration Panel</PageTitle>
|
<PageTitle>Administration Panel</PageTitle>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageContent className="mt-10">
|
<PageContent className="mt-10">
|
||||||
<AdminTabs settings={settings!} currentUser={user} users={users} />
|
<AdminTabs settings={settings!} users={users} />
|
||||||
</PageContent>
|
</PageContent>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import {GearIcon} from "@radix-ui/react-icons";
|
import {GearIcon} from "@radix-ui/react-icons";
|
||||||
import {prisma} from "@/prisma";
|
|
||||||
import {PageParams} from "@/types/next";
|
import {PageParams} from "@/types/next";
|
||||||
import {Page, PageContent, PageDescription, PageTitle} from "@/features/layout/page";
|
import {Page, PageContent, PageDescription, PageTitle} from "@/features/layout/page";
|
||||||
import {formatDateLastContact} from "@/utils/date-formatting";
|
import {formatDateLastContact} from "@/utils/date-formatting";
|
||||||
@@ -9,38 +8,55 @@ import {Card, CardContent, CardHeader} from "@/components/ui/card";
|
|||||||
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
||||||
import {DatabaseCard} from "@/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard";
|
import {DatabaseCard} from "@/components/wrappers/dashboard/projects/ProjectCard/ProjectDatabaseCard";
|
||||||
import {AgentCardKey} from "@/components/wrappers/dashboard/agent/AgentCardKey/AgentCardKey";
|
import {AgentCardKey} from "@/components/wrappers/dashboard/agent/AgentCardKey/AgentCardKey";
|
||||||
|
import { db } from "@/db";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
import {and, eq} from "drizzle-orm";
|
||||||
|
import {notFound} from "next/navigation";
|
||||||
|
|
||||||
|
|
||||||
export default async function RoutePage(props: PageParams<{ agentId: string }>) {
|
export default async function RoutePage(props: PageParams<{ agentId: string }>) {
|
||||||
|
|
||||||
const {agentId} = await props.params
|
const {agentId} = await props.params
|
||||||
|
|
||||||
const agent = await prisma.agent.findUnique({
|
const agent = await db.query.agent.findFirst({
|
||||||
where: {
|
where: eq(drizzleDb.schemas.agent.id, agentId),
|
||||||
id: agentId,
|
with: {
|
||||||
},
|
databases: true
|
||||||
include: {
|
|
||||||
databases: {}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
//
|
||||||
|
console.log(agent)
|
||||||
|
|
||||||
const databaseId = 'db-123';
|
if (!agent) {
|
||||||
|
notFound()
|
||||||
const totalBackups = await prisma.backup.count({
|
}
|
||||||
where: {
|
//
|
||||||
databaseId: databaseId,
|
// const databaseId = 'db-123';
|
||||||
},
|
//
|
||||||
});
|
// const totalBackupsResult = await db
|
||||||
|
// .select({ count: drizzleDb.schemas.backup.id })
|
||||||
const successfulBackups = await prisma.backup.count({
|
// .from(drizzleDb.schemas.backup)
|
||||||
where: {
|
// .where(eq(drizzleDb.schemas.backup.databaseId, databaseId))
|
||||||
databaseId: databaseId,
|
// .execute();
|
||||||
status: 'success',
|
//
|
||||||
},
|
// const totalBackups = totalBackupsResult.length;
|
||||||
});
|
//
|
||||||
|
// const successfulBackupsResult = await db
|
||||||
const successRate = totalBackups > 0 ? (successfulBackups / totalBackups) * 100 : null
|
// .select({ count: drizzleDb.schemas.backup.id })
|
||||||
|
// .from(drizzleDb.schemas.backup)
|
||||||
|
// .where(
|
||||||
|
// and(
|
||||||
|
// eq(drizzleDb.schemas.backup.databaseId, databaseId),
|
||||||
|
// eq(drizzleDb.schemas.backup.status, "success")
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// .execute();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// const successfulBackups = successfulBackupsResult.length;
|
||||||
|
//
|
||||||
|
// const successRate =
|
||||||
|
// totalBackups > 0 ? (successfulBackups / totalBackups) * 100 : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
@@ -73,7 +89,7 @@ export default async function RoutePage(props: PageParams<{ agentId: string }>)
|
|||||||
Success rate
|
Success rate
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{successRate ?? "Unavailable for now."}
|
{/*{successRate ?? "Unavailable for now."}*/}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="w-full sm:w-auto flex-1">
|
<Card className="w-full sm:w-auto flex-1">
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import Link from "next/link";
|
|||||||
import { Page, PageActions, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
|
import { Page, PageActions, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
export const dynamic = "force-dynamic";
|
|
||||||
|
|
||||||
export default async function RoutePage(props: PageParams<{}>) {
|
export default async function RoutePage(props: PageParams<{}>) {
|
||||||
const agents = await db.query.agent.findMany();
|
const agents = await db.query.agent.findMany();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
const org = await db.query.organization.findFirst({
|
const org = await db.query.organization.findFirst({
|
||||||
where: eq(drizzleDb.schemas.organization.slug, "default"),
|
where: eq(drizzleDb.schemas.organization.slug, "default"),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default async function RoutePage(props: PageParams<{
|
|||||||
<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}
|
{proj.name}
|
||||||
<Link className={buttonVariants({ variant: "outline" })} href={`/dashboard/${organization.slug}/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>
|
||||||
</PageTitle>
|
</PageTitle>
|
||||||
|
|||||||
@@ -1,26 +1,19 @@
|
|||||||
import {PageParams} from "@/types/next";
|
import {PageParams} from "@/types/next";
|
||||||
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||||
import {getCurrentOrganizationSlug} from "@/features/dashboard/organization-cookie";
|
|
||||||
import {prisma} from "@/prisma";
|
|
||||||
import {requiredCurrentUser} from "@/auth/current-user";
|
|
||||||
import {notFound} from "next/navigation";
|
import {notFound} from "next/navigation";
|
||||||
import {OrganizationForm} from "@/components/wrappers/dashboard/organization/OrganizationForm/OrganizationForm";
|
import {OrganizationForm} from "@/components/wrappers/dashboard/organization/OrganizationForm/OrganizationForm";
|
||||||
import {getOrganization} from "@/lib/auth/auth";
|
import {getOrganization} from "@/lib/auth/auth";
|
||||||
|
|
||||||
|
|
||||||
export default async function RoutePage(props: PageParams<{
|
export default async function RoutePage(props: PageParams<{
|
||||||
slug: string;
|
|
||||||
}>) {
|
}>) {
|
||||||
|
const organization = await getOrganization({});
|
||||||
const {slug: organizationSlug} = await props.params;
|
|
||||||
|
|
||||||
const organization = await getOrganization({organizationSlug});
|
|
||||||
|
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
notFound()
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<Page>
|
<Page>
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ import {Page, PageActions, PageContent, PageDescription, PageHeader, PageTitle}
|
|||||||
import {currentUser} from "@/lib/auth/current-user";
|
import {currentUser} from "@/lib/auth/current-user";
|
||||||
import {getOrganization} from "@/lib/auth/auth";
|
import {getOrganization} from "@/lib/auth/auth";
|
||||||
import {notFound} from "next/navigation";
|
import {notFound} from "next/navigation";
|
||||||
import {requiredCurrentUser} from "@/auth/current-user";
|
|
||||||
import {SettingsTabs} from "@/components/wrappers/dashboard/settings/SettingsTabs/SettingsTabs";
|
|
||||||
import {getCurrentOrganizationSlug} from "@/features/dashboard/organization-cookie";
|
|
||||||
import {
|
import {
|
||||||
DeleteOrganizationButton
|
DeleteOrganizationButton
|
||||||
} from "@/components/wrappers/dashboard/organization/DeleteOrganization/DeleteOrganizationButton";
|
} from "@/components/wrappers/dashboard/organization/DeleteOrganization/DeleteOrganizationButton";
|
||||||
@@ -13,50 +10,13 @@ import {EditButtonSettings} from "@/components/wrappers/dashboard/settings/EditB
|
|||||||
|
|
||||||
|
|
||||||
export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||||
const {slug: organizationSlug} = await props.params;
|
const organization = await getOrganization({});
|
||||||
|
|
||||||
const user = await currentUser();
|
const user = await currentUser();
|
||||||
|
|
||||||
const organization = await getOrganization({organizationSlug});
|
if (!organization) {
|
||||||
|
|
||||||
if (!organization || organization?.slug !== organizationSlug) {
|
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// const organization = await prisma.organization.findUnique({
|
|
||||||
// where: {
|
|
||||||
// slug: currentOrganizationSlug,
|
|
||||||
// },
|
|
||||||
// include: {
|
|
||||||
// users:{
|
|
||||||
// include:{
|
|
||||||
// user: {}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// const currentOrganizationUser = await prisma.userOrganization.findFirst({
|
|
||||||
// where:{
|
|
||||||
// userId: user.id,
|
|
||||||
// organization:{
|
|
||||||
// slug: currentOrganizationSlug != "" ? currentOrganizationSlug : "default",
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// if (currentOrganizationUser.role != "admin") {
|
|
||||||
// notFound()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// const settings = await prisma.settings.findUnique({
|
|
||||||
// where: {
|
|
||||||
// name: "system"
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
@@ -76,7 +36,7 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
|||||||
Manage your organization settings.
|
Manage your organization settings.
|
||||||
</PageDescription>
|
</PageDescription>
|
||||||
<PageContent>
|
<PageContent>
|
||||||
{/*<SettingsTabs settings={settings} currentUser={user} users={organization.users}/>*/}
|
{/* TODO add the list of organisation members (add, remove, edit) */}
|
||||||
</PageContent>
|
</PageContent>
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ import { notFound } from "next/navigation";
|
|||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { asc, count, eq, inArray } from "drizzle-orm";
|
import { asc, count, eq, inArray } from "drizzle-orm";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
|
import {getOrganization} from "@/lib/auth/auth";
|
||||||
|
|
||||||
export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
export default async function RoutePage(props: PageParams<{ }>) {
|
||||||
const { slug: organizationSlug } = await props.params;
|
const organization = await getOrganization({});
|
||||||
|
|
||||||
const currentOrganizationSlug = await getCurrentOrganizationSlug();
|
if (!organization) {
|
||||||
if (currentOrganizationSlug !== organizationSlug) {
|
|
||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
const org = await db.query.organization.findFirst({
|
const org = await db.query.organization.findFirst({
|
||||||
where: eq(drizzleDb.schemas.organization.slug, currentOrganizationSlug),
|
where: eq(drizzleDb.schemas.organization.slug, organization.slug),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!org) notFound();
|
if (!org) notFound();
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {prisma} from "@/prisma";
|
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {uploadLocalPrivate} from "@/features/upload/private/upload.action";
|
import {uploadLocalPrivate} from "@/features/upload/private/upload.action";
|
||||||
import {v4 as uuidv4} from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
import {Backup, Database} from "@prisma/client";
|
|
||||||
import {eventEmitter} from "../../../events/route";
|
import {eventEmitter} from "../../../events/route";
|
||||||
|
import {db} from "@/db";
|
||||||
|
import {Backup} from "@/db/schema/06_database";
|
||||||
|
import {and, eq} from "drizzle-orm";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
|
||||||
export async function POST(
|
export async function POST(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: Promise<{ agentId: string }> }
|
{params}: { params: Promise<{ agentId: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const contentType = request.headers.get("Content-Type");
|
const contentType = request.headers.get("Content-Type");
|
||||||
|
|
||||||
if (!contentType || !contentType.includes("multipart/form-data")) {
|
if (!contentType || !contentType.includes("multipart/form-data")) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Unsupported or missing Content-Type" },
|
{error: "Unsupported or missing Content-Type"},
|
||||||
{ status: 400 }
|
{status: 400}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
eventEmitter.emit('modification', { update: true });
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
const agentId = (await params).agentId;
|
const agentId = (await params).agentId;
|
||||||
const formData = await request.formData();
|
const formData = await request.formData();
|
||||||
@@ -28,61 +30,64 @@ export async function POST(
|
|||||||
|
|
||||||
if (!generatedId || !isUuidv4(generatedId)) {
|
if (!generatedId || !isUuidv4(generatedId)) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "generatedId is not a valid UUID" },
|
{error: "generatedId is not a valid UUID"},
|
||||||
{ status: 400 }
|
{status: 400}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const agent = await prisma.agent.findFirst({
|
const agent = await db.query.agent.findFirst({
|
||||||
where: { id: agentId },
|
where: eq(drizzleDb.schemas.agent.id, agentId),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!agent) {
|
if (!agent) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Agent not found" },
|
{error: "Agent not found"},
|
||||||
{ status: 404 }
|
{status: 404}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const database = await prisma.database.findFirst({
|
const database = await db.query.database.findFirst({
|
||||||
where: { generatedId },
|
where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!database) {
|
if (!database) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Database associated with generatedId not found" },
|
{error: "Database associated with generatedId not found"},
|
||||||
{ status: 404 }
|
{status: 404}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let backup: Backup | null = null;
|
let backup: Backup | null | undefined = null;
|
||||||
|
|
||||||
if (method === "automatic") {
|
if (method === "automatic") {
|
||||||
backup = await prisma.backup.create({
|
[backup] = await db
|
||||||
data: {
|
.insert(drizzleDb.schemas.backup)
|
||||||
status: "ongoing",
|
.values({
|
||||||
|
status: 'ongoing',
|
||||||
databaseId: database.id,
|
databaseId: database.id,
|
||||||
},
|
})
|
||||||
});
|
.returning();
|
||||||
|
|
||||||
|
|
||||||
if (!backup) {
|
if (!backup) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Unable to create an automatic backup" },
|
{error: "Unable to create an automatic backup"},
|
||||||
{ status: 500 }
|
{status: 500}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
backup = await prisma.backup.findFirst({
|
backup = await db.query.backup.findFirst({
|
||||||
where: {
|
where: and(
|
||||||
status: "ongoing",
|
eq(drizzleDb.schemas.backup.status, 'ongoing'),
|
||||||
databaseId: database.id,
|
eq(drizzleDb.schemas.backup.databaseId, database.id),
|
||||||
},
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (!backup) {
|
if (!backup) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Unable to find the corresponding backup" },
|
{error: "Unable to find the corresponding backup"},
|
||||||
{ status: 404 }
|
{status: 404}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +99,8 @@ export async function POST(
|
|||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "File is required for successful backup" },
|
{error: "File is required for successful backup"},
|
||||||
{ status: 400 }
|
{status: 400}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,49 +108,52 @@ export async function POST(
|
|||||||
const fileName = `${uuid}.dump`;
|
const fileName = `${uuid}.dump`;
|
||||||
const buffer = Buffer.from(await file.arrayBuffer());
|
const buffer = Buffer.from(await file.arrayBuffer());
|
||||||
|
|
||||||
const { success, message, filePath } = await uploadLocalPrivate(fileName, buffer);
|
const {success, message, filePath} = await uploadLocalPrivate(fileName, buffer);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: message },
|
{error: message},
|
||||||
{ status: 500 }
|
{status: 500}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await prisma.backup.update({
|
await db
|
||||||
where: { id: backup.id },
|
.update(drizzleDb.schemas.backup)
|
||||||
data: {
|
.set({
|
||||||
file: fileName,
|
file: fileName,
|
||||||
status: "success",
|
status: 'success',
|
||||||
},
|
})
|
||||||
});
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
eventEmitter.emit('modification', { update: true });
|
|
||||||
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
message: "Backup successfully uploaded",
|
message: "Backup successfully uploaded",
|
||||||
},
|
},
|
||||||
{ status: 200 }
|
{status: 200}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await prisma.backup.update({
|
|
||||||
where: { id: backup.id },
|
await db
|
||||||
data: { status: "failed" },
|
.update(drizzleDb.schemas.backup)
|
||||||
});
|
.set({status: 'failed'})
|
||||||
eventEmitter.emit('modification', { update: true });
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
|
|
||||||
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
message: "Backup successfully updated with status failed",
|
message: "Backup successfully updated with status failed",
|
||||||
},
|
},
|
||||||
{ status: 200 }
|
{status: 200}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in POST handler:", error);
|
console.error("Error in POST handler:", error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Internal server error" },
|
{error: "Internal server error"},
|
||||||
{ status: 500 }
|
{status: 500}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {prisma} from "@/prisma";
|
|
||||||
import {eventEmitter} from "../../../events/route";
|
import {eventEmitter} from "../../../events/route";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
import {db} from "@/db";
|
||||||
|
import {and, eq} from "drizzle-orm";
|
||||||
|
|
||||||
|
|
||||||
export type BodyResultRestore = {
|
export type BodyResultRestore = {
|
||||||
generatedId: string
|
generatedId: string
|
||||||
status: string
|
status: string
|
||||||
}
|
}
|
||||||
|
type RestorationStatus = 'waiting' | 'ongoing' | 'failed' | 'success';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function POST(
|
export async function POST(
|
||||||
@@ -17,7 +20,7 @@ export async function POST(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eventEmitter.emit('modification', { update: true });
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
const agentId = (await params).agentId
|
const agentId = (await params).agentId
|
||||||
const body: BodyResultRestore = await request.json();
|
const body: BodyResultRestore = await request.json();
|
||||||
@@ -33,53 +36,44 @@ export async function POST(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const agent = await prisma.agent.findFirst({
|
const agent = await db.query.agent.findFirst({
|
||||||
where: {
|
where: eq(drizzleDb.schemas.agent.id, agentId)
|
||||||
id: agentId
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
if (!agent) {
|
if (!agent) {
|
||||||
return NextResponse.json({error: "Agent not found"}, {status: 404})
|
return NextResponse.json({error: "Agent not found"}, {status: 404})
|
||||||
}
|
}
|
||||||
|
|
||||||
const database = await prisma.database.findFirst({
|
const database = await db.query.database.findFirst({
|
||||||
where: {
|
where: eq(drizzleDb.schemas.database.agentDatabaseId, body.generatedId)
|
||||||
generatedId: body.generatedId
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!database) {
|
if (!database) {
|
||||||
return NextResponse.json({error: "Database associated with generatedId provided not found"}, {status: 404})
|
return NextResponse.json({error: "Database associated with generatedId provided not found"}, {status: 404})
|
||||||
}
|
}
|
||||||
|
|
||||||
const restoration = await prisma.restoration.findFirst({
|
const restoration = await db.query.restoration.findFirst({
|
||||||
where: {
|
where: and(eq(drizzleDb.schemas.restoration.status, "ongoing"), eq(drizzleDb.schemas.restoration.databaseId, database.id),)
|
||||||
status : "ongoing",
|
|
||||||
databaseId: database.id
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!restoration) {
|
if (!restoration) {
|
||||||
return NextResponse.json({error: "Unable to fin the corresponding restoration"}, {status: 404})
|
return NextResponse.json({error: "Unable to fin the corresponding restoration"}, {status: 404})
|
||||||
}
|
}
|
||||||
|
|
||||||
await prisma.restoration.update({
|
await db
|
||||||
where:{
|
.update(drizzleDb.schemas.restoration)
|
||||||
id : restoration.id
|
.set({ status: body.status as RestorationStatus })
|
||||||
},
|
.where(eq(drizzleDb.schemas.restoration.id, restoration.id));
|
||||||
data: {
|
|
||||||
status: body.status
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
message: true,
|
message: true,
|
||||||
details: "Restoration successfully updated"
|
details: "Restoration successfully updated"
|
||||||
}
|
}
|
||||||
|
|
||||||
eventEmitter.emit('modification', { update: true });
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
|
|
||||||
return Response.json(response , {status: 200})
|
return Response.json(response, {status: 200})
|
||||||
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import {Agent, Database} from "@prisma/client";
|
|
||||||
import {prisma} from "@/prisma";
|
|
||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {Body} from "./route";
|
import {Body} from "./route";
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {getFileUrlPresignedLocal} from "@/features/upload/private/upload.action";
|
import {getFileUrlPresignedLocal} from "@/features/upload/private/upload.action";
|
||||||
|
import {Agent} from "@/db/schema/07_agent";
|
||||||
|
import {Database} from "@/db/schema/06_database";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
import {db as dbClient} from "@/db";
|
||||||
|
import {and, eq} from "drizzle-orm";
|
||||||
|
|
||||||
export async function handleDatabases(body: Body, agent: Agent, lastContact: Date) {
|
export async function handleDatabases(body: Body, agent: Agent, lastContact: Date) {
|
||||||
const databasesResponse = [];
|
const databasesResponse = [];
|
||||||
|
|
||||||
const formatDatabase = (database: Database, backupAction: boolean, restoreAction: boolean, UrlBackup: string) => ({
|
const formatDatabase = (database: Database, backupAction: boolean, restoreAction: boolean, UrlBackup: string) => ({
|
||||||
generatedId: database.generatedId,
|
generatedId: database.agentDatabaseId,
|
||||||
dbms: database.dbms,
|
dbms: database.dbms,
|
||||||
data: {
|
data: {
|
||||||
backup: {
|
backup: {
|
||||||
@@ -25,15 +27,14 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const db of body.databases) {
|
for (const db of body.databases) {
|
||||||
const existingDatabase = await prisma.database.findFirst({
|
|
||||||
where: {
|
const existingDatabase = await dbClient.query.database.findFirst({
|
||||||
generatedId: db.generatedId,
|
where: eq(drizzleDb.schemas.database.agentDatabaseId, db.generatedId)
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let backupAction: boolean = false
|
let backupAction: boolean = false
|
||||||
let restoreAction: boolean = false
|
let restoreAction: boolean = false
|
||||||
let UrlBackup: string = null
|
let UrlBackup: string = ""
|
||||||
|
|
||||||
if (!existingDatabase) {
|
if (!existingDatabase) {
|
||||||
if (!isUuidv4(db.generatedId)) {
|
if (!isUuidv4(db.generatedId)) {
|
||||||
@@ -42,74 +43,69 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat
|
|||||||
{ status: 500 }
|
{ status: 500 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const databaseCreated = await prisma.database.create({
|
|
||||||
data: {
|
const [databaseCreated] = await dbClient
|
||||||
|
.insert(drizzleDb.schemas.database)
|
||||||
|
.values({
|
||||||
agentId: agent.id,
|
agentId: agent.id,
|
||||||
name: db.name,
|
name: db.name,
|
||||||
dbms: db.dbms,
|
dbms: db.dbms,
|
||||||
generatedId: db.generatedId,
|
agentDatabaseId: db.generatedId,
|
||||||
lastContact: lastContact,
|
lastContact: lastContact,
|
||||||
},
|
})
|
||||||
});
|
.returning();
|
||||||
|
|
||||||
if (databaseCreated) {
|
if (databaseCreated) {
|
||||||
databasesResponse.push(formatDatabase(databaseCreated, backupAction,restoreAction, UrlBackup));
|
databasesResponse.push(formatDatabase(databaseCreated, backupAction,restoreAction, UrlBackup));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const databaseUpdated = await prisma.database.update({
|
|
||||||
where: {
|
|
||||||
id: existingDatabase.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
lastContact: lastContact,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const backup = await prisma.backup.findFirst({
|
|
||||||
where: {
|
|
||||||
databaseId: databaseUpdated.id,
|
const [databaseUpdated] = await dbClient
|
||||||
status: "waiting"
|
.update(drizzleDb.schemas.database)
|
||||||
}
|
.set({ lastContact: lastContact })
|
||||||
|
.where(eq(drizzleDb.schemas.database.id, existingDatabase.id))
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const backup = await dbClient.query.backup.findFirst({
|
||||||
|
where: and(eq(drizzleDb.schemas.backup.databaseId, databaseUpdated.id), eq(drizzleDb.schemas.backup.status,"waiting"))
|
||||||
})
|
})
|
||||||
|
|
||||||
const restoration = await prisma.restoration.findFirst({
|
|
||||||
where:{
|
const restoration = await dbClient.query.restoration.findFirst({
|
||||||
databaseId: databaseUpdated.id,
|
where: and(eq(drizzleDb.schemas.restoration.databaseId, databaseUpdated.id), eq(drizzleDb.schemas.restoration.status,"waiting"))
|
||||||
status: "waiting"
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
if(backup){
|
if(backup){
|
||||||
backupAction = true
|
backupAction = true
|
||||||
await prisma.backup.update({
|
|
||||||
where:{
|
await dbClient
|
||||||
id: backup.id
|
.update(drizzleDb.schemas.backup)
|
||||||
},
|
.set({ status: "ongoing" })
|
||||||
data: {
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
status: "ongoing"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(restoration){
|
if(restoration){
|
||||||
restoreAction = true
|
restoreAction = true
|
||||||
|
|
||||||
const backupToRestore = await prisma.backup.findFirst({
|
|
||||||
where:{
|
const backupToRestore = await dbClient.query.backup.findFirst({
|
||||||
id: restoration.backupId
|
where: eq(drizzleDb.schemas.backup.id, restoration.backupId),
|
||||||
}
|
|
||||||
})
|
|
||||||
const fileName = backupToRestore.file
|
|
||||||
UrlBackup = await getFileUrlPresignedLocal(fileName)
|
|
||||||
await prisma.restoration.update({
|
|
||||||
where: {
|
|
||||||
id: restoration.id
|
|
||||||
},
|
|
||||||
data:{
|
|
||||||
status: "ongoing"
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const fileName = backupToRestore?.file
|
||||||
|
UrlBackup = await getFileUrlPresignedLocal(fileName ?? "")
|
||||||
|
|
||||||
|
await dbClient
|
||||||
|
.update(drizzleDb.schemas.restoration)
|
||||||
|
.set({ status: "ongoing" })
|
||||||
|
.where(eq(drizzleDb.schemas.restoration.id, restoration.id));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import {prisma} from "@/prisma";
|
|
||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {Dbms} from "@prisma/client";
|
|
||||||
import {getFileUrlPresignedLocal} from "@/features/upload/private/upload.action";
|
import {getFileUrlPresignedLocal} from "@/features/upload/private/upload.action";
|
||||||
import {handleDatabases} from "./helpers";
|
import {handleDatabases} from "./helpers";
|
||||||
import {eventEmitter} from "../../../events/route";
|
import {eventEmitter} from "../../../events/route";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
import {db} from "@/db";
|
||||||
|
import {EDbmsSchema} from "@/db/schema/types";
|
||||||
|
import {eq} from "drizzle-orm";
|
||||||
|
|
||||||
export type databaseAgent = {
|
export type databaseAgent = {
|
||||||
name: string,
|
name: string,
|
||||||
dbms: Dbms,
|
dbms: EDbmsSchema,
|
||||||
generatedId: string
|
generatedId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,25 +34,23 @@ export async function POST(
|
|||||||
const body: Body = await request.json();
|
const body: Body = await request.json();
|
||||||
const lastContact = new Date();
|
const lastContact = new Date();
|
||||||
|
|
||||||
const agent = await prisma.agent.findFirst({
|
|
||||||
where: {
|
const agent = await db.query.agent.findFirst({
|
||||||
id: agentId
|
where: eq(drizzleDb.schemas.agent.id, agentId),
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!agent) {
|
if (!agent) {
|
||||||
return NextResponse.json({error: "Agent not found"}, {status: 404})
|
return NextResponse.json({error: "Agent not found"}, {status: 404})
|
||||||
}
|
}
|
||||||
const databasesResponse = await handleDatabases(body, agent, lastContact)
|
const databasesResponse = await handleDatabases(body, agent, lastContact)
|
||||||
await prisma.agent.update({
|
|
||||||
where:{
|
|
||||||
id: agentId,
|
|
||||||
},
|
|
||||||
data:{
|
|
||||||
lastContact: lastContact,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
eventEmitter.emit('modification', { update: true });
|
|
||||||
|
await db
|
||||||
|
.update(drizzleDb.schemas.agent)
|
||||||
|
.set({ lastContact: lastContact })
|
||||||
|
.where(eq(drizzleDb.schemas.agent.id, agentId));
|
||||||
|
|
||||||
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
agent: {
|
agent: {
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
"use client";
|
"use client"
|
||||||
|
import {ColumnDef} from "@tanstack/react-table";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import {Badge} from "@/components/ui/badge";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import {updateUserAction} from "@/components/wrappers/dashboard/profile/UserForm/user-form.action";
|
||||||
import { User } from "@prisma/client";
|
import {useMutation} from "@tanstack/react-query";
|
||||||
import { updateUserAction } from "@/components/wrappers/dashboard/profile/UserForm/user-form.action";
|
import {toast} from "sonner";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import {useRouter} from "next/navigation";
|
||||||
import { toast } from "sonner";
|
import {useState} from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import {Trash2} from "lucide-react";
|
||||||
import { useState } from "react";
|
import {deleteUserAction} from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/delete-account.action";
|
||||||
import { Trash2 } from "lucide-react";
|
import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading";
|
||||||
import { deleteUserAction } from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/delete-account.action";
|
import {User} from "@/db/schema/01_user";
|
||||||
import { ButtonWithLoading } from "@/components/wrappers/common/button/button-with-loading";
|
import {useSession} from "@/lib/auth/auth-client";
|
||||||
|
|
||||||
export const usersColumnsAdmin: ColumnDef<User>[] = [
|
export const usersColumnsAdmin: ColumnDef<User>[] = [
|
||||||
{
|
{
|
||||||
accessorKey: "role",
|
accessorKey: "role",
|
||||||
header: "Role",
|
header: "Role",
|
||||||
cell: ({ row }) => {
|
cell: ({row}) => {
|
||||||
const [role, setRole] = useState<string>(row.getValue("role"));
|
const [role, setRole] = useState<string>(row.getValue("role"));
|
||||||
|
|
||||||
const updateMutation = useMutation({
|
const updateMutation = useMutation({
|
||||||
mutationFn: () => updateUserAction({ id: row.original.id, data: { role: role } }),
|
mutationFn: () => updateUserAction({id: row.original.id, data: {role: role}}),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success(`User updated successfully.`);
|
toast.success(`User updated successfully.`);
|
||||||
},
|
},
|
||||||
@@ -53,22 +53,19 @@ export const usersColumnsAdmin: ColumnDef<User>[] = [
|
|||||||
{
|
{
|
||||||
accessorKey: "updatedAt",
|
accessorKey: "updatedAt",
|
||||||
header: "Updated At",
|
header: "Updated At",
|
||||||
cell: ({ row }) => {
|
cell: ({row}) => {
|
||||||
return new Date(row.getValue("updatedAt")).toLocaleString("fr-FR");
|
return new Date(row.getValue("updatedAt")).toLocaleString("fr-FR", {
|
||||||
},
|
timeZone: "Europe/Paris",
|
||||||
},
|
});
|
||||||
{
|
|
||||||
accessorKey: "authMethod",
|
|
||||||
header: "Method",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
return <Badge variant="outline">{row.getValue("authMethod")}</Badge>;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "Action",
|
header: "Action",
|
||||||
id: "actions",
|
id: "actions",
|
||||||
cell: ({ row }) => {
|
cell: ({row}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const {data: session, isPending} = useSession();
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: () => deleteUserAction(row.original.id),
|
mutationFn: () => deleteUserAction(row.original.id),
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
@@ -77,17 +74,23 @@ export const usersColumnsAdmin: ColumnDef<User>[] = [
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ButtonWithLoading
|
{!session || session?.user.email === row.original.email ? null :
|
||||||
variant="outline"
|
<ButtonWithLoading
|
||||||
text=""
|
variant="outline"
|
||||||
icon={<Trash2 color="red" size={15} />}
|
text=""
|
||||||
onClick={async () => {
|
icon={<Trash2 color="red" size={15}/>}
|
||||||
await mutation.mutateAsync();
|
onClick={async () => {
|
||||||
}}
|
await mutation.mutateAsync();
|
||||||
size="icon"
|
}}
|
||||||
/>
|
size="icon"
|
||||||
|
/>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||||
import { ProjectWith } from "@/db/schema";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import {ProjectWith} from "@/db/schema/05_project";
|
||||||
|
|
||||||
export type projectCardProps = {
|
export type projectCardProps = {
|
||||||
data: ProjectWith;
|
data: ProjectWith;
|
||||||
@@ -13,7 +13,7 @@ export const ProjectCard = (props: projectCardProps) => {
|
|||||||
const { data: project, organizationSlug } = props;
|
const { data: project, organizationSlug } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/dashboard/${organizationSlug}/projects/${project.id}`}>
|
<Link href={`/dashboard/projects/${project.id}`}>
|
||||||
<Card className="flex flex-row justify-between">
|
<Card className="flex flex-row justify-between">
|
||||||
<div className="">
|
<div className="">
|
||||||
<CardHeader>{project.name}</CardHeader>
|
<CardHeader>{project.name}</CardHeader>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const ProjectDatabaseCard = (props: projectDatabaseCardProps) => {
|
|||||||
const { organizationSlug, data: database, extendedProps: extendedProps } = props;
|
const { organizationSlug, data: database, extendedProps: extendedProps } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/dashboard/${organizationSlug}/projects/${extendedProps.id}/database/${database.id}`}>
|
<Link href={`/dashboard/projects/${extendedProps.id}/database/${database.id}`}>
|
||||||
<DatabaseCard data={database} />
|
<DatabaseCard data={database} />
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export const ProjectForm = (props: projectFormProps) => {
|
|||||||
if (project && project.data) {
|
if (project && project.data) {
|
||||||
if (project.data.success) {
|
if (project.data.success) {
|
||||||
project.data.actionSuccess && toast.success(project.data.actionSuccess.message);
|
project.data.actionSuccess && toast.success(project.data.actionSuccess.message);
|
||||||
router.push(`/dashboard/${props.organization.slug}/projects/${project.data.value!.id}`);
|
router.push(`/dashboard/projects/${project.data.value!.id}`);
|
||||||
router.refresh();
|
router.refresh();
|
||||||
} else {
|
} else {
|
||||||
project.data.actionError && toast.error(project.data.actionError.message || "Unknown error occurred.");
|
project.data.actionError && toast.error(project.data.actionError.message || "Unknown error occurred.");
|
||||||
|
|||||||
@@ -2,20 +2,14 @@ import {
|
|||||||
Sidebar,
|
Sidebar,
|
||||||
SidebarContent,
|
SidebarContent,
|
||||||
SidebarFooter,
|
SidebarFooter,
|
||||||
SidebarGroup,
|
|
||||||
SidebarGroupContent,
|
|
||||||
SidebarGroupLabel,
|
|
||||||
SidebarHeader,
|
SidebarHeader,
|
||||||
SidebarMenu as SM,
|
SidebarMenu as SM,
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
import {SidebarItem, SidebarMenu} from "@/components/wrappers/dashboard/sideBar/SideBarMenu/SideBarMenu";
|
|
||||||
import {OrganizationCombobox} from "@/components/wrappers/dashboard/organization/organization-combobox";
|
import {OrganizationCombobox} from "@/components/wrappers/dashboard/organization/organization-combobox";
|
||||||
import {SideBarLogo} from "@/components/wrappers/dashboard/sideBar/SideBarLogo/SideBarLogo";
|
import {SideBarLogo} from "@/components/wrappers/dashboard/sideBar/SideBarLogo/SideBarLogo";
|
||||||
import {SideBarFooterCredit} from "@/components/wrappers/dashboard/sideBar/SideBarFooterCredit/SideBarFooterCredit";
|
import {SideBarFooterCredit} from "@/components/wrappers/dashboard/sideBar/SideBarFooterCredit/SideBarFooterCredit";
|
||||||
import {LoggedInButton} from "@/components/wrappers/dashboard/loggedInButton/LoggedInButton";
|
import {LoggedInButton} from "@/components/wrappers/dashboard/loggedInButton/LoggedInButton";
|
||||||
import {Layers, ChartArea, Settings, ShieldHalf} from "lucide-react";
|
|
||||||
import {authClient} from "@/lib/auth/auth-client";
|
|
||||||
import {SidebarContentA} from "./sidebar-content";
|
import {SidebarContentA} from "./sidebar-content";
|
||||||
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
|
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
|
||||||
import {notFound} from "next/navigation";
|
import {notFound} from "next/navigation";
|
||||||
@@ -31,7 +25,6 @@ export async function AppSidebar() {
|
|||||||
|
|
||||||
const organization = await getOrganization({organizationId: member.organizationId});
|
const organization = await getOrganization({organizationId: member.organizationId});
|
||||||
|
|
||||||
//todo: à revoir
|
|
||||||
console.log("organization", organization);
|
console.log("organization", organization);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ export const SidebarContentA = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const adminItems: SidebarItem[] = [
|
const adminItems: SidebarItem[] = [
|
||||||
{
|
{
|
||||||
type: "list",
|
type: "list",
|
||||||
@@ -62,13 +64,24 @@ export const SidebarContentA = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
activeOrganization && (
|
activeOrganization && (
|
||||||
|
<>
|
||||||
|
<SidebarGroup>
|
||||||
|
<SidebarGroupLabel>Application</SidebarGroupLabel>
|
||||||
|
<SidebarGroupContent>
|
||||||
|
<SidebarMenu items={appItems} baseUrl={`/dashboard`} />
|
||||||
|
</SidebarGroupContent>
|
||||||
|
</SidebarGroup>
|
||||||
|
{(session && (session.user.role === "admin" || session.user.role === "superadmin")) && (
|
||||||
|
<SidebarGroup>
|
||||||
|
<SidebarGroupLabel>Administration</SidebarGroupLabel>
|
||||||
|
<SidebarGroupContent>
|
||||||
|
<SidebarMenu items={adminItems} baseUrl={`/dashboard`} />
|
||||||
|
</SidebarGroupContent>
|
||||||
|
</SidebarGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
<SidebarGroup>
|
|
||||||
<SidebarGroupLabel>Application</SidebarGroupLabel>
|
|
||||||
<SidebarGroupContent>
|
|
||||||
<SidebarMenu items={appItems} baseUrl={`/dashboard/${activeOrganization.slug}`} />
|
|
||||||
</SidebarGroupContent>
|
|
||||||
</SidebarGroup>
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const database = pgTable("databases", {
|
|||||||
agentDatabaseId: uuid("agent_database_id").notNull().defaultRandom(),
|
agentDatabaseId: uuid("agent_database_id").notNull().defaultRandom(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
dbms: dbmsEnum("dbms").notNull(),
|
dbms: dbmsEnum("dbms").notNull(),
|
||||||
description: text("description").notNull(),
|
description: text("description"),
|
||||||
backupPolicy: text("backup_policy"),
|
backupPolicy: text("backup_policy"),
|
||||||
isWaitingForBackup: boolean("is_waiting_for_backup").default(false).notNull(),
|
isWaitingForBackup: boolean("is_waiting_for_backup").default(false).notNull(),
|
||||||
backupToRestore: text("backup_to_restore"),
|
backupToRestore: text("backup_to_restore"),
|
||||||
@@ -23,8 +23,7 @@ export const database = pgTable("databases", {
|
|||||||
lastContact: timestamp("last_contact"),
|
lastContact: timestamp("last_contact"),
|
||||||
|
|
||||||
projectId: uuid("project_id")
|
projectId: uuid("project_id")
|
||||||
.references(() => project.id)
|
.references(() => project.id),
|
||||||
.notNull(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const backup = pgTable(
|
export const backup = pgTable(
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
||||||
import { createSelectSchema } from "drizzle-zod";
|
import { createSelectSchema } from "drizzle-zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import {database} from "@/db/schema/06_database";
|
||||||
|
import {relations} from "drizzle-orm";
|
||||||
|
|
||||||
export const agent = pgTable("agents", {
|
export const agent = pgTable("agents", {
|
||||||
id: uuid("id").primaryKey().defaultRandom(),
|
id: uuid("id").primaryKey().defaultRandom(),
|
||||||
@@ -14,3 +16,8 @@ export const agent = pgTable("agents", {
|
|||||||
|
|
||||||
export const agentSchema = createSelectSchema(agent);
|
export const agentSchema = createSelectSchema(agent);
|
||||||
export type Agent = z.infer<typeof agentSchema>;
|
export type Agent = z.infer<typeof agentSchema>;
|
||||||
|
|
||||||
|
|
||||||
|
export const agentRelations = relations(agent, ({ many }) => ({
|
||||||
|
databases: many(database),
|
||||||
|
}));
|
||||||
@@ -97,7 +97,7 @@ export const auth = betterAuth({
|
|||||||
await db.insert(drizzleDb.schemas.member).values({
|
await db.insert(drizzleDb.schemas.member).values({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
organizationId: defaultOrg.id,
|
organizationId: defaultOrg.id,
|
||||||
role: "orgOwner",
|
role: "owner",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.warn("Default organization not found. Cannot assign member.");
|
console.warn("Default organization not found. Cannot assign member.");
|
||||||
|
|||||||
Reference in New Issue
Block a user