App info
This commit is contained in:
@@ -8,11 +8,11 @@ import { Play, Square, RotateCcw, MoreVertical, Plus } from "lucide-react";
|
|||||||
import { Progress } from "@/components/ui/progress";
|
import { Progress } from "@/components/ui/progress";
|
||||||
import DeployApplication from "@/components/dialogs/DeployApplication";
|
import DeployApplication from "@/components/dialogs/DeployApplication";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Application } from "@/lib/types";
|
import { ImageApp } from "@/lib/types";
|
||||||
import { getApplications } from "@/core/application";
|
import { getApplications } from "@/core/application";
|
||||||
|
|
||||||
export default function ApplicationsPage() {
|
export default function ApplicationsPage() {
|
||||||
const [applications, setApplications] = useState<Application[]>([]);
|
const [applications, setApplications] = useState<ImageApp[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
@@ -22,6 +22,8 @@ export default function ApplicationsPage() {
|
|||||||
fetch();
|
fetch();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
console.log(applications);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardLayout
|
<DashboardLayout
|
||||||
title="Applications"
|
title="Applications"
|
||||||
@@ -54,7 +56,7 @@ export default function ApplicationsPage() {
|
|||||||
{/* {app.status} */}
|
{/* {app.status} */}
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="font-mono text-sm font-medium">
|
<div className="font-mono text-sm font-medium">
|
||||||
{app.name}
|
{app.app?.name || app.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-muted-foreground font-mono truncate">
|
<div className="text-xs text-muted-foreground font-mono truncate">
|
||||||
{app.image}
|
{app.image}
|
||||||
@@ -62,10 +64,10 @@ export default function ApplicationsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Replicas */}
|
{/* Containers */}
|
||||||
<div className="flex justify-between md:block md:col-span-1">
|
<div className="flex justify-between md:block md:col-span-1">
|
||||||
<span className="text-xs text-muted-foreground md:hidden">
|
<span className="text-xs text-muted-foreground md:hidden">
|
||||||
Replicas
|
Containers
|
||||||
</span>
|
</span>
|
||||||
<div className="font-mono text-sm">{app.replicas}</div>
|
<div className="font-mono text-sm">{app.replicas}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { verifySession } from "./auth/session";
|
import { verifySession } from "./auth/session";
|
||||||
import { getNodes } from "./node";
|
import { getNodes } from "./node";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { Application } from "@/lib/types";
|
import { ImageApp } from "@/lib/types";
|
||||||
|
|
||||||
export async function deployNewApp(name: string, repo: string, nodeId: string) {
|
export async function deployNewApp(name: string, repo: string, nodeId: string) {
|
||||||
if (await verifySession()) {
|
if (await verifySession()) {
|
||||||
@@ -25,7 +25,7 @@ export async function deployNewApp(name: string, repo: string, nodeId: string) {
|
|||||||
).data.applications;
|
).data.applications;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getApplications(): Promise<Application[]> {
|
export async function getApplications(): Promise<ImageApp[]> {
|
||||||
const nodes = await getNodes();
|
const nodes = await getNodes();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,22 +2,21 @@
|
|||||||
|
|
||||||
import Docker from "dockerode";
|
import Docker from "dockerode";
|
||||||
import { randomUUID } from "crypto";
|
import { randomUUID } from "crypto";
|
||||||
import fs from "fs/promises";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
import util from "util";
|
import util from "util";
|
||||||
import axios from "axios";
|
import { ImageApp } from "@/lib/types";
|
||||||
import { Application } from "@/lib/types";
|
|
||||||
|
|
||||||
const docker = new Docker();
|
const docker = new Docker();
|
||||||
const execAsync = util.promisify(exec);
|
const execAsync = util.promisify(exec);
|
||||||
const DATA_DIR = path.join(process.cwd(), "data", "apps");
|
const DATA_DIR = path.join(process.cwd(), "data", "apps");
|
||||||
|
|
||||||
export async function getApplications(): Promise<Application[]> {
|
export async function getApplications(): Promise<ImageApp[]> {
|
||||||
const images = await docker.listImages();
|
const images = await docker.listImages();
|
||||||
const containers = await docker.listContainers({ all: true });
|
const containers = await docker.listContainers({ all: true });
|
||||||
|
|
||||||
const apps: Application[] = [];
|
const apps: ImageApp[] = [];
|
||||||
|
|
||||||
for (const image of images) {
|
for (const image of images) {
|
||||||
const imageName = image.RepoTags?.[0];
|
const imageName = image.RepoTags?.[0];
|
||||||
@@ -46,9 +45,20 @@ export async function getApplications(): Promise<Application[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const name = imageName.split("/").pop()?.split(":")[0] ?? imageName;
|
||||||
|
|
||||||
|
var app;
|
||||||
|
|
||||||
|
try {
|
||||||
|
app = JSON.parse(
|
||||||
|
fs.readFileSync(path.join(DATA_DIR, name, "app.json")).toString()
|
||||||
|
);
|
||||||
|
} catch {}
|
||||||
|
|
||||||
apps.push({
|
apps.push({
|
||||||
|
app,
|
||||||
|
name,
|
||||||
id: image.Id.slice(7, 15),
|
id: image.Id.slice(7, 15),
|
||||||
name: imageName.split("/").pop()?.split(":")[0] ?? imageName,
|
|
||||||
image: imageName,
|
image: imageName,
|
||||||
containers: relatedContainers.length,
|
containers: relatedContainers.length,
|
||||||
replicas: `${running}/${relatedContainers.length}`,
|
replicas: `${running}/${relatedContainers.length}`,
|
||||||
@@ -70,7 +80,7 @@ export async function deployNewApp(name: string, repo: string, nodeId: string) {
|
|||||||
const repoDir = path.join(appDir, "repo");
|
const repoDir = path.join(appDir, "repo");
|
||||||
|
|
||||||
// Create directories
|
// Create directories
|
||||||
await fs.mkdir(repoDir, { recursive: true });
|
fs.mkdirSync(repoDir, { recursive: true });
|
||||||
|
|
||||||
// Write app.json
|
// Write app.json
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
@@ -81,7 +91,7 @@ export async function deployNewApp(name: string, repo: string, nodeId: string) {
|
|||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
await fs.writeFile(
|
fs.writeFileSync(
|
||||||
path.join(appDir, "app.json"),
|
path.join(appDir, "app.json"),
|
||||||
JSON.stringify(appConfig, null, 2)
|
JSON.stringify(appConfig, null, 2)
|
||||||
);
|
);
|
||||||
@@ -97,7 +107,7 @@ export async function deployNewApp(name: string, repo: string, nodeId: string) {
|
|||||||
const dockerfilePath = path.join(repoDir, "Dockerfile");
|
const dockerfilePath = path.join(repoDir, "Dockerfile");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.access(dockerfilePath);
|
fs.accessSync(dockerfilePath);
|
||||||
} catch {
|
} catch {
|
||||||
throw new Error("Dockerfile not found in repository root");
|
throw new Error("Dockerfile not found in repository root");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ export interface Docker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Application {
|
export interface Application {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
repo: string;
|
||||||
|
nodeId: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageApp {
|
||||||
|
app?: Application;
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
image: string;
|
image: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user