Skip to content

Commit ecb0927

Browse files
committed
Allow getting previous logs in terminal window
- Added scroll functionality to view previous logs - Updated terminal color handling - Improved pod logs component Signed-off-by: adameska <[email protected]>
1 parent 97f0afd commit ecb0927

File tree

3 files changed

+39
-106
lines changed

3 files changed

+39
-106
lines changed

packages/webview/src/component/pods/PodLogs.svelte

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import type { Terminal } from '@xterm/xterm';
99
import TerminalWindow from '/@/component/terminal/TerminalWindow.svelte';
1010
import { SvelteMap } from 'svelte/reactivity';
11-
import { ansi256Colours, colourizedANSIContainerName, colorizeLogLevel } from '/@/component/terminal/terminal-colors';
11+
import { ansi256Colours, colourizedANSIContainerName } from '/@/component/terminal/terminal-colors';
1212
1313
interface Props {
1414
object: V1Pod;
@@ -66,17 +66,13 @@
6666
// All lines are prefixed, except the last one if it's empty.
6767
const lines = data
6868
.split('\n')
69-
.map(line => colorizeLogLevel(line))
7069
.map((line, index, arr) =>
7170
index < arr.length - 1 || line.length > 0 ? `${padding}${colouredName}|${line}` : line,
7271
);
7372
callback(lines.join('\n'));
7473
}
7574
: (_name: string, data: string, callback: (data: string) => void): void => {
76-
const lines = data
77-
.split('\n')
78-
.map(line => colorizeLogLevel(line));
79-
callback(lines.join('\n'));
75+
callback(data);
8076
};
8177
8278
const options: PodLogsOptions = {

packages/webview/src/component/terminal/TerminalWindow.svelte

Lines changed: 37 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,45 @@
11
<script lang="ts">
2-
import '@xterm/xterm/css/xterm.css';
3-
4-
import { FitAddon } from '@xterm/addon-fit';
5-
import { Terminal } from '@xterm/xterm';
6-
import { onDestroy, onMount } from 'svelte';
7-
8-
import { getTerminalTheme } from './terminal-theme';
9-
import TerminalSearchControls from './TerminalSearchControls.svelte';
10-
11-
interface Props {
12-
terminal?: Terminal;
13-
convertEol?: boolean;
14-
disableStdIn?: boolean;
15-
screenReaderMode?: boolean;
16-
showCursor?: boolean;
17-
search?: boolean;
18-
class?: string;
19-
fontSize?: number;
20-
}
21-
22-
let {
23-
terminal = $bindable(),
24-
convertEol,
25-
disableStdIn = true,
26-
screenReaderMode,
27-
showCursor = false,
28-
search = false,
29-
class: className,
30-
fontSize = 10,
31-
}: Props = $props();
32-
33-
let logsXtermDiv: HTMLDivElement | undefined;
34-
let resizeHandler: () => void;
35-
let fitAddon: FitAddon;
2+
import '@xterm/xterm/css/xterm.css';
3+
4+
import { FitAddon } from '@xterm/addon-fit';
5+
import { Terminal } from '@xterm/xterm';
6+
import { onDestroy, onMount } from 'svelte';
7+
8+
import { getTerminalTheme } from './terminal-theme';
9+
import TerminalSearchControls from './TerminalSearchControls.svelte';
10+
11+
interface Props {
12+
terminal?: Terminal;
13+
convertEol?: boolean;
14+
disableStdIn?: boolean;
15+
screenReaderMode?: boolean;
16+
showCursor?: boolean;
17+
search?: boolean;
18+
class?: string;
19+
fontSize?: number;
20+
}
3621
37-
async function refreshTerminal(): Promise<void> {
22+
let {
23+
terminal = $bindable(),
24+
convertEol,
25+
disableStdIn = true,
26+
screenReaderMode,
27+
showCursor = false,
28+
search = false,
29+
class: className,
30+
fontSize = 10,
31+
}: Props = $props();
32+
33+
let logsXtermDiv: HTMLDivElement | undefined;
34+
let resizeHandler: () => void;
35+
let fitAddon: FitAddon;
36+
37+
async function refreshTerminal(): Promise<void> {
3838
// missing element, return
3939
if (!logsXtermDiv) {
4040
return;
4141
}
42-
42+
4343
const lineHeight = 1; // TODO: get from configuration
4444
4545
terminal = new Terminal({
@@ -49,7 +49,7 @@
4949
theme: getTerminalTheme(),
5050
convertEol: convertEol,
5151
screenReaderMode: screenReaderMode,
52-
rightClickSelectsWord: true,
52+
rightClickSelectsWord: true,
5353
});
5454
fitAddon = new FitAddon();
5555
terminal.loadAddon(fitAddon);
@@ -60,25 +60,6 @@
6060
terminal.write('\x1b[?25l');
6161
}
6262
63-
// Handle text selection and copy to clipboard
64-
terminal.onSelectionChange(() => {
65-
const selection = terminal.getSelection();
66-
if (selection) {
67-
const textarea = document.createElement('textarea');
68-
textarea.value = selection;
69-
textarea.style.position = 'fixed';
70-
textarea.style.opacity = '0';
71-
document.body.appendChild(textarea);
72-
textarea.select();
73-
try {
74-
document.execCommand('copy');
75-
} catch (err) {
76-
console.error('Failed to copy:', err);
77-
}
78-
document.body.removeChild(textarea);
79-
}
80-
});
81-
8263
// call fit addon each time we resize the window
8364
resizeHandler = (): void => {
8465
fitAddon.fit();

packages/webview/src/component/terminal/terminal-colors.ts

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -32,52 +32,8 @@ export const ansi256Colours = [
3232
'\u001b[34;1m', // bright blue
3333
];
3434

35-
// ANSI colors for log levels
36-
const LOG_LEVEL_COLORS: Record<string, string> = {
37-
DBG: '\u001b[36m', // cyan
38-
DEBUG: '\u001b[36m',
39-
INF: '\u001b[32m', // green
40-
INFO: '\u001b[32m',
41-
WRN: '\u001b[33m', // yellow
42-
WARN: '\u001b[33m',
43-
WARNING: '\u001b[33m',
44-
ERR: '\u001b[31m', // red
45-
ERROR: '\u001b[31m',
46-
FATAL: '\u001b[31;1m', // bright red
47-
TRACE: '\u001b[35m', // magenta
48-
};
49-
5035
// Function that takes the container name and ANSI colour and encapsulates the name in the colour,
5136
// making sure that we reset the colour back to white after the name.
5237
export function colourizedANSIContainerName(name: string, colour: string): string {
5338
return `${colour}${name}\u001b[0m`;
5439
}
55-
56-
/**
57-
* Colorizes log levels in brackets for better readability.
58-
* Detects patterns like [timestamp LEVEL] or [LEVEL] anywhere in the line.
59-
*
60-
* Examples:
61-
* - [23:10:06 INF] -> green
62-
* - [DBG] -> cyan
63-
* - [ERROR] -> red
64-
* - 2025-10-29T23:10:10.688386132-05:00 [23:10:10 INF] -> green (with K8s timestamp)
65-
*/
66-
export function colorizeLogLevel(logLine: string): string {
67-
// Pattern to match [timestamp? LEVEL] anywhere in the line (removed ^ anchor)
68-
const logLevelPattern = /(\[(?:[0-9:]+\s+)?)(DBG|DEBUG|INF|INFO|WRN|WARN|WARNING|ERR|ERROR|FATAL|TRACE)(\])/i;
69-
70-
const match = logLine.match(logLevelPattern);
71-
if (match && match.index !== undefined) {
72-
const beforeBracket = logLine.slice(0, match.index);
73-
const prefix = match[1]; // [timestamp or [
74-
const level = match[2].toUpperCase();
75-
const suffix = match[3]; // ]
76-
const rest = logLine.slice(match.index + match[0].length);
77-
78-
const color = LOG_LEVEL_COLORS[level] || '\u001b[37m';
79-
return `${beforeBracket}${color}${prefix}${level}${suffix}\u001b[0m${rest}`;
80-
}
81-
82-
return logLine;
83-
}

0 commit comments

Comments
 (0)