add: specs & database status

This commit is contained in:
2024-05-08 21:56:23 +02:00
parent 8f47633e86
commit 27e9e2d941
12 changed files with 472 additions and 80 deletions

View File

@@ -3,12 +3,12 @@
import { Database } from '@prisma/client';
import { ColumnDef } from '@tanstack/react-table';
import Image from 'next/image';
import { databaseProviders } from './database-new-form';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { Button } from '@/components/ui/button';
import { EllipsisVertical } from 'lucide-react';
import { databaseProviders } from '@/lib/deploy/database-config';
import { cn } from '@/lib/utils';
interface IDatabase extends Pick<Database, 'id' | 'name' | 'provider' | 'createdAt'> {}
interface IDatabase extends Pick<Database, 'id' | 'name' | 'provider' | 'createdAt'> {
status: any;
}
export const columns: ColumnDef<IDatabase>[] = [
{
@@ -16,8 +16,9 @@ export const columns: ColumnDef<IDatabase>[] = [
header: 'Provider',
cell(props) {
return (
<div className="flex items-center">
<div className="flex items-center relative">
<Image src={databaseProviders.filter((pro) => pro.id.toUpperCase() === props.getValue())[0]?.image?.src} alt={databaseProviders.filter((pro) => pro.id.toUpperCase() === props.getValue())[0]?.image?.alt} width={32} height={32} />
<span className={cn('absolute bottom-0 left-8 w-2 h-2 rounded-full', props.row.original.status.status.phase == 'Running' ? 'bg-emerald-400' : 'bg-red-400')}></span>
</div>
);
},

View File

@@ -1,5 +1,6 @@
'use client';
import { PostgresSpecsPage } from '@/components/deploy/database/provider/postgres';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
@@ -8,6 +9,7 @@ import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
import { useWorkspace } from '@/hooks/useWorkspace';
import { deployDatabase } from '@/lib/deploy/database';
import { databaseProviders, defaultDatabaseConfiguration, IDatabaseConfiguration } from '@/lib/deploy/database-config';
import { cn } from '@/lib/utils';
import { Plus } from 'lucide-react';
import Image from 'next/image';
@@ -18,25 +20,6 @@ interface DatabaseNewSteps {
display: string;
}
interface IDatabaseProvider {
id: string;
display: string;
image: {
alt: string;
src: string;
};
}
export interface IDatabaseConfig {
workspaceId: string;
name: string;
provider: IDatabaseProvider;
user: {
username: string;
password: string;
};
}
const steps: DatabaseNewSteps[] = [
{
display: 'Database Type',
@@ -52,55 +35,26 @@ const steps: DatabaseNewSteps[] = [
},
];
export const databaseProviders: IDatabaseProvider[] = [
{
id: 'vitess',
display: 'Vitess',
image: {
alt: 'Vitess',
src: '/vitess.png',
},
},
{
id: 'redis',
display: 'Redis',
image: {
alt: 'Redis',
src: '/redis.svg',
},
},
{
id: 'postgres',
display: 'Postgres',
image: {
alt: 'Postgres',
src: '/postgres.png',
},
},
];
export default function DatabaseNewForm() {
const [open, setOpen] = useState<boolean>(false);
const [currentSteps, setCurrentSteps] = useState<number>(1);
const router = useRouter();
// TODO: Generate all data randomly, but leave the user the choice to modify
const { id } = useWorkspace();
const defaultDatabaseConfig: IDatabaseConfig = {
workspaceId: id,
name: 'my-new-cool-db',
provider: databaseProviders[0],
user: {
username: 'my-new-super-user',
password: 'a-super-strong-generated-password',
},
};
const [databaseConfig, setDatabaseConfig] = useState<IDatabaseConfig>(defaultDatabaseConfig);
const [databaseConfig, setDatabaseConfig] = useState<IDatabaseConfiguration>(defaultDatabaseConfiguration(id));
return (
<Sheet open={open} onOpenChange={() => setOpen((open) => !open)}>
<Sheet
open={open}
onOpenChange={() => {
setOpen((open) => !open);
if (!open) {
setDatabaseConfig(defaultDatabaseConfiguration(id));
setCurrentSteps(1);
}
}}
>
<SheetTrigger asChild>
<Button className="flex gap-1 justify-center items-center bg-[#3A7BFE]">
<Plus />
@@ -152,8 +106,9 @@ export default function DatabaseNewForm() {
{currentSteps == 2 && (
<div>
<p>WIP for now 1CPU 2048Mb RAM</p>
<p>Storage 1 GB</p>
{databaseConfig.provider.id == 'vitess' && <div>Vitess</div>}
{databaseConfig.provider.id == 'redis' && <div>Redis</div>}
{databaseConfig.provider.id == 'postgres' && <PostgresSpecsPage config={databaseConfig} setConfig={setDatabaseConfig} />}
</div>
)}
@@ -197,11 +152,36 @@ export default function DatabaseNewForm() {
{currentSteps == 4 && (
<div>
<h2>Review your new database information :</h2>
<p>Type : {databaseConfig.provider.display}</p>
<p>Name : {databaseConfig.name}</p>
<p>Username : {databaseConfig.user.username}</p>
<p>Password : {databaseConfig.user.password}</p>
<div className="flex flex-col gap-2">
<div>
<p className="text-muted-foreground text-sm">Database Type</p>
<p>{databaseConfig.provider.display}</p>
</div>
<div>
<p className="text-muted-foreground text-sm">CPUs</p>
<p>{databaseConfig.specs.cpu}</p>
</div>
<div>
<p className="text-muted-foreground text-sm">RAM</p>
<p>{databaseConfig.specs.memory}</p>
</div>
<div>
<p className="text-muted-foreground text-sm">Storage</p>
<p>{databaseConfig.specs.storage}</p>
</div>
<div>
<p className="text-muted-foreground text-sm">Name</p>
<p>{databaseConfig.name}</p>
</div>
<div>
<p className="text-muted-foreground text-sm">Username</p>
<p>{databaseConfig.user.username}</p>
</div>
<div>
<p className="text-muted-foreground text-sm">Password</p>
<p>{databaseConfig.user.password}</p>
</div>
</div>
</div>
)}
@@ -224,7 +204,7 @@ export default function DatabaseNewForm() {
console.log(res);
setOpen(false);
setCurrentSteps(1);
setDatabaseConfig(defaultDatabaseConfig);
setDatabaseConfig(defaultDatabaseConfiguration(id));
router.refresh();
})
.catch((err) => {

View File

@@ -11,6 +11,7 @@ import { EllipsisVertical, X } from 'lucide-react';
import { Dialog, DialogClose, DialogContent, DialogTrigger } from '@/components/ui/dialog';
import { useState } from 'react';
import { Database } from '@prisma/client';
import { deleteDatabase } from '@/lib/deploy/database';
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
@@ -19,6 +20,7 @@ interface DataTableProps<TData, TValue> {
export function DatabaseTable<TData, TValue>({ columns, data }: DataTableProps<TData, TValue>) {
const [open, setOpen] = useState(false);
const [destroyOpen, setDestroyOpen] = useState(false);
const table = useReactTable({
data,
@@ -27,7 +29,7 @@ export function DatabaseTable<TData, TValue>({ columns, data }: DataTableProps<T
});
const router = useRouter();
const { slug } = useWorkspace();
const { slug, id } = useWorkspace();
return (
<div className="rounded-lg w-full overflow-hidden">
@@ -106,7 +108,51 @@ export function DatabaseTable<TData, TValue>({ columns, data }: DataTableProps<T
</div>
</DialogContent>
</Dialog>
<DropdownMenuItem className="text-red-400">Destroy</DropdownMenuItem>
<Dialog open={destroyOpen} onOpenChange={setDestroyOpen}>
<DialogTrigger asChild>
<DropdownMenuItem
onClick={(e) => {
e.preventDefault();
setDestroyOpen(true);
}}
className="text-red-400"
>
Destroy
</DropdownMenuItem>
</DialogTrigger>
<DialogContent>
<div className="flex flex-col">
<div className="flex flex-row justify-between mb-0">
<h1 className="text-3xl font-semibold">Are you sure?</h1>
<DialogClose asChild>
<Button variant="ghost">
<X size={17} />
</Button>
</DialogClose>
</div>
<p className="text-gray-700">Deleting a database if irreversible. This action cannot be undone.</p>
</div>
<div>
<Button
variant={'destructive'}
onClick={(e) => {
e.preventDefault();
deleteDatabase({ id: data[index].id, workspaceId: id })
.then(() => {
setDestroyOpen(false);
router.refresh();
})
.catch((err) => {
console.error(err);
});
}}
>
Delete
</Button>
</div>
</DialogContent>
</Dialog>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>

View File

@@ -3,6 +3,7 @@ import DatabaseNewForm from './database-new-form';
import prisma from '@/lib/prisma';
import { DatabaseTable } from './database-table';
import { columns } from './database-column';
import { getDatabase } from '@/lib/deploy/database';
export default async function Databases({ params }: { params: { workspace: string } }) {
const workspaceSlug = params.workspace;
@@ -15,6 +16,16 @@ export default async function Databases({ params }: { params: { workspace: strin
},
});
const status = await Promise.all(
workspace.Database.map(async (database) => {
const res = await getDatabase({
id: database.id,
workspaceId: workspace.id,
}).catch(() => ({ status: { phase: 'unknown' } }));
return { ...res, id: database.id };
})
);
if (workspace?.Database.length == 0) {
return (
<div className="mt-12">
@@ -47,7 +58,7 @@ export default async function Databases({ params }: { params: { workspace: strin
</div>
</div>
))} */}
<DatabaseTable columns={columns} data={workspace.Database} />
<DatabaseTable columns={columns} data={workspace.Database.map((db) => ({ ...db, status: status.find((st) => st.id == db.id) }))} />
</div>
</div>
);