diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42b6aa3..c9cf0c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ on: branches: ["main"] env: - VERSION: "1.5.3" + VERSION: "1.5.4" jobs: docker: diff --git a/pkg/common/common.go b/pkg/common/common.go index 4ce10b2..7165260 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -1,3 +1,3 @@ package common -const Version = "1.5.3" \ No newline at end of file +const Version = "1.5.4" \ No newline at end of file diff --git a/web/src/app/compose/compose-logs.tsx b/web/src/app/compose/compose-logs.tsx index 4117c37..503d832 100644 --- a/web/src/app/compose/compose-logs.tsx +++ b/web/src/app/compose/compose-logs.tsx @@ -13,18 +13,26 @@ import { useEffect, useState } from "react" import { wsApiBaseUrl } from "@/lib/api-base-url" import { AttachAddon } from "@xterm/addon-attach" import { FitAddon } from "@xterm/addon-fit" -import { newTerminal, recreateTerminalElement } from "@/lib/utils" +import { + downloadTerminalTextAsFile, + newTerminal, + recreateTerminalElement, +} from "@/lib/utils" import useNodeHead from "@/hooks/useNodeHead" import useNodeComposeItem from "@/hooks/useNodeComposeItem" +import { Button } from "@/components/ui/button" +import { Terminal } from "@xterm/xterm" export default function ComposeLogs() { const { nodeId, composeProjectId } = useParams() const { nodeHead } = useNodeHead(nodeId!) const { nodeComposeItem } = useNodeComposeItem(nodeId!, composeProjectId!) const [socket, setSocket] = useState(null!) + const [terminal, setTerminal] = useState(null!) useEffect(() => { - const terminal = newTerminal() + const t = newTerminal() + setTerminal(t) if (socket) socket.close() const s = new WebSocket( @@ -32,18 +40,25 @@ export default function ComposeLogs() { ) setSocket(s) - terminal.loadAddon(new AttachAddon(s)) + t.loadAddon(new AttachAddon(s)) const fitAddon = new FitAddon() - terminal.loadAddon(fitAddon) + t.loadAddon(fitAddon) const terminalEl = recreateTerminalElement("terminalContainer", "terminal") - terminal.open(terminalEl!) + t.open(terminalEl!) fitAddon.fit() addEventListener("resize", () => { fitAddon?.fit() }) }, [composeProjectId]) + const handleDownload = () => { + downloadTerminalTextAsFile( + terminal, + `logs_${nodeComposeItem?.projectName}.txt` + ) + } + return ( @@ -65,7 +80,9 @@ export default function ComposeLogs() { Logs - + + +
diff --git a/web/src/app/containers/container-logs.tsx b/web/src/app/containers/container-logs.tsx index 2e17171..7e6ef30 100644 --- a/web/src/app/containers/container-logs.tsx +++ b/web/src/app/containers/container-logs.tsx @@ -13,17 +13,25 @@ import { useParams } from "react-router-dom" import "/node_modules/xterm/css/xterm.css" import { useEffect, useState } from "react" import { wsApiBaseUrl } from "@/lib/api-base-url" -import { newTerminal, recreateTerminalElement } from "@/lib/utils" +import { + downloadTerminalTextAsFile, + newTerminal, + recreateTerminalElement, +} from "@/lib/utils" import { AttachAddon } from "@xterm/addon-attach" import useNodeHead from "@/hooks/useNodeHead" +import { Button } from "@/components/ui/button" +import { Terminal } from "@xterm/xterm" export default function ContainerLogs() { const { nodeId, containerId } = useParams() const { nodeHead } = useNodeHead(nodeId!) const [socket, setSocket] = useState(null!) + const [terminal, setTerminal] = useState(null!) useEffect(() => { - const terminal = newTerminal() + const t = newTerminal() + setTerminal(t) if (socket) socket.close() const s = new WebSocket( @@ -31,18 +39,22 @@ export default function ContainerLogs() { ) setSocket(s) - terminal.loadAddon(new AttachAddon(s)) + t.loadAddon(new AttachAddon(s)) const fitAddon = new FitAddon() - terminal.loadAddon(fitAddon) + t.loadAddon(fitAddon) const terminalEl = recreateTerminalElement("terminalContainer", "terminal") - terminal.open(terminalEl!) + t.open(terminalEl!) fitAddon.fit() addEventListener("resize", () => { fitAddon?.fit() }) }, [containerId]) + const handleDownload = () => { + downloadTerminalTextAsFile(terminal, `logs_${containerId}.txt`) + } + return ( @@ -59,7 +71,9 @@ export default function ContainerLogs() { Logs for {containerId} - + + +
diff --git a/web/src/components/side-nav/side-nav-compose.tsx b/web/src/components/side-nav/side-nav-compose.tsx index 6e9bc8f..4a9df3f 100644 --- a/web/src/components/side-nav/side-nav-compose.tsx +++ b/web/src/components/side-nav/side-nav-compose.tsx @@ -35,7 +35,7 @@ export function SideNavCompose() {
    {items.map((item) => ( -
  • +
  • {item.icon} {item.title} diff --git a/web/src/components/side-nav/side-nav-node.tsx b/web/src/components/side-nav/side-nav-node.tsx index 770fd92..b7f8043 100644 --- a/web/src/components/side-nav/side-nav-node.tsx +++ b/web/src/components/side-nav/side-nav-node.tsx @@ -57,7 +57,7 @@ export function SideNavNode() {
      {items.map((item) => ( -
    • +
    • {item.icon} {item.title} diff --git a/web/src/components/side-nav/side-nav-top-level.tsx b/web/src/components/side-nav/side-nav-top-level.tsx index 21a1049..f63d7ea 100644 --- a/web/src/components/side-nav/side-nav-top-level.tsx +++ b/web/src/components/side-nav/side-nav-top-level.tsx @@ -44,7 +44,7 @@ export function SideNavTopLevel() { <>
        {items.map((item) => ( -
      • +
      • {item.icon} {item.title} diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index 0805344..5ef4754 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -89,6 +89,20 @@ export function newTerminal(convertToEol?: boolean) { }) } +export function downloadTerminalTextAsFile( + terminal: Terminal, + filename: string +) { + let text = "" + const l = terminal.buffer.normal.length + for (let i = 0; i < l; i++) { + const line = terminal.buffer.normal.getLine(i)?.translateToString(true) + text += `${line}\r\n` + } + + download(filename, text) +} + export function initMonaco() { loader.init().then((monaco) => { monaco.editor.defineTheme("dark", { @@ -129,3 +143,19 @@ export function toastFailed(message: string) { description: message, }) } + +export function download(filename: string, text: string) { + var element = document.createElement("a") + element.setAttribute( + "href", + "data:text/plain;charset=utf-8," + encodeURIComponent(text) + ) + element.setAttribute("download", filename) + + element.style.display = "none" + document.body.appendChild(element) + + element.click() + + document.body.removeChild(element) +} diff --git a/web/src/lib/version.ts b/web/src/lib/version.ts index 4a380e4..e92c14f 100644 --- a/web/src/lib/version.ts +++ b/web/src/lib/version.ts @@ -1 +1 @@ -export const VERSION = "1.5.3" +export const VERSION = "1.5.4"