From cbb87dcaf121437a7595ab6d351f2582f4bfc588 Mon Sep 17 00:00:00 2001 From: Derock Date: Sat, 18 May 2024 22:43:29 -0400 Subject: [PATCH] feat: log style improvements, streaming imporvements --- package.json | 2 + pnpm-lock.yaml | 26 ++++++ .../_components/DeploymentCard.tsx | 9 +- .../_components/DeploymentLogs.tsx | 49 ++++------ .../service/[serviceId]/deployments/page.tsx | 3 + .../service/[serviceId]/logs/page.tsx | 32 +++++++ src/components/LogWindow.tsx | 52 +++++++++++ src/server/api/middleware/service.ts | 2 +- .../api/routers/projects/service/index.ts | 6 +- .../api/routers/projects/service/logs.ts | 91 +++++++++++++++---- src/server/docker/docker.ts | 47 ++++++++++ src/server/managers/Service.ts | 20 +++- src/server/utils/serverUtils.ts | 54 +++++++++++ 13 files changed, 329 insertions(+), 64 deletions(-) create mode 100644 src/app/(dashboard)/project/[projectId]/service/[serviceId]/logs/page.tsx create mode 100644 src/components/LogWindow.tsx diff --git a/package.json b/package.json index 8067034..bbfd127 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@trpc/server": "11.0.0-next-alpha.150", "@uiw/codemirror-extensions-langs": "^4.21.21", "@uiw/react-codemirror": "^4.21.21", + "ansi-to-react": "^6.1.6", "argon2": "^0.31.2", "better-sqlite3": "^9.2.2", "bufferutil": "^4.0.8", @@ -93,6 +94,7 @@ "@types/better-sqlite3": "^7.6.8", "@types/common-tags": "^1.8.4", "@types/cookie": "^0.6.0", + "@types/docker-modem": "^3.0.6", "@types/dockerode": "^3.3.23", "@types/eslint": "^8.56.1", "@types/node": "^20.10.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f78ba6a..001d7e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ dependencies: '@uiw/react-codemirror': specifier: ^4.21.21 version: 4.21.21(@babel/runtime@7.23.9)(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.1)(@codemirror/lint@6.5.0)(@codemirror/search@6.5.6)(@codemirror/state@6.4.0)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.24.0)(codemirror@6.0.1)(react-dom@18.2.0)(react@18.2.0) + ansi-to-react: + specifier: ^6.1.6 + version: 6.1.6(react-dom@18.2.0)(react@18.2.0) argon2: specifier: ^0.31.2 version: 0.31.2 @@ -226,6 +229,9 @@ devDependencies: '@types/cookie': specifier: ^0.6.0 version: 0.6.0 + '@types/docker-modem': + specifier: ^3.0.6 + version: 3.0.6 '@types/dockerode': specifier: ^3.3.23 version: 3.3.23 @@ -3331,6 +3337,10 @@ packages: uri-js: 4.4.1 dev: true + /anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + dev: false + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -3356,6 +3366,18 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + /ansi-to-react@6.1.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+HWn72GKydtupxX9TORBedqOMsJRiKTqaLUKW8txSBZw9iBpzPKLI8KOu4WzwD4R7hSv1zEspobY6LwlWvwZ6Q==} + peerDependencies: + react: ^16.3.2 || ^17.0.0 + react-dom: ^16.3.2 || ^17.0.0 + dependencies: + anser: 1.4.10 + escape-carriage: 1.3.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -4751,6 +4773,10 @@ packages: engines: {node: '>=6'} dev: true + /escape-carriage@1.3.1: + resolution: {integrity: sha512-GwBr6yViW3ttx1kb7/Oh+gKQ1/TrhYwxKqVmg5gS+BK+Qe2KrOa/Vh7w3HPBvgGf0LfcDGoY9I6NHKoA5Hozhw==} + dev: false + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} diff --git a/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentCard.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentCard.tsx index 8c7e81b..051e4d8 100644 --- a/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentCard.tsx +++ b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentCard.tsx @@ -40,17 +40,10 @@ export function DeploymentCard({ }: { deployment: RouterOutputs["projects"]["services"]["deployments"][number]; }) { - const [deploymentId, setDeploymentId] = useQueryParam( - "deploymentId", - StringParam, - ); + const [_, setDeploymentId] = useQueryParam("deploymentId", StringParam); return ( - {deploymentId === deployment.id && ( - - )} -

diff --git a/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentLogs.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentLogs.tsx index 7838922..cd3201a 100644 --- a/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentLogs.tsx +++ b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/deployments/_components/DeploymentLogs.tsx @@ -7,62 +7,45 @@ import { useProject } from "../../../../_context/ProjectContext"; import { useState } from "react"; import { toast } from "sonner"; import { Drawer, DrawerContent } from "~/components/ui/drawer"; +import { LogWindow, type LogLine } from "~/components/LogWindow"; +import { StringParam, useQueryParam } from "use-query-params"; -export function DeploymentLogs({ - deployment, -}: { - deployment: RouterOutputs["projects"]["services"]["deployments"][number]; -}) { +export function DeploymentLogs() { const project = useProject(); - const [logs, setLogs] = useState(null); + const [logs, setLogs] = useState(null); + const [deploymentId, setDeploymentId] = useQueryParam( + "deploymentId", + StringParam, + ); api.projects.services.deploymentLogs.useSubscription( { serviceId: project.selectedService!.id, - deploymentId: deployment.id, + deploymentId: deploymentId ?? "", projectId: project.id, }, { onData(data) { - setLogs( - (existing) => - (existing += data - .split("\n") - .map((it) => { - try { - return JSON.parse(it); - } catch (error) { - return { m: it }; - } - }) - .map((it) => it.m) - .join("\n")), - ); + setLogs((existing) => existing?.concat(data) ?? [data]); }, onError(error) { console.error(error); toast.error("Failed to fetch logs: " + error.message); }, + + enabled: !!deploymentId, }, ); return ( - + setDeploymentId(null)}>

Logs

- {/*
{logs}
*/} -