@muhammedaksam/easiarr 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +29750 -0
- package/package.json +15 -15
- package/src/VersionInfo.ts +0 -12
- package/src/api/arr-api.ts +0 -521
- package/src/api/auto-setup-types.ts +0 -64
- package/src/api/base-api.ts +0 -216
- package/src/api/bazarr-api.ts +0 -297
- package/src/api/cloudflare-api.ts +0 -493
- package/src/api/custom-format-api.ts +0 -224
- package/src/api/grafana-api.ts +0 -230
- package/src/api/heimdall-api.ts +0 -141
- package/src/api/homarr-api.ts +0 -209
- package/src/api/huntarr-api.ts +0 -457
- package/src/api/index.ts +0 -9
- package/src/api/jellyfin-api.ts +0 -389
- package/src/api/jellyseerr-api.ts +0 -559
- package/src/api/maintainerr-api.ts +0 -461
- package/src/api/naming-config.ts +0 -101
- package/src/api/overseerr-api.ts +0 -392
- package/src/api/plex-api.ts +0 -308
- package/src/api/portainer-api.ts +0 -374
- package/src/api/profilarr-api.ts +0 -391
- package/src/api/prowlarr-api.ts +0 -488
- package/src/api/qbittorrent-api.ts +0 -300
- package/src/api/quality-profile-api.ts +0 -272
- package/src/api/tautulli-api.ts +0 -244
- package/src/api/uptime-kuma-api.ts +0 -343
- package/src/apps/categories.ts +0 -14
- package/src/apps/index.ts +0 -2
- package/src/apps/registry.ts +0 -1275
- package/src/compose/caddy-config.ts +0 -130
- package/src/compose/generator.ts +0 -287
- package/src/compose/index.ts +0 -7
- package/src/compose/templates.ts +0 -78
- package/src/compose/traefik-config.ts +0 -187
- package/src/config/bookmarks-generator.ts +0 -160
- package/src/config/defaults.ts +0 -37
- package/src/config/homepage-config.ts +0 -381
- package/src/config/index.ts +0 -6
- package/src/config/manager.ts +0 -150
- package/src/config/recyclarr-config.ts +0 -181
- package/src/config/schema.ts +0 -310
- package/src/config/slskd-config.ts +0 -86
- package/src/config/soularr-config.ts +0 -105
- package/src/config/trash-quality-definitions.ts +0 -213
- package/src/data/lidarr-custom-formats.ts +0 -127
- package/src/data/trash-profiles.ts +0 -333
- package/src/docker/client.ts +0 -312
- package/src/docker/index.ts +0 -18
- package/src/index.ts +0 -77
- package/src/setup/actions/arr-common.ts +0 -307
- package/src/setup/actions/dashboards.ts +0 -79
- package/src/setup/actions/download-clients.ts +0 -54
- package/src/setup/actions/jellyseerr.ts +0 -331
- package/src/setup/actions/media-servers.ts +0 -68
- package/src/setup/actions/monitoring.ts +0 -120
- package/src/setup/actions/prowlarr.ts +0 -137
- package/src/setup/actions/utilities.ts +0 -490
- package/src/setup/index.ts +0 -78
- package/src/setup/types.ts +0 -144
- package/src/structure/manager.ts +0 -129
- package/src/ui/App.ts +0 -111
- package/src/ui/components/ApplicationSelector.ts +0 -275
- package/src/ui/components/CredentialsForm.ts +0 -180
- package/src/ui/components/DownloadClientForm.ts +0 -114
- package/src/ui/components/FileEditor.ts +0 -91
- package/src/ui/components/FooterHint.ts +0 -119
- package/src/ui/components/PageLayout.ts +0 -160
- package/src/ui/components/UpdateNotification.ts +0 -102
- package/src/ui/index.ts +0 -7
- package/src/ui/screens/AdvancedSettings.ts +0 -188
- package/src/ui/screens/ApiKeyViewer.ts +0 -511
- package/src/ui/screens/AppConfigurator.ts +0 -543
- package/src/ui/screens/AppManager.ts +0 -284
- package/src/ui/screens/ContainerControl.ts +0 -581
- package/src/ui/screens/LogsViewer.ts +0 -478
- package/src/ui/screens/MainMenu.ts +0 -299
- package/src/ui/screens/MonitorDashboard.ts +0 -881
- package/src/ui/screens/SecretsEditor.ts +0 -216
- package/src/ui/screens/SettingsScreen.ts +0 -633
- package/src/ui/screens/index.ts +0 -22
- package/src/ui/screens/setup/BaseAppSetupScreen.ts +0 -375
- package/src/ui/screens/setup/CloudflaredSetup.ts +0 -460
- package/src/ui/screens/setup/FullAutoSetup.ts +0 -766
- package/src/ui/screens/setup/HomepageSetup.ts +0 -165
- package/src/ui/screens/setup/JellyfinSetup.ts +0 -328
- package/src/ui/screens/setup/JellyseerrSetup.ts +0 -242
- package/src/ui/screens/setup/ProwlarrSetup.ts +0 -500
- package/src/ui/screens/setup/QBittorrentSetup.ts +0 -221
- package/src/ui/screens/setup/QuickSetup.ts +0 -1169
- package/src/ui/screens/setup/RecyclarrSetup.ts +0 -270
- package/src/ui/screens/setup/TRaSHProfileSetup.ts +0 -381
- package/src/utils/arch.ts +0 -78
- package/src/utils/browser.ts +0 -27
- package/src/utils/categories.ts +0 -61
- package/src/utils/debug.ts +0 -84
- package/src/utils/env.ts +0 -138
- package/src/utils/index.ts +0 -8
- package/src/utils/logs.ts +0 -119
- package/src/utils/migrations/1765626338_rename_env_variables.ts +0 -102
- package/src/utils/migrations/1765707135_rename_easiarr_status.ts +0 -91
- package/src/utils/migrations/1765732722_remove_cloudflare_dns_api_token.ts +0 -45
- package/src/utils/migrations/1769515650_migrate_to_xdg.ts +0 -114
- package/src/utils/migrations.ts +0 -165
- package/src/utils/password.ts +0 -42
- package/src/utils/paths.ts +0 -33
- package/src/utils/unraid.ts +0 -103
- package/src/utils/update-checker.ts +0 -210
- package/src/utils/url-utils.ts +0 -38
|
@@ -1,478 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Container Logs Viewer Screen
|
|
3
|
-
* Full-screen log viewer with streaming, search, and save functionality
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { CliRenderer, KeyEvent, RenderContext } from "@opentui/core"
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
BoxRenderable,
|
|
10
|
-
SelectRenderable,
|
|
11
|
-
SelectRenderableEvents,
|
|
12
|
-
TextRenderable,
|
|
13
|
-
} from "@opentui/core"
|
|
14
|
-
|
|
15
|
-
import type { EasiarrConfig } from "~/config/schema"
|
|
16
|
-
import type { ContainerStatus } from "~/docker"
|
|
17
|
-
import { getContainerLogs, getContainerStatuses } from "~/docker"
|
|
18
|
-
import { createPageLayout } from "~/ui/components/PageLayout"
|
|
19
|
-
import { formatBytes, formatRelativeTime, listSavedLogs, saveLog } from "~/utils/logs"
|
|
20
|
-
|
|
21
|
-
type ViewMode = "select" | "logs" | "saved"
|
|
22
|
-
|
|
23
|
-
export class LogsViewer extends BoxRenderable {
|
|
24
|
-
private renderer: CliRenderer
|
|
25
|
-
private config: EasiarrConfig
|
|
26
|
-
private onBack: () => void
|
|
27
|
-
private keyHandler: ((k: KeyEvent) => void) | null = null
|
|
28
|
-
|
|
29
|
-
// State
|
|
30
|
-
private mode: ViewMode = "select"
|
|
31
|
-
private containers: ContainerStatus[] = []
|
|
32
|
-
private selectedContainer: ContainerStatus | null = null
|
|
33
|
-
private logContent: string[] = []
|
|
34
|
-
private scrollOffset = 0
|
|
35
|
-
private lineCount = 100 // Number of log lines to fetch
|
|
36
|
-
private visibleLines = 35 // Number of visible lines in log view
|
|
37
|
-
private isLoading = false
|
|
38
|
-
private statusMessage = ""
|
|
39
|
-
private savedLogs: Array<{ filename: string; path: string; date: Date; size: number }> = []
|
|
40
|
-
|
|
41
|
-
// UI Components
|
|
42
|
-
private page!: BoxRenderable
|
|
43
|
-
private content!: BoxRenderable
|
|
44
|
-
private statusBar!: TextRenderable
|
|
45
|
-
|
|
46
|
-
constructor(renderer: RenderContext, config: EasiarrConfig, onBack: () => void) {
|
|
47
|
-
super(renderer, { width: "100%", height: "100%", flexDirection: "column" })
|
|
48
|
-
this.renderer = renderer as CliRenderer
|
|
49
|
-
this.config = config
|
|
50
|
-
this.onBack = onBack
|
|
51
|
-
|
|
52
|
-
this.init()
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
private async init(): Promise<void> {
|
|
56
|
-
await this.loadContainers()
|
|
57
|
-
this.buildUI()
|
|
58
|
-
this.attachKeyHandler()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private async loadContainers(): Promise<void> {
|
|
62
|
-
this.isLoading = true
|
|
63
|
-
const all = await getContainerStatuses()
|
|
64
|
-
// Only show running containers (can fetch logs from them)
|
|
65
|
-
this.containers = all.filter((c) => c.status === "running")
|
|
66
|
-
this.isLoading = false
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private buildUI(): void {
|
|
70
|
-
const { container: page, content } = createPageLayout(this.renderer, {
|
|
71
|
-
title: "📋 Container Logs",
|
|
72
|
-
stepInfo: `${this.containers.length} running containers`,
|
|
73
|
-
footerHint: this.getFooterHints(),
|
|
74
|
-
})
|
|
75
|
-
this.page = page
|
|
76
|
-
this.content = content
|
|
77
|
-
|
|
78
|
-
this.statusBar = new TextRenderable(this.renderer, {
|
|
79
|
-
id: "status-bar",
|
|
80
|
-
content: "",
|
|
81
|
-
fg: "#f1fa8c",
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
this.renderContent()
|
|
85
|
-
this.add(page)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private getFooterHints(): Array<
|
|
89
|
-
{ type: "key"; key: string; value: string } | { type: "separator" }
|
|
90
|
-
> {
|
|
91
|
-
switch (this.mode) {
|
|
92
|
-
case "select":
|
|
93
|
-
return [
|
|
94
|
-
{ type: "key", key: "Enter", value: "View Logs" },
|
|
95
|
-
{ type: "key", key: "h", value: "Saved Logs" },
|
|
96
|
-
{ type: "key", key: "q", value: "Back" },
|
|
97
|
-
]
|
|
98
|
-
case "logs":
|
|
99
|
-
return [
|
|
100
|
-
{ type: "key", key: "↑↓", value: "Scroll" },
|
|
101
|
-
{ type: "key", key: "s", value: "Save" },
|
|
102
|
-
{ type: "key", key: "r", value: "Refresh" },
|
|
103
|
-
{ type: "key", key: "+/-", value: "Lines" },
|
|
104
|
-
{ type: "key", key: "q", value: "Back" },
|
|
105
|
-
]
|
|
106
|
-
case "saved":
|
|
107
|
-
return [
|
|
108
|
-
{ type: "key", key: "Enter", value: "View" },
|
|
109
|
-
{ type: "key", key: "q", value: "Back" },
|
|
110
|
-
]
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
private clearContent(): void {
|
|
115
|
-
const children = [...this.content.getChildren()]
|
|
116
|
-
for (const child of children) {
|
|
117
|
-
if (child.id) this.content.remove(child.id)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private renderContent(): void {
|
|
122
|
-
this.clearContent()
|
|
123
|
-
|
|
124
|
-
switch (this.mode) {
|
|
125
|
-
case "select":
|
|
126
|
-
this.renderContainerSelect()
|
|
127
|
-
break
|
|
128
|
-
case "logs":
|
|
129
|
-
this.renderLogView()
|
|
130
|
-
break
|
|
131
|
-
case "saved":
|
|
132
|
-
this.renderSavedLogs()
|
|
133
|
-
break
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
this.content.add(this.statusBar)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private renderContainerSelect(): void {
|
|
140
|
-
if (this.containers.length === 0) {
|
|
141
|
-
this.content.add(
|
|
142
|
-
new TextRenderable(this.renderer, {
|
|
143
|
-
id: "no-containers",
|
|
144
|
-
content: "No running containers found.\nStart containers first to view logs.",
|
|
145
|
-
fg: "#888888",
|
|
146
|
-
})
|
|
147
|
-
)
|
|
148
|
-
return
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.content.add(
|
|
152
|
-
new TextRenderable(this.renderer, {
|
|
153
|
-
id: "select-header",
|
|
154
|
-
content: "Select a container to view logs:",
|
|
155
|
-
fg: "#4a9eff",
|
|
156
|
-
})
|
|
157
|
-
)
|
|
158
|
-
this.content.add(new TextRenderable(this.renderer, { content: "" }))
|
|
159
|
-
|
|
160
|
-
const menu = new SelectRenderable(this.renderer, {
|
|
161
|
-
id: "container-select",
|
|
162
|
-
width: "100%",
|
|
163
|
-
flexGrow: 1,
|
|
164
|
-
options: this.containers.map((c) => ({
|
|
165
|
-
name: `🐳 ${c.name}`,
|
|
166
|
-
description: c.ports ? `Ports: ${c.ports.split(",")[0]}` : "",
|
|
167
|
-
})),
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
menu.on(SelectRenderableEvents.ITEM_SELECTED, async (index) => {
|
|
171
|
-
this.selectedContainer = this.containers[index]
|
|
172
|
-
await this.fetchLogs()
|
|
173
|
-
this.mode = "logs"
|
|
174
|
-
this.scrollOffset = 0
|
|
175
|
-
this.rebuildUI()
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
this.content.add(menu)
|
|
179
|
-
setTimeout(() => menu.focus(), 10)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
private renderLogView(): void {
|
|
183
|
-
if (!this.selectedContainer) return
|
|
184
|
-
|
|
185
|
-
// Header with container info
|
|
186
|
-
const header = new BoxRenderable(this.renderer, {
|
|
187
|
-
id: "log-header",
|
|
188
|
-
width: "100%",
|
|
189
|
-
flexDirection: "row",
|
|
190
|
-
marginBottom: 1,
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
header.add(
|
|
194
|
-
new TextRenderable(this.renderer, {
|
|
195
|
-
id: "container-name",
|
|
196
|
-
content: `📦 ${this.selectedContainer.name}`,
|
|
197
|
-
fg: "#4a9eff",
|
|
198
|
-
})
|
|
199
|
-
)
|
|
200
|
-
header.add(
|
|
201
|
-
new TextRenderable(this.renderer, {
|
|
202
|
-
id: "log-info",
|
|
203
|
-
content: ` (${this.lineCount} lines, scroll: ${this.scrollOffset}/${Math.max(0, this.logContent.length - this.visibleLines)})`,
|
|
204
|
-
fg: "#666666",
|
|
205
|
-
})
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
this.content.add(header)
|
|
209
|
-
|
|
210
|
-
// Log content box
|
|
211
|
-
const logBox = new BoxRenderable(this.renderer, {
|
|
212
|
-
id: "log-box",
|
|
213
|
-
width: "100%",
|
|
214
|
-
flexGrow: 1,
|
|
215
|
-
flexDirection: "column",
|
|
216
|
-
border: true,
|
|
217
|
-
borderStyle: "single",
|
|
218
|
-
borderColor: "#444444",
|
|
219
|
-
padding: 1,
|
|
220
|
-
overflow: "hidden",
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
if (this.isLoading) {
|
|
224
|
-
logBox.add(
|
|
225
|
-
new TextRenderable(this.renderer, {
|
|
226
|
-
id: "loading",
|
|
227
|
-
content: "Loading logs...",
|
|
228
|
-
fg: "#f1fa8c",
|
|
229
|
-
})
|
|
230
|
-
)
|
|
231
|
-
} else if (this.logContent.length === 0) {
|
|
232
|
-
logBox.add(
|
|
233
|
-
new TextRenderable(this.renderer, {
|
|
234
|
-
id: "no-logs",
|
|
235
|
-
content: "No logs available",
|
|
236
|
-
fg: "#888888",
|
|
237
|
-
})
|
|
238
|
-
)
|
|
239
|
-
} else {
|
|
240
|
-
// Show visible lines based on scroll offset
|
|
241
|
-
const lines = this.logContent.slice(this.scrollOffset, this.scrollOffset + this.visibleLines)
|
|
242
|
-
|
|
243
|
-
lines.forEach((line, idx) => {
|
|
244
|
-
// Colorize log levels
|
|
245
|
-
let fg = "#888888"
|
|
246
|
-
if (line.includes("ERROR") || line.includes("error")) fg = "#ff5555"
|
|
247
|
-
else if (line.includes("WARN") || line.includes("warn")) fg = "#f1fa8c"
|
|
248
|
-
else if (line.includes("INFO") || line.includes("info")) fg = "#50fa7b"
|
|
249
|
-
else if (line.includes("DEBUG") || line.includes("debug")) fg = "#6272a4"
|
|
250
|
-
|
|
251
|
-
logBox.add(
|
|
252
|
-
new TextRenderable(this.renderer, {
|
|
253
|
-
id: `log-line-${idx}`,
|
|
254
|
-
content: line.substring(0, 120), // Truncate long lines
|
|
255
|
-
fg,
|
|
256
|
-
})
|
|
257
|
-
)
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
this.content.add(logBox)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
private async renderSavedLogs(): Promise<void> {
|
|
265
|
-
if (!this.selectedContainer) {
|
|
266
|
-
this.content.add(
|
|
267
|
-
new TextRenderable(this.renderer, {
|
|
268
|
-
id: "no-selection",
|
|
269
|
-
content: "Select a container first to view saved logs.",
|
|
270
|
-
fg: "#888888",
|
|
271
|
-
})
|
|
272
|
-
)
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
this.savedLogs = await listSavedLogs(this.selectedContainer.name)
|
|
277
|
-
|
|
278
|
-
this.content.add(
|
|
279
|
-
new TextRenderable(this.renderer, {
|
|
280
|
-
id: "saved-header",
|
|
281
|
-
content: `📁 Saved logs for ${this.selectedContainer.name}:`,
|
|
282
|
-
fg: "#4a9eff",
|
|
283
|
-
})
|
|
284
|
-
)
|
|
285
|
-
this.content.add(new TextRenderable(this.renderer, { content: "" }))
|
|
286
|
-
|
|
287
|
-
if (this.savedLogs.length === 0) {
|
|
288
|
-
this.content.add(
|
|
289
|
-
new TextRenderable(this.renderer, {
|
|
290
|
-
id: "no-saved",
|
|
291
|
-
content: "No saved logs found. Press 's' while viewing logs to save.",
|
|
292
|
-
fg: "#888888",
|
|
293
|
-
})
|
|
294
|
-
)
|
|
295
|
-
return
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const menu = new SelectRenderable(this.renderer, {
|
|
299
|
-
id: "saved-select",
|
|
300
|
-
width: "100%",
|
|
301
|
-
flexGrow: 1,
|
|
302
|
-
options: this.savedLogs.map((log) => ({
|
|
303
|
-
name: `📄 ${log.filename}`,
|
|
304
|
-
description: `${formatBytes(log.size)} - ${formatRelativeTime(log.date)}`,
|
|
305
|
-
})),
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
menu.on(SelectRenderableEvents.ITEM_SELECTED, async (index) => {
|
|
309
|
-
const log = this.savedLogs[index]
|
|
310
|
-
// Load and display saved log
|
|
311
|
-
const content = await Bun.file(log.path).text()
|
|
312
|
-
this.logContent = content.split("\n")
|
|
313
|
-
this.scrollOffset = 0
|
|
314
|
-
this.mode = "logs"
|
|
315
|
-
this.rebuildUI()
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
this.content.add(menu)
|
|
319
|
-
setTimeout(() => menu.focus(), 10)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
private async fetchLogs(): Promise<void> {
|
|
323
|
-
if (!this.selectedContainer) return
|
|
324
|
-
|
|
325
|
-
this.isLoading = true
|
|
326
|
-
this.setStatus("Fetching logs...", "#f1fa8c")
|
|
327
|
-
|
|
328
|
-
const result = await getContainerLogs(this.selectedContainer.name, this.lineCount)
|
|
329
|
-
|
|
330
|
-
if (result.success) {
|
|
331
|
-
this.logContent = result.output.split("\n").filter((line) => line.trim())
|
|
332
|
-
this.setStatus(`Loaded ${this.logContent.length} lines`, "#50fa7b")
|
|
333
|
-
} else {
|
|
334
|
-
this.logContent = []
|
|
335
|
-
this.setStatus("Failed to fetch logs", "#ff5555")
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
this.isLoading = false
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
private async saveCurrentLogs(): Promise<void> {
|
|
342
|
-
if (!this.selectedContainer || this.logContent.length === 0) {
|
|
343
|
-
this.setStatus("No logs to save", "#ff5555")
|
|
344
|
-
return
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
this.setStatus("Saving logs...", "#f1fa8c")
|
|
348
|
-
const content = this.logContent.join("\n")
|
|
349
|
-
const filepath = await saveLog(this.selectedContainer.name, content)
|
|
350
|
-
this.setStatus(`✓ Saved to ${filepath}`, "#50fa7b")
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
private setStatus(message: string, color: string): void {
|
|
354
|
-
this.statusMessage = message
|
|
355
|
-
if (this.statusBar) {
|
|
356
|
-
this.statusBar.content = message
|
|
357
|
-
this.statusBar.fg = color
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
private rebuildUI(): void {
|
|
362
|
-
// Remove old page
|
|
363
|
-
if (this.page) {
|
|
364
|
-
this.remove(this.page.id)
|
|
365
|
-
}
|
|
366
|
-
this.buildUI()
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
private attachKeyHandler(): void {
|
|
370
|
-
this.keyHandler = async (k: KeyEvent) => {
|
|
371
|
-
switch (this.mode) {
|
|
372
|
-
case "select":
|
|
373
|
-
await this.handleSelectModeKey(k)
|
|
374
|
-
break
|
|
375
|
-
case "logs":
|
|
376
|
-
await this.handleLogsModeKey(k)
|
|
377
|
-
break
|
|
378
|
-
case "saved":
|
|
379
|
-
await this.handleSavedModeKey(k)
|
|
380
|
-
break
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
this.renderer.keyInput.on("keypress", this.keyHandler)
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
private async handleSelectModeKey(k: KeyEvent): Promise<void> {
|
|
387
|
-
switch (k.name) {
|
|
388
|
-
case "h":
|
|
389
|
-
if (this.selectedContainer) {
|
|
390
|
-
this.mode = "saved"
|
|
391
|
-
this.rebuildUI()
|
|
392
|
-
}
|
|
393
|
-
break
|
|
394
|
-
case "q":
|
|
395
|
-
case "escape":
|
|
396
|
-
this.cleanup()
|
|
397
|
-
this.onBack()
|
|
398
|
-
break
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
private async handleLogsModeKey(k: KeyEvent): Promise<void> {
|
|
403
|
-
const maxScroll = Math.max(0, this.logContent.length - this.visibleLines)
|
|
404
|
-
|
|
405
|
-
switch (k.name) {
|
|
406
|
-
case "up":
|
|
407
|
-
this.scrollOffset = Math.max(0, this.scrollOffset - 1)
|
|
408
|
-
this.renderContent()
|
|
409
|
-
break
|
|
410
|
-
case "down":
|
|
411
|
-
this.scrollOffset = Math.min(maxScroll, this.scrollOffset + 1)
|
|
412
|
-
this.renderContent()
|
|
413
|
-
break
|
|
414
|
-
case "pageup":
|
|
415
|
-
this.scrollOffset = Math.max(0, this.scrollOffset - 10)
|
|
416
|
-
this.renderContent()
|
|
417
|
-
break
|
|
418
|
-
case "pagedown":
|
|
419
|
-
this.scrollOffset = Math.min(maxScroll, this.scrollOffset + 10)
|
|
420
|
-
this.renderContent()
|
|
421
|
-
break
|
|
422
|
-
case "home":
|
|
423
|
-
this.scrollOffset = 0
|
|
424
|
-
this.renderContent()
|
|
425
|
-
break
|
|
426
|
-
case "end":
|
|
427
|
-
this.scrollOffset = maxScroll
|
|
428
|
-
this.renderContent()
|
|
429
|
-
break
|
|
430
|
-
case "s":
|
|
431
|
-
await this.saveCurrentLogs()
|
|
432
|
-
break
|
|
433
|
-
case "r":
|
|
434
|
-
await this.fetchLogs()
|
|
435
|
-
this.renderContent()
|
|
436
|
-
break
|
|
437
|
-
case "+":
|
|
438
|
-
case "=":
|
|
439
|
-
this.lineCount = Math.min(500, this.lineCount + 50)
|
|
440
|
-
await this.fetchLogs()
|
|
441
|
-
this.rebuildUI()
|
|
442
|
-
break
|
|
443
|
-
case "-":
|
|
444
|
-
this.lineCount = Math.max(50, this.lineCount - 50)
|
|
445
|
-
await this.fetchLogs()
|
|
446
|
-
this.rebuildUI()
|
|
447
|
-
break
|
|
448
|
-
case "h":
|
|
449
|
-
this.mode = "saved"
|
|
450
|
-
this.rebuildUI()
|
|
451
|
-
break
|
|
452
|
-
case "q":
|
|
453
|
-
case "escape":
|
|
454
|
-
this.mode = "select"
|
|
455
|
-
this.selectedContainer = null
|
|
456
|
-
this.logContent = []
|
|
457
|
-
this.rebuildUI()
|
|
458
|
-
break
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
private async handleSavedModeKey(k: KeyEvent): Promise<void> {
|
|
463
|
-
switch (k.name) {
|
|
464
|
-
case "q":
|
|
465
|
-
case "escape":
|
|
466
|
-
this.mode = this.selectedContainer ? "logs" : "select"
|
|
467
|
-
this.rebuildUI()
|
|
468
|
-
break
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
private cleanup(): void {
|
|
473
|
-
if (this.keyHandler) {
|
|
474
|
-
this.renderer.keyInput.off("keypress", this.keyHandler)
|
|
475
|
-
this.keyHandler = null
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|