Shortened applictions for apps in code
This commit is contained in:
@@ -13,13 +13,13 @@ export async function GET(req: NextRequest): Promise<NextResponse> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const apps = await getApplications();
|
// const apps = await getApps();
|
||||||
|
|
||||||
const applications = await getDeployments([]);
|
const apps = await getDeployments([]);
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
message: "ok",
|
message: "ok",
|
||||||
applications,
|
apps,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,32 +13,29 @@ import { Badge } from "@/components/ui/badge";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { MoreVertical, Plus, Rocket } from "lucide-react";
|
import { MoreVertical, Plus, Rocket } from "lucide-react";
|
||||||
import InstallApplicationDialog from "@/components/dialogs/InstallApplication";
|
import InstallApplicationDialog from "@/components/dialogs/InstallApplication";
|
||||||
import { getApplications, removeApp } from "@/lib/dockship/application";
|
import { getApps, removeApp } from "@/lib/dockship/application";
|
||||||
import RemoveDialog from "@/components/dialogs/Remove";
|
import RemoveDialog from "@/components/dialogs/Remove";
|
||||||
import DeployAppDialog from "@/components/dialogs/DeployApp";
|
import DeployAppDialog from "@/components/dialogs/DeployApp";
|
||||||
import { useAsyncInterval } from "@/hooks/use-async";
|
import { useAsyncInterval } from "@/hooks/use-async";
|
||||||
|
|
||||||
export default function ApplicationsPage() {
|
export default function ApplicationsPage() {
|
||||||
const { value: applications, setValue: setApplications } = useAsyncInterval(
|
const { value: apps, setValue: setApps } = useAsyncInterval(
|
||||||
[],
|
[],
|
||||||
getApplications,
|
getApps,
|
||||||
3000
|
3000
|
||||||
);
|
);
|
||||||
|
|
||||||
const remove = async (appId: string) => {
|
const remove = async (appId: string) => {
|
||||||
await removeApp(appId);
|
await removeApp(appId);
|
||||||
setApplications((prev) => prev.filter((app) => app.id !== appId));
|
setApps((prev) => prev.filter((app) => app.id !== appId));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardLayout
|
<DashboardLayout title="Applications" subtitle="Manage dockship applications">
|
||||||
title="Applications"
|
|
||||||
subtitle="Manage installed applications"
|
|
||||||
>
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between mb-6">
|
<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">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<Badge>{applications.length} apps</Badge>
|
<Badge>{apps.length} apps</Badge>
|
||||||
</div>
|
</div>
|
||||||
<InstallApplicationDialog>
|
<InstallApplicationDialog>
|
||||||
<Button size="sm" className="gap-2 w-full sm:w-auto">
|
<Button size="sm" className="gap-2 w-full sm:w-auto">
|
||||||
@@ -47,7 +44,7 @@ export default function ApplicationsPage() {
|
|||||||
</InstallApplicationDialog>
|
</InstallApplicationDialog>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{applications.map((app) => (
|
{apps.map((app) => (
|
||||||
<Card key={app.id}>
|
<Card key={app.id}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>{app.name}</CardTitle>
|
<CardTitle>{app.name}</CardTitle>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Rocket, RotateCcw, Eye, MoreVertical, Plus } from "lucide-react";
|
import { Rocket, RotateCcw, Eye, MoreVertical, Plus } from "lucide-react";
|
||||||
import { Application, Deployment } from "@/lib/types";
|
import { Application, Deployment } from "@/lib/types";
|
||||||
import { getDeployments } from "@/lib/dockship/deploy";
|
import { getDeployments } from "@/lib/dockship/deploy";
|
||||||
import { getApplications } from "@/lib/dockship/application";
|
import { getApps } from "@/lib/dockship/application";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import DeployAppDialog from "@/components/dialogs/DeployApp";
|
import DeployAppDialog from "@/components/dialogs/DeployApp";
|
||||||
import { useAsync } from "@/hooks/use-async";
|
import { useAsync } from "@/hooks/use-async";
|
||||||
@@ -20,23 +20,23 @@ const statusDot = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default function DeploymentsPage() {
|
export default function DeploymentsPage() {
|
||||||
const { value: applications } = useAsync([], getApplications);
|
const { value: apps } = useAsync([], getApps);
|
||||||
|
|
||||||
const { value: deployments, loading } = useAsync(
|
const { value: deployments, loading } = useAsync(
|
||||||
[],
|
[],
|
||||||
async () => (await getDeployments()).filter((d) => d !== null),
|
async () => (await getDeployments()).filter((d) => d !== null),
|
||||||
[applications]
|
[apps]
|
||||||
);
|
);
|
||||||
|
|
||||||
const appNameByContainer = useMemo(() => {
|
const appNameByContainer = useMemo(() => {
|
||||||
const map = new Map<string, string>();
|
const map = new Map<string, string>();
|
||||||
for (const app of applications) {
|
for (const app of apps) {
|
||||||
for (const container of app.deployments) {
|
for (const container of app.deployments) {
|
||||||
map.set(container, app.name);
|
map.set(container, app.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}, [applications]);
|
}, [apps]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardLayout
|
<DashboardLayout
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
NodeLiveData,
|
NodeLiveData,
|
||||||
} from "@/lib/types";
|
} from "@/lib/types";
|
||||||
import { getDocker } from "@/lib/dockship/docker";
|
import { getDocker } from "@/lib/dockship/docker";
|
||||||
import { getApplications } from "@/lib/dockship/application";
|
import { getApps } from "@/lib/dockship/application";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { getDeployments } from "@/lib/dockship/deploy";
|
import { getDeployments } from "@/lib/dockship/deploy";
|
||||||
import { useAsync, useAsyncInterval } from "@/hooks/use-async";
|
import { useAsync, useAsyncInterval } from "@/hooks/use-async";
|
||||||
@@ -36,7 +36,7 @@ export default function OverviewPage() {
|
|||||||
const { value: dockerNodes } = useAsync([], async () => getDocker(nodes), [
|
const { value: dockerNodes } = useAsync([], async () => getDocker(nodes), [
|
||||||
nodes,
|
nodes,
|
||||||
]);
|
]);
|
||||||
const { value: applications } = useAsyncInterval([], getApplications, 3000);
|
const { value: apps } = useAsyncInterval([], getApps, 3000);
|
||||||
const { value: deployments } = useAsyncInterval(
|
const { value: deployments } = useAsyncInterval(
|
||||||
[],
|
[],
|
||||||
async () => (await getDeployments()).filter((d) => d !== null),
|
async () => (await getDeployments()).filter((d) => d !== null),
|
||||||
@@ -45,13 +45,13 @@ export default function OverviewPage() {
|
|||||||
|
|
||||||
const appNameByContainer = useMemo(() => {
|
const appNameByContainer = useMemo(() => {
|
||||||
const map = new Map<string, string>();
|
const map = new Map<string, string>();
|
||||||
for (const app of applications) {
|
for (const app of apps) {
|
||||||
for (const container of app.deployments) {
|
for (const container of app.deployments) {
|
||||||
map.set(container, app.name);
|
map.set(container, app.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}, [applications]);
|
}, [apps]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardLayout title="Overview" subtitle="System status and metrics">
|
<DashboardLayout title="Overview" subtitle="System status and metrics">
|
||||||
@@ -59,9 +59,9 @@ export default function OverviewPage() {
|
|||||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
||||||
<StatCard
|
<StatCard
|
||||||
title="Applications"
|
title="Applications"
|
||||||
value={applications.length}
|
value={apps.length}
|
||||||
subtitle={`${
|
subtitle={`${
|
||||||
applications.filter((app) => app.deployments.length > 0).length
|
apps.filter((app) => app.deployments.length > 0).length
|
||||||
} Deployed`}
|
} Deployed`}
|
||||||
icon={<Box className="w-4 h-4" />}
|
icon={<Box className="w-4 h-4" />}
|
||||||
/>
|
/>
|
||||||
@@ -111,12 +111,12 @@ export default function OverviewPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Rows */}
|
{/* Rows */}
|
||||||
{applications.slice(-5).length === 0 ? (
|
{apps.slice(-5).length === 0 ? (
|
||||||
<div className="py-6 text-sm text-muted-foreground text-center">
|
<div className="py-6 text-sm text-muted-foreground text-center">
|
||||||
No applications yet
|
No applications yet
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
applications.slice(-5).map((app) => (
|
apps.slice(-5).map((app) => (
|
||||||
<div
|
<div
|
||||||
key={app.id}
|
key={app.id}
|
||||||
className="
|
className="
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function DeployAppDialog({
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { value: nodes } = useAsync([], getLiveNodes);
|
const { value: nodes } = useAsync([], getLiveNodes);
|
||||||
const { value: applications } = useAsync<Application[]>([], async () => []);
|
const { value: apps } = useAsync<Application[]>([], async () => []);
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [app, setApp] = useState(defaultApp || "");
|
const [app, setApp] = useState(defaultApp || "");
|
||||||
const [node, setNode] = useState("");
|
const [node, setNode] = useState("");
|
||||||
@@ -66,7 +66,7 @@ export default function DeployAppDialog({
|
|||||||
<Combobox
|
<Combobox
|
||||||
value={app}
|
value={app}
|
||||||
setValue={setApp}
|
setValue={setApp}
|
||||||
data={applications.map((app) => ({
|
data={apps.map((app) => ({
|
||||||
label: app.name,
|
label: app.name,
|
||||||
value: app.id,
|
value: app.id,
|
||||||
}))}
|
}))}
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ export async function installApp(name: string, repo: string, nodeId: string) {
|
|||||||
headers: { Authorization: `ApiKey ${targetNode?.key}` },
|
headers: { Authorization: `ApiKey ${targetNode?.key}` },
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
).data.applications;
|
).data.apps;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getApplications(): Promise<Application[]> {
|
export async function getApps(): Promise<Application[]> {
|
||||||
if (await verifySession()) {
|
if (await verifySession()) {
|
||||||
throw new Error("Unauthorized");
|
throw new Error("Unauthorized");
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ export async function getApplications(): Promise<Application[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getEnv(): Promise<Record<string, Env>> {
|
export async function getEnv(): Promise<Record<string, Env>> {
|
||||||
const apps = await getApplications();
|
const apps = await getApps();
|
||||||
|
|
||||||
return apps.reduce<Record<string, Env>>((acc, app) => {
|
return apps.reduce<Record<string, Env>>((acc, app) => {
|
||||||
acc[app.id] = {
|
acc[app.id] = {
|
||||||
@@ -56,14 +56,14 @@ export async function setEnv(
|
|||||||
throw new Error("Unauthorized");
|
throw new Error("Unauthorized");
|
||||||
}
|
}
|
||||||
|
|
||||||
const apps = await getApplications();
|
const apps = await getApps();
|
||||||
const app = apps.find((app) => app.id === appId);
|
const app = apps.find((app) => app.id === appId);
|
||||||
if (!app) throw new Error("App not found");
|
if (!app) throw new Error("App not found");
|
||||||
editApp(appId, { ...app, env: variables });
|
editApp(appId, { ...app, env: variables });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeApp(appId: string) {
|
export async function removeApp(appId: string) {
|
||||||
const apps = await getApplications();
|
const apps = await getApps();
|
||||||
|
|
||||||
const nextApps = apps.filter((app) => app.id !== appId);
|
const nextApps = apps.filter((app) => app.id !== appId);
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ export async function removeApp(appId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function editApp(appId: string, updatedApp: Application) {
|
export async function editApp(appId: string, updatedApp: Application) {
|
||||||
const apps = await getApplications();
|
const apps = await getApps();
|
||||||
|
|
||||||
const nextApps = apps.map((app) => (app.id === appId ? updatedApp : app));
|
const nextApps = apps.map((app) => (app.id === appId ? updatedApp : app));
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export async function getDeployments(): Promise<(null | Deployment)[]> {
|
|||||||
await axios.get(`http://${n.ip}:3000/api/deploy`, {
|
await axios.get(`http://${n.ip}:3000/api/deploy`, {
|
||||||
headers: { Authorization: `ApiKey ${n.key}` },
|
headers: { Authorization: `ApiKey ${n.key}` },
|
||||||
})
|
})
|
||||||
).data.applications
|
).data.apps
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).flat();
|
).flat();
|
||||||
|
|||||||
Reference in New Issue
Block a user