From c804cd4bdfa69caa9b69c62692cc9f8a113ae7d9 Mon Sep 17 00:00:00 2001 From: biersoeckli Date: Sat, 2 Nov 2024 13:57:53 +0000 Subject: [PATCH] added logs for builds --- package.json | 1 + src/app/project/app/[tabName]/app-tabs.tsx | 2 +- .../[tabName]/overview/build-logs-overlay.tsx | 51 ++++++++++++ .../overview/{builds.tsx => deployments.tsx} | 7 +- .../app/[tabName]/overview/logs-streamed.tsx | 39 +++++---- src/server/services/build.service.ts | 15 ++++ src/server/services/log-stream.service.ts | 80 ++++++++++++++----- 7 files changed, 156 insertions(+), 39 deletions(-) create mode 100644 src/app/project/app/[tabName]/overview/build-logs-overlay.tsx rename src/app/project/app/[tabName]/overview/{builds.tsx => deployments.tsx} (90%) diff --git a/package.json b/package.json index a83ce69..41355a5 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "scripts": { "dev": "next dev", + "dev-live": "bun src/server.ts", "build": "next build", "start": "next start", "prisma-generate": "bunx prisma generate && bun ./fix-wrong-zod-imports.js", diff --git a/src/app/project/app/[tabName]/app-tabs.tsx b/src/app/project/app/[tabName]/app-tabs.tsx index b325a00..525c81e 100644 --- a/src/app/project/app/[tabName]/app-tabs.tsx +++ b/src/app/project/app/[tabName]/app-tabs.tsx @@ -10,7 +10,7 @@ import DomainsList from "./domains/domains"; import StorageList from "./storage/storages"; import { AppExtendedModel } from "@/model/app-extended.model"; import { BuildJobModel } from "@/model/build-job"; -import BuildsTab from "./overview/builds"; +import BuildsTab from "./overview/deployments"; import Logs from "./overview/logs"; export default function AppTabs({ diff --git a/src/app/project/app/[tabName]/overview/build-logs-overlay.tsx b/src/app/project/app/[tabName]/overview/build-logs-overlay.tsx new file mode 100644 index 0000000..60cfd69 --- /dev/null +++ b/src/app/project/app/[tabName]/overview/build-logs-overlay.tsx @@ -0,0 +1,51 @@ +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import React, { useEffect } from "react"; +import { set } from "date-fns"; +import { DeploymentInfoModel } from "@/model/deployment-info.model"; +import LogsStreamed from "./logs-streamed"; +import { formatDate } from "@/lib/format.utils"; +import { podLogsSocket } from "@/lib/sockets"; + +export function BuildLogsDialog({ + deploymentInfo, + onClose +}: { + deploymentInfo?: DeploymentInfoModel; + onClose: () => void; +}) { + + if (!deploymentInfo) { + return <>; + } + + return ( + { + podLogsSocket.emit('leavePodLog', { streamKey: deploymentInfo.buildJobName }); + onClose(); + }}> + + + Build Logs + + View the build logs for the selected deployment {formatDate(deploymentInfo.createdAt)}. + + +
+ {!deploymentInfo.buildJobName && 'For this build is no log available'} + {deploymentInfo.buildJobName && } +
+
+
+ ) +} diff --git a/src/app/project/app/[tabName]/overview/builds.tsx b/src/app/project/app/[tabName]/overview/deployments.tsx similarity index 90% rename from src/app/project/app/[tabName]/overview/builds.tsx rename to src/app/project/app/[tabName]/overview/deployments.tsx index 806d977..bdcbc08 100644 --- a/src/app/project/app/[tabName]/overview/builds.tsx +++ b/src/app/project/app/[tabName]/overview/deployments.tsx @@ -17,6 +17,7 @@ import { DeploymentInfoModel } from "@/model/deployment-info.model"; import DeploymentStatusBadge from "./deployment-status-badge"; import { io } from "socket.io-client"; import { podLogsSocket } from "@/lib/sockets"; +import { BuildLogsDialog } from "./build-logs-overlay"; export default function BuildsTab({ app @@ -27,6 +28,7 @@ export default function BuildsTab({ const { openDialog } = useConfirmDialog(); const [appBuilds, setAppBuilds] = useState(undefined); const [error, setError] = useState(undefined); + const [selectedDeploymentForLogs, setSelectedDeploymentForLogs] = useState(undefined); const updateBuilds = async () => { setError(undefined); @@ -90,7 +92,7 @@ export default function BuildsTab({ return <>
- {item.buildJobName && } + {item.buildJobName && } {item.buildJobName && item.status === 'BUILDING' && }
@@ -98,6 +100,7 @@ export default function BuildsTab({ /> } - + + setSelectedDeploymentForLogs(undefined)} /> ; } diff --git a/src/app/project/app/[tabName]/overview/logs-streamed.tsx b/src/app/project/app/[tabName]/overview/logs-streamed.tsx index c0f8949..d5cbb63 100644 --- a/src/app/project/app/[tabName]/overview/logs-streamed.tsx +++ b/src/app/project/app/[tabName]/overview/logs-streamed.tsx @@ -1,17 +1,21 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { podLogsSocket } from "@/lib/sockets"; import { Textarea } from "@/components/ui/textarea"; +import React from "react"; export default function LogsStreamed({ namespace, podName, + buildJobName, }: { - namespace: string; - podName: string; + namespace?: string; + podName?: string; + buildJobName?: string; }) { const [isConnected, setIsConnected] = useState(false); const [transport, setTransport] = useState("N/A"); const [logs, setLogs] = useState(''); + const textAreaRef = useRef(null); function onConnect() { setIsConnected(true); @@ -28,40 +32,47 @@ export default function LogsStreamed({ } const myListener = (e: string) => { - setLogs(e); + setLogs((prevLogs) => prevLogs + e); } useEffect(() => { - if (!podName) { + if (!buildJobName && (!namespace || !podName)) { return; } - const logEventName = `${namespace}_${podName}`; - console.log('Connecting to logs ' + logEventName); + const streamKey = buildJobName ? buildJobName : `${namespace}_${podName}`; + console.log('Connecting to logs ' + streamKey); if (podLogsSocket.connected) { onConnect(); } - podLogsSocket.emit('joinPodLog', { namespace, podName }); + podLogsSocket.emit('joinPodLog', { namespace, podName, buildJobName }); podLogsSocket.on("connect", onConnect); podLogsSocket.on("disconnect", onDisconnect); - podLogsSocket.on(logEventName, myListener); + podLogsSocket.on(streamKey, myListener); return () => { if (!podName) { return; } - console.log('Disconnecting from logs ' + logEventName); - podLogsSocket.emit('leavePodLog', { namespace, podName }); + console.log('Disconnecting from logs ' + streamKey); + podLogsSocket.emit('leavePodLog', { streamKey: streamKey }); setLogs(''); podLogsSocket.off("connect", onConnect); podLogsSocket.off("disconnect", onDisconnect); - podLogsSocket.off(logEventName, myListener); + podLogsSocket.off(streamKey, myListener); }; - }, [namespace, podName]); + }, [namespace, podName, buildJobName]); + + useEffect(() => { + if (textAreaRef.current) { + // Scroll to the bottom every time logs change + textAreaRef.current.scrollTop = textAreaRef.current.scrollHeight; + } + }, [logs]); return <> -