From a574aeb48f35f971750de9423c19a2743b3c6799 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Thu, 1 Jan 2026 06:37:21 +0100 Subject: [PATCH] Get env --- src/app/environment/page.tsx | 70 +++++++++++----------------------- src/core/application.ts | 19 ++++++++- src/core/server/application.ts | 20 +++++++++- src/lib/format.ts | 7 ++++ src/lib/types.ts | 6 +++ 5 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/app/environment/page.tsx b/src/app/environment/page.tsx index 15f00a3..c5013b3 100644 --- a/src/app/environment/page.tsx +++ b/src/app/environment/page.tsx @@ -1,51 +1,28 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { DashboardLayout } from "@/components/dashboard/DashboardLayout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Plus, Trash2, Eye, EyeOff, Copy, Save, Lock } from "lucide-react"; - -const envGroups = [ - { - name: "api-gateway", - variables: [ - { key: "PORT", value: "8080", secret: false }, - { key: "NODE_ENV", value: "production", secret: false }, - { key: "API_KEY", value: "sk-xxxx-xxxx-xxxx", secret: true }, - { key: "DATABASE_URL", value: "postgresql://...", secret: true }, - { key: "REDIS_URL", value: "redis://localhost:6379", secret: false }, - { key: "LOG_LEVEL", value: "info", secret: false }, - ], - }, - { - name: "auth-service", - variables: [ - { key: "PORT", value: "9000", secret: false }, - { key: "JWT_SECRET", value: "xxxxxxxxxxxx", secret: true }, - { key: "JWT_EXPIRY", value: "7d", secret: false }, - { key: "OAUTH_CLIENT_ID", value: "client-id-xxxx", secret: true }, - { key: "OAUTH_CLIENT_SECRET", value: "client-secret-xxxx", secret: true }, - ], - }, - { - name: "worker-queue", - variables: [ - { key: "QUEUE_URL", value: "amqp://localhost:5672", secret: false }, - { key: "CONCURRENCY", value: "10", secret: false }, - { key: "RETRY_LIMIT", value: "3", secret: false }, - { key: "DEAD_LETTER_QUEUE", value: "dlq.worker", secret: false }, - ], - }, -]; +import { Env } from "@/lib/types"; +import { getEnv } from "@/core/application"; export default function EnvironmentPage() { - const [selectedApp, setSelectedApp] = useState("api-gateway"); + const [selectedApp, setSelectedApp] = useState(""); const [showSecrets, setShowSecrets] = useState>({}); + const [envGroups, setEnvGroups] = useState>({}); - const currentGroup = envGroups.find((g) => g.name === selectedApp); + useEffect(() => { + const fetch = async () => { + setEnvGroups(await getEnv()); + }; + fetch(); + }, []); + + const currentGroup = envGroups[selectedApp]; const toggleSecret = (key: string) => { setShowSecrets((prev) => ({ ...prev, [key]: !prev[key] })); @@ -70,23 +47,21 @@ export default function EnvironmentPage() { - {envGroups.map((group) => ( + {Object.entries(envGroups).map(([key, variables]) => ( ))} @@ -100,9 +75,8 @@ export default function EnvironmentPage() {
{selectedApp}

- {currentGroup?.variables.length} variables •{" "} - {currentGroup?.variables.filter((v) => v.secret).length}{" "} - secrets + {currentGroup?.length} variables •{" "} + {currentGroup?.filter((v) => v.secret).length} secrets

@@ -128,7 +102,7 @@ export default function EnvironmentPage() { {/* Rows */}
- {currentGroup?.variables.map((variable) => ( + {currentGroup?.map((variable) => (
{ ) ).flat(); } + +export async function getEnv(): Promise> { + const nodes = await getNodes(); + + const envRecords = await Promise.all( + nodes.map(async (n) => { + const response = await axios.get(`http://${n.ip}:3000/api/env`, { + headers: { Authorization: `ApiKey ${n.key}` }, + }); + return response.data as Record; + }) + ); + + const merged: Record = Object.assign({}, ...envRecords); + + return merged; +} diff --git a/src/core/server/application.ts b/src/core/server/application.ts index a5c23ea..4c3bd73 100644 --- a/src/core/server/application.ts +++ b/src/core/server/application.ts @@ -6,7 +6,7 @@ import fs from "fs"; import path from "path"; import { exec } from "child_process"; import util from "util"; -import { ImageApp } from "@/lib/types"; +import { Env, ImageApp } from "@/lib/types"; import { CPUusage } from "@/lib/server/calc"; const docker = new Docker(); @@ -100,6 +100,8 @@ export async function deployNewApp(name: string, repo: string, nodeId: string) { JSON.stringify(appConfig, null, 2) ); + fs.writeFileSync(path.join(appDir, "env.json"), JSON.stringify([], null, 2)); + // Clone repository try { await execAsync(`git clone ${repo} ${repoDir}`); @@ -132,3 +134,19 @@ export async function deployNewApp(name: string, repo: string, nodeId: string) { image: imageTag, }; } + +export async function getEnv(): Promise> { + const apps = fs.readdirSync(DATA_DIR); + + return apps.reduce((acc, appId) => { + const appPath = path.join(DATA_DIR, appId, "app.json"); + const name = JSON.parse(fs.readFileSync(appPath).toString()).name; + + const envPath = path.join(DATA_DIR, appId, "env.json"); + if (fs.existsSync(envPath)) { + const envData: Env[] = JSON.parse(fs.readFileSync(envPath, "utf-8")); + acc[name] = envData; + } + return acc; + }, {} as Record); +} diff --git a/src/lib/format.ts b/src/lib/format.ts index 7749bec..b5347f7 100644 --- a/src/lib/format.ts +++ b/src/lib/format.ts @@ -15,3 +15,10 @@ export function average(values: Array, p: (v: T) => number) { ? values.reduce((sum, value) => sum + p(value), 0) / values.length : 0; } + +export function mapRecord( + input: Record, + fn: ([key, value]: [string, T]) => [string, U] +): Record { + return Object.fromEntries(Object.entries(input).map(fn)); +} diff --git a/src/lib/types.ts b/src/lib/types.ts index cffc3e3..0244f1e 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -81,3 +81,9 @@ export interface Log { source: string; message: string; } + +export interface Env { + key: string; + value: string; + secret: boolean; +}