mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Working on the organization system.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import {PageParams} from "@/types/next";
|
||||
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {notFound} from "next/navigation";
|
||||
import {RestoreForm} from "@/components/wrappers/dashboard/database/RestoreForm";
|
||||
import {currentUser} from "@/lib/auth/current-user";
|
||||
|
||||
import {db} from "@/db";
|
||||
import {eq} from "drizzle-orm";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
|
||||
export default async function RoutePage(
|
||||
props: PageParams<{
|
||||
databaseId: string;
|
||||
}>
|
||||
) {
|
||||
const {databaseId} = await props.params;
|
||||
|
||||
const user = await currentUser();
|
||||
if (!user) notFound();
|
||||
|
||||
const [dbToRestore] = await db.select().from(drizzleDb.schemas.database).where(eq(drizzleDb.schemas.database.id, databaseId));
|
||||
|
||||
if (!dbToRestore) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const dbsOfSameType = await db.select().from(drizzleDb.schemas.database).where(eq(drizzleDb.schemas.database.dbms!, dbToRestore.dbms!));
|
||||
const successfulBackups = await db.select().from(drizzleDb.schemas.backup).where(eq(drizzleDb.schemas.backup.status, "success"));
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<PageHeader>
|
||||
<PageTitle>Restore {dbToRestore.name}</PageTitle>
|
||||
</PageHeader>
|
||||
<PageContent>
|
||||
<RestoreForm databaseToRestore={dbToRestore} databases={dbsOfSameType} backups={successfulBackups}/>
|
||||
</PageContent>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
+3
-2
@@ -4,14 +4,15 @@ import { notFound } from "next/navigation";
|
||||
import { DatabaseForm } from "@/components/wrappers/dashboard/database/DatabaseForm/DatabaseForm";
|
||||
|
||||
import { db } from "@/db";
|
||||
import { database } from "@/db/schema";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{ databaseId: string }>) {
|
||||
const { databaseId } = await props.params;
|
||||
|
||||
const dbItem = await db.query.database.findFirst({
|
||||
where: eq(database.id, databaseId),
|
||||
where: eq(drizzleDb.schemas.database.id, databaseId),
|
||||
});
|
||||
|
||||
if (!dbItem) {
|
||||
+10
-10
@@ -9,13 +9,13 @@ import { CronButton } from "@/components/wrappers/dashboard/database/CronButton/
|
||||
|
||||
import { db } from "@/db";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { backup as drizzleBackup, database as drizzleDatabase, restoration as drizzleRestoration } from "@/db/schema";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{ databaseId: string }>) {
|
||||
const { databaseId } = await props.params;
|
||||
|
||||
const dbItem = await db.query.database.findFirst({
|
||||
where: eq(drizzleDatabase.id, databaseId),
|
||||
where: eq(drizzleDb.schemas.database.id, databaseId),
|
||||
});
|
||||
|
||||
if (!dbItem) {
|
||||
@@ -23,7 +23,7 @@ export default async function RoutePage(props: PageParams<{ databaseId: string }
|
||||
}
|
||||
|
||||
const backups = await db.query.backup.findMany({
|
||||
where: eq(drizzleBackup.databaseId, dbItem.id),
|
||||
where: eq(drizzleDb.schemas.backup.databaseId, dbItem.id),
|
||||
with: {
|
||||
restorations: true,
|
||||
},
|
||||
@@ -31,7 +31,7 @@ export default async function RoutePage(props: PageParams<{ databaseId: string }
|
||||
});
|
||||
|
||||
const restorations = await db.query.restoration.findMany({
|
||||
where: eq(drizzleRestoration.databaseId, dbItem.id),
|
||||
where: eq(drizzleDb.schemas.restoration.databaseId, dbItem.id),
|
||||
orderBy: (r, { desc }) => [desc(r.createdAt)],
|
||||
});
|
||||
|
||||
@@ -40,14 +40,14 @@ export default async function RoutePage(props: PageParams<{ databaseId: string }
|
||||
|
||||
const [totalBackups, successfulBackups] = await Promise.all([
|
||||
db
|
||||
.select({ count: drizzleBackup.id })
|
||||
.from(drizzleBackup)
|
||||
.where(eq(drizzleBackup.databaseId, dbItem.id))
|
||||
.select({ count: drizzleDb.schemas.backup.id })
|
||||
.from(drizzleDb.schemas.backup)
|
||||
.where(eq(drizzleDb.schemas.backup.databaseId, dbItem.id))
|
||||
.then((rows) => rows.length),
|
||||
db
|
||||
.select({ count: drizzleBackup.id })
|
||||
.from(drizzleBackup)
|
||||
.where(and(eq(drizzleBackup.databaseId, dbItem.id), eq(drizzleBackup.status, "success")))
|
||||
.select({ count: drizzleDb.schemas.backup.id })
|
||||
.from(drizzleDb.schemas.backup)
|
||||
.where(and(eq(drizzleDb.schemas.backup.databaseId, dbItem.id), eq(drizzleDb.schemas.backup.status, "success")))
|
||||
.then((rows) => rows.length),
|
||||
]);
|
||||
|
||||
+14
-13
@@ -1,17 +1,18 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { PageParams } from "@/types/next";
|
||||
import { Page, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
|
||||
import { ProjectForm } from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm";
|
||||
import {notFound} from "next/navigation";
|
||||
import {PageParams} from "@/types/next";
|
||||
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {ProjectForm} from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
import { db } from "@/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { project as drizzleProject, organization as drizzleOrganization, DatabaseWith } from "@/db/schema";
|
||||
import {db} from "@/db";
|
||||
import {eq} from "drizzle-orm";
|
||||
import {DatabaseWith} from "@/db/schema/06_database";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{ projectId: string }>) {
|
||||
const { projectId } = await props.params;
|
||||
const {projectId} = await props.params;
|
||||
|
||||
const proj = await db.query.project.findFirst({
|
||||
where: eq(drizzleProject.id, projectId),
|
||||
where: eq(drizzleDb.schemas.project.id, projectId),
|
||||
with: {
|
||||
databases: true,
|
||||
},
|
||||
@@ -23,7 +24,7 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
|
||||
|
||||
//
|
||||
const org = await db.query.organization.findFirst({
|
||||
where: eq(drizzleOrganization.slug, "default"),
|
||||
where: eq(drizzleDb.schemas.organization.slug, "default"),
|
||||
});
|
||||
|
||||
if (!org) {
|
||||
@@ -32,14 +33,14 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
|
||||
|
||||
const availableDatabases = (
|
||||
await db.query.database.findMany({
|
||||
where: (db, { or, eq, isNull }) => or(isNull(db.projectId), eq(db.projectId, proj.id)),
|
||||
where: (db, {or, eq, isNull}) => or(isNull(db.projectId), eq(db.projectId, proj.id)),
|
||||
with: {
|
||||
agent: true,
|
||||
project: true,
|
||||
backups: true,
|
||||
restorations: true,
|
||||
},
|
||||
orderBy: (db, { desc }) => [desc(db.createdAt)],
|
||||
orderBy: (db, {desc}) => [desc(db.createdAt)],
|
||||
})
|
||||
).filter((db): db is DatabaseWith => db.project !== null);
|
||||
|
||||
@@ -52,7 +53,7 @@ export default async function RoutePage(props: PageParams<{ projectId: string }>
|
||||
<ProjectForm
|
||||
organization={org}
|
||||
databases={availableDatabases}
|
||||
defaultValues={{ name: proj.name, slug: proj.slug, databases: proj.databases.map((db) => db.id) }}
|
||||
defaultValues={{name: proj.name, slug: proj.slug, databases: proj.databases.map((db) => db.id)}}
|
||||
projectId={proj.id}
|
||||
/>
|
||||
</PageContent>
|
||||
+12
-7
@@ -10,19 +10,24 @@ import { notFound } from "next/navigation";
|
||||
|
||||
import { db } from "@/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { organization as drizzleOrganization } from "@/db/schema";
|
||||
import {getOrganization} from "@/lib/auth/auth";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{ slug: string; projectId: string }>) {
|
||||
const { slug: organizationSlug, projectId } = await props.params;
|
||||
export default async function RoutePage(props: PageParams<{
|
||||
// slug: string;
|
||||
projectId: string
|
||||
}>) {
|
||||
const {
|
||||
// slug: organizationSlug,
|
||||
projectId } = await props.params;
|
||||
|
||||
const organization = await getOrganization({organizationSlug});
|
||||
const organization = await getOrganization({});
|
||||
|
||||
if (!organization || organization?.slug !== organizationSlug) {
|
||||
if (!organization) {
|
||||
notFound();
|
||||
}
|
||||
const org = await db.query.organization.findFirst({
|
||||
where: eq(drizzleOrganization.slug, organization.slug),
|
||||
where: eq(drizzleDb.schemas.organization.slug, organization.slug),
|
||||
});
|
||||
|
||||
if (!org) notFound();
|
||||
@@ -56,7 +61,7 @@ export default async function RoutePage(props: PageParams<{ slug: string; projec
|
||||
{proj.databases.length > 0 ? (
|
||||
<CardsWithPagination
|
||||
data={proj.databases}
|
||||
organizationSlug={organizationSlug}
|
||||
organizationSlug={organization.slug}
|
||||
cardItem={ProjectDatabaseCard}
|
||||
cardsPerPage={4}
|
||||
numberOfColumns={1}
|
||||
+6
-6
@@ -3,16 +3,16 @@ import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {ProjectForm} from "@/components/wrappers/dashboard/projects/ProjectsForm/ProjectForm";
|
||||
import {notFound} from "next/navigation";
|
||||
import {db} from "@/db";
|
||||
import {DatabaseWith, organization as drizzleOrganization} from "@/db/schema";
|
||||
import {eq} from "drizzle-orm";
|
||||
import {getOrganization} from "@/lib/auth/auth";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {DatabaseWith} from "@/db/schema/06_database";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
const {slug: organizationSlug} = await props.params;
|
||||
export default async function RoutePage(props: PageParams<{ }>) {
|
||||
|
||||
const organization = await getOrganization({organizationSlug});
|
||||
const organization = await getOrganization({});
|
||||
|
||||
if (!organization || organization?.slug !== organizationSlug) {
|
||||
if (!organization ) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
).filter((db) => db.project !== null) as DatabaseWith[];
|
||||
|
||||
const org = await db.query.organization.findFirst({
|
||||
where: eq(drizzleOrganization.slug, organization.slug),
|
||||
where: eq(drizzleDb.schemas.organization.slug, organization.slug),
|
||||
});
|
||||
|
||||
if (!org) notFound();
|
||||
+6
-7
@@ -9,12 +9,11 @@ import {db} from "@/db";
|
||||
import {notFound} from "next/navigation";
|
||||
import {getOrganization} from "@/lib/auth/auth";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
const {slug: organizationSlug} = await props.params;
|
||||
export default async function RoutePage(props: PageParams<{ }>) {
|
||||
|
||||
const organization = await getOrganization({organizationSlug});
|
||||
const organization = await getOrganization({});
|
||||
|
||||
if (!organization || organization?.slug !== organizationSlug) {
|
||||
if (!organization) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
@@ -35,7 +34,7 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
<PageTitle>Projects</PageTitle>
|
||||
{projects.length > 0 && (
|
||||
<PageActions>
|
||||
<Link href={`/dashboard/${organizationSlug}/projects/new`}>
|
||||
<Link href={`/dashboard/projects/new`}>
|
||||
<Button>+ Create Project</Button>
|
||||
</Link>
|
||||
</PageActions>
|
||||
@@ -44,11 +43,11 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
|
||||
<PageContent className="mt-10">
|
||||
{projects.length > 0 ? (
|
||||
<CardsWithPagination organizationSlug={organizationSlug} data={projects} cardItem={ProjectCard}
|
||||
<CardsWithPagination organizationSlug={organization.slug} data={projects} cardItem={ProjectCard}
|
||||
cardsPerPage={4} numberOfColumns={1}/>
|
||||
) : (
|
||||
<Link
|
||||
href={`/dashboard/${organizationSlug}/projects/new`}
|
||||
href={`/dashboard/projects/new`}
|
||||
className=" flex item-center justify-center border-2 border-dashed transition-colors border-primary p-8 lg:p-12 w-full rounded-md"
|
||||
>
|
||||
Create new Project
|
||||
+10
-10
@@ -7,7 +7,7 @@ import { getCurrentOrganizationSlug } from "@/features/dashboard/organization-co
|
||||
import { notFound } from "next/navigation";
|
||||
import { db } from "@/db";
|
||||
import { asc, count, eq, inArray } from "drizzle-orm";
|
||||
import { organization as drizzleOrganization, project as drizzleProject, backup as drizzleBackup } from "@/db/schema";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
const { slug: organizationSlug } = await props.params;
|
||||
@@ -18,13 +18,13 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
}
|
||||
|
||||
const org = await db.query.organization.findFirst({
|
||||
where: eq(drizzleOrganization.slug, currentOrganizationSlug),
|
||||
where: eq(drizzleDb.schemas.organization.slug, currentOrganizationSlug),
|
||||
});
|
||||
|
||||
if (!org) notFound();
|
||||
|
||||
const projects = await db.query.project.findMany({
|
||||
where: eq(drizzleProject.organizationId, org.id),
|
||||
where: eq(drizzleDb.schemas.project.organizationId, org.id),
|
||||
});
|
||||
|
||||
const projectsCount = projects.length;
|
||||
@@ -34,19 +34,19 @@ export default async function RoutePage(props: PageParams<{ slug: string }>) {
|
||||
id: true,
|
||||
createdAt: true,
|
||||
},
|
||||
orderBy: [asc(drizzleBackup.id)],
|
||||
orderBy: [asc(drizzleDb.schemas.backup.id)],
|
||||
});
|
||||
|
||||
const backupsRate = await db
|
||||
.select({
|
||||
createdAt: drizzleBackup.createdAt,
|
||||
status: drizzleBackup.status,
|
||||
createdAt: drizzleDb.schemas.backup.createdAt,
|
||||
status: drizzleDb.schemas.backup.status,
|
||||
_count: count(),
|
||||
})
|
||||
.from(drizzleBackup)
|
||||
.where(inArray(drizzleBackup.status, ["success", "failed"]))
|
||||
.groupBy(drizzleBackup.createdAt, drizzleBackup.status)
|
||||
.orderBy(drizzleBackup.createdAt);
|
||||
.from(drizzleDb.schemas.backup)
|
||||
.where(inArray(drizzleDb.schemas.backup.status, ["success", "failed"]))
|
||||
.groupBy(drizzleDb.schemas.backup.createdAt, drizzleDb.schemas.backup.status)
|
||||
.orderBy(drizzleDb.schemas.backup.createdAt);
|
||||
|
||||
return (
|
||||
<Page>
|
||||
@@ -1,41 +0,0 @@
|
||||
import { PageParams } from "@/types/next";
|
||||
import { Page, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
|
||||
import { notFound } from "next/navigation";
|
||||
import { RestoreForm } from "@/components/wrappers/dashboard/database/RestoreForm";
|
||||
import { currentUser } from "@/lib/auth/current-user";
|
||||
|
||||
import { db } from "@/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { database, backup } from "@/db/schema";
|
||||
|
||||
export default async function RoutePage(
|
||||
props: PageParams<{
|
||||
databaseId: string;
|
||||
}>
|
||||
) {
|
||||
const { databaseId } = await props.params;
|
||||
|
||||
const user = await currentUser();
|
||||
if (!user) notFound();
|
||||
|
||||
const [dbToRestore] = await db.select().from(database).where(eq(database.id, databaseId));
|
||||
|
||||
if (!dbToRestore) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const dbsOfSameType = await db.select().from(database).where(eq(database.dbms!, dbToRestore.dbms!));
|
||||
|
||||
const successfulBackups = await db.select().from(backup).where(eq(backup.status, "success"));
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<PageHeader>
|
||||
<PageTitle>Restore {dbToRestore.name}</PageTitle>
|
||||
</PageHeader>
|
||||
<PageContent>
|
||||
<RestoreForm databaseToRestore={dbToRestore} databases={dbsOfSameType} backups={successfulBackups} />
|
||||
</PageContent>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +1,22 @@
|
||||
import React from "react";
|
||||
import { redirect } from "next/navigation";
|
||||
import {redirect} from "next/navigation";
|
||||
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { AppSidebar } from "@/components/wrappers/dashboard/sideBar/app-sidebar";
|
||||
import { Header } from "@/features/layout/Header";
|
||||
import { currentUser } from "@/lib/auth/current-user";
|
||||
import {SidebarInset, SidebarProvider} from "@/components/ui/sidebar";
|
||||
import {AppSidebar} from "@/components/wrappers/dashboard/sideBar/app-sidebar";
|
||||
import {Header} from "@/features/layout/Header";
|
||||
import {currentUser} from "@/lib/auth/current-user";
|
||||
|
||||
export default async function Layout({ children }: { children: React.ReactNode }) {
|
||||
export default async function Layout({children}: { children: React.ReactNode }) {
|
||||
const user = await currentUser();
|
||||
|
||||
if (!user) redirect("/login");
|
||||
|
||||
return (
|
||||
<>
|
||||
<SidebarProvider>
|
||||
<div className="flex flex-col lg:flex-row w-full">
|
||||
<AppSidebar />
|
||||
<AppSidebar/>
|
||||
<SidebarInset>
|
||||
<Header />
|
||||
<Header/>
|
||||
<main className="h-full">{children}</main>
|
||||
</SidebarInset>
|
||||
</div>
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import { PageParams } from "@/types/next";
|
||||
import { Page, PageActions, PageContent, PageHeader, PageTitle } from "@/features/layout/page";
|
||||
import { notFound } from "next/navigation";
|
||||
import { UserForm } from "@/components/wrappers/dashboard/profile/UserForm/UserForm";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ButtonDeleteAccount } from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/ButtonDeleteAccount";
|
||||
import { AvatarWithUpload } from "@/components/wrappers/dashboard/profile/Avatar/AvatarWithUpload";
|
||||
import { currentUser } from "@/lib/auth/current-user";
|
||||
import {PageParams} from "@/types/next";
|
||||
import {Page, PageActions, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {notFound} from "next/navigation";
|
||||
import {UserForm} from "@/components/wrappers/dashboard/profile/UserForm/UserForm";
|
||||
import {Badge} from "@/components/ui/badge";
|
||||
import {ButtonDeleteAccount} from "@/components/wrappers/dashboard/profile/ButtonDeleteAccount/ButtonDeleteAccount";
|
||||
import {AvatarWithUpload} from "@/components/wrappers/dashboard/profile/Avatar/AvatarWithUpload";
|
||||
import {currentUser} from "@/lib/auth/current-user";
|
||||
import {getAccounts, getSessions} from "@/lib/auth/auth";
|
||||
//import { getAccounts, getSessions } from "@/lib/auth/auth";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{}>) {
|
||||
const user = await currentUser();
|
||||
|
||||
console.log("my user",user);
|
||||
if (!user) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
|
||||
if (user.role !== "user" && user.role !== "admin" && user.role !== "superadmin") {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
// const sessions = await getSessions();
|
||||
// const accounts = await getAccounts();
|
||||
// const sessions = await getSessions();
|
||||
// const accounts = await getAccounts();
|
||||
|
||||
return (
|
||||
<Page>
|
||||
@@ -41,7 +43,7 @@ export default async function RoutePage(props: PageParams<{}>) {
|
||||
<Badge className="ml-3 hidden lg:block">{user.role}</Badge>
|
||||
</PageTitle>
|
||||
<PageActions className="mt-2 hidden sm:block">
|
||||
<ButtonDeleteAccount text="Delete my account" />
|
||||
<ButtonDeleteAccount text="Delete my account"/>
|
||||
</PageActions>
|
||||
</div>
|
||||
<PageContent>
|
||||
@@ -54,7 +56,7 @@ export default async function RoutePage(props: PageParams<{}>) {
|
||||
}}
|
||||
/>
|
||||
<div className="mt-4 sm:hidden">
|
||||
<ButtonDeleteAccount text="Delete my account" />
|
||||
<ButtonDeleteAccount text="Delete my account"/>
|
||||
</div>
|
||||
</PageContent>
|
||||
</Page>
|
||||
|
||||
Reference in New Issue
Block a user