Restructured applications

This commit is contained in:
2026-01-02 12:37:46 +01:00
parent dd8662cb90
commit 767afd9fef
6 changed files with 106 additions and 177 deletions
+32 -89
View File
@@ -4,20 +4,20 @@ import { DashboardLayout } from "@/components/dashboard/DashboardLayout";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Play, Square, MoreVertical, Plus, Rocket } from "lucide-react";
import { Progress } from "@/components/ui/progress";
import { MoreVertical, Plus, Rocket } from "lucide-react";
import InstallApplicationDialog from "@/components/dialogs/InstallApplication";
import { useEffect, useState } from "react";
import { ImageApp } from "@/lib/types";
import { getApplications, removeApp } from "@/core/application";
import RemoveDialog from "@/components/dialogs/Remove";
import { Application } from "@/lib/types";
export default function ApplicationsPage() {
const [applications, setApplications] = useState<ImageApp[]>([]);
const [applications, setApplications] = useState<Application[]>([]);
useEffect(() => {
const fetch = async () => {
setApplications(await getApplications());
const apps = await getApplications();
setApplications(apps);
};
fetch();
@@ -40,110 +40,53 @@ export default function ApplicationsPage() {
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between mb-6">
<div className="flex flex-wrap items-center gap-2">
<Badge>{applications.length} apps</Badge>
<Badge>
{applications.filter((a) => a.status === "running").length} running
</Badge>
</div>
<InstallApplicationDialog>
<Button size="sm" className="gap-2 w-full sm:w-auto">
<Plus className="w-4 h-4" />
Install Application
<Plus className="w-4 h-4" /> Install Application
</Button>
</InstallApplicationDialog>
</div>
<div className="space-y-3">
{applications.map((app, i) => (
<Card key={i}>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{applications.map((app) => (
<Card key={app.id}>
<CardContent className="p-4">
<div className="grid grid-cols-1 md:grid-cols-12 gap-4 md:items-center">
<div className="flex flex-col gap-4">
{/* Status & Name */}
<div className="flex items-center gap-3 md:col-span-3">
{/* {app.status} */}
<div className="flex items-center gap-3 min-w-0">
<div className="min-w-0">
<div className="font-mono text-sm font-medium">
{app.app?.name || app.name}
<div className="font-mono text-sm font-medium truncate">
{app.name}
</div>
<div className="text-xs text-muted-foreground font-mono truncate">
{app.image}
{app.repo}
</div>
</div>
</div>
{/* Containers */}
<div className="flex justify-between md:block md:col-span-1">
<span className="text-xs text-muted-foreground md:hidden">
Containers
{/* Deployments */}
<div className="flex justify-between items-center">
<span className="text-xs text-muted-foreground">
Deployments
</span>
<div className="font-mono text-sm">{app.replicas}</div>
</div>
{/* CPU */}
<div className="md:col-span-2">
<div className="text-xs text-muted-foreground mb-1">CPU</div>
<div className="flex items-center gap-2">
<Progress value={app.cpu} className="w-full" />
<span className="text-xs font-mono w-8">
{app.cpu.toFixed(1)}%
</span>
</div>
</div>
{/* Memory */}
<div className="md:col-span-2">
<div className="text-xs text-muted-foreground mb-1">
Memory
</div>
<div className="flex items-center gap-2">
<Progress value={app.memory} className="w-full" />
<span className="text-xs font-mono w-8">
{app.memory.toFixed(1)}%
</span>
</div>
</div>
{/* Network */}
<div className="flex justify-between md:block md:col-span-1">
<span className="text-xs text-muted-foreground md:hidden">
Network
<span className="font-mono text-sm">
{app.deployments?.length ?? 0}
</span>
<div className="font-mono text-xs">{app.network}</div>
</div>
{/* Ports */}
<div className="md:col-span-2">
<div className="text-xs text-muted-foreground mb-1">
Ports
</div>
<div className="flex gap-1 flex-wrap">
{app.ports?.length > 0 ? (
app.ports.map((port) => (
<Badge key={port} className="text-[10px]">
{port}
</Badge>
))
) : (
<span className="text-xs text-muted-foreground">—</span>
)}
</div>
</div>
{/* Actions */}
<div className="flex items-center justify-end gap-1 md:col-span-1">
{app.status === "running" ? (
<Button variant="ghost" size="icon-sm">
<Square className="w-3 h-3" />
</Button>
) : (
<Button variant="ghost" size="icon-sm">
<Rocket className="w-3 h-3" />
</Button>
)}
<RemoveDialog
remove={() => app.app?.id && remove(app.app?.id)}
/>
<Button variant="ghost" size="icon-sm">
<div className="flex items-center justify-end gap-1">
<Button variant="ghost" size="icon-sm" aria-label="Deploy">
<Rocket className="w-3 h-3" />
</Button>
{app.id && <RemoveDialog remove={() => remove(app.id)} />}
<Button
variant="ghost"
size="icon-sm"
aria-label="More options"
>
<MoreVertical className="w-3 h-3" />
</Button>
</div>