@muhammedaksam/easiarr 0.4.2 → 0.5.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/package.json +1 -1
- package/src/api/arr-api.ts +156 -0
- package/src/api/prowlarr-api.ts +447 -14
- package/src/apps/registry.ts +5 -0
- package/src/config/schema.ts +34 -0
- package/src/index.ts +4 -0
- package/src/ui/components/FooterHint.ts +119 -0
- package/src/ui/components/PageLayout.ts +58 -10
- package/src/ui/screens/AdvancedSettings.ts +4 -1
- package/src/ui/screens/ApiKeyViewer.ts +6 -1
- package/src/ui/screens/AppConfigurator.ts +16 -5
- package/src/ui/screens/AppManager.ts +6 -1
- package/src/ui/screens/ContainerControl.ts +4 -1
- package/src/ui/screens/FullAutoSetup.ts +4 -1
- package/src/ui/screens/MainMenu.ts +19 -3
- package/src/ui/screens/MonitorDashboard.ts +866 -0
- package/src/ui/screens/ProwlarrSetup.ts +260 -5
- package/src/ui/screens/QBittorrentSetup.ts +4 -1
- package/src/ui/screens/QuickSetup.ts +36 -8
- package/src/ui/screens/TRaSHProfileSetup.ts +6 -1
package/src/config/schema.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface EasiarrConfig {
|
|
|
16
16
|
network?: NetworkConfig
|
|
17
17
|
traefik?: TraefikConfig
|
|
18
18
|
vpn?: VpnConfig
|
|
19
|
+
monitor?: MonitorConfig
|
|
19
20
|
createdAt: string
|
|
20
21
|
updatedAt: string
|
|
21
22
|
}
|
|
@@ -27,6 +28,38 @@ export interface VpnConfig {
|
|
|
27
28
|
provider?: string // For future use (e.g. custom, airvpn, protonvpn)
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
// ==========================================
|
|
32
|
+
// Monitoring Configuration
|
|
33
|
+
// ==========================================
|
|
34
|
+
|
|
35
|
+
export type MonitorCheckType = "health" | "diskspace" | "status" | "queue"
|
|
36
|
+
|
|
37
|
+
export interface MonitorOptions {
|
|
38
|
+
health: boolean
|
|
39
|
+
diskspace: boolean
|
|
40
|
+
status: boolean
|
|
41
|
+
queue: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface CategoryMonitorConfig {
|
|
45
|
+
category: AppCategory
|
|
46
|
+
enabled: boolean
|
|
47
|
+
checks: MonitorOptions
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface AppMonitorConfig {
|
|
51
|
+
appId: AppId
|
|
52
|
+
override: boolean // If true, uses app-specific settings instead of category defaults
|
|
53
|
+
enabled: boolean
|
|
54
|
+
checks: MonitorOptions
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface MonitorConfig {
|
|
58
|
+
categories: CategoryMonitorConfig[]
|
|
59
|
+
apps: AppMonitorConfig[] // App-specific overrides
|
|
60
|
+
pollIntervalSeconds: number
|
|
61
|
+
}
|
|
62
|
+
|
|
30
63
|
export interface TraefikConfig {
|
|
31
64
|
enabled: boolean
|
|
32
65
|
domain: string
|
|
@@ -152,6 +185,7 @@ export interface AppDefinition {
|
|
|
152
185
|
cap_add?: string[]
|
|
153
186
|
apiKeyMeta?: ApiKeyMeta
|
|
154
187
|
rootFolder?: RootFolderMeta
|
|
188
|
+
prowlarrCategoryIds?: number[]
|
|
155
189
|
/** Architecture compatibility info - omit if supports all */
|
|
156
190
|
arch?: ArchCompatibility
|
|
157
191
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Footer Hint Types and Utilities
|
|
3
|
+
* Provides a flexible array-based structure for footer hints
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Base interface for all footer hint types with common styling */
|
|
7
|
+
export interface FooterHintBase {
|
|
8
|
+
/** Foreground color */
|
|
9
|
+
fg?: string
|
|
10
|
+
/** Background color */
|
|
11
|
+
bg?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** A simple text message hint (e.g., "Press ? for help.") */
|
|
15
|
+
export interface FooterHintText extends FooterHintBase {
|
|
16
|
+
type: "text"
|
|
17
|
+
value: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A keyboard shortcut hint (e.g., key: "↓", value: "Down") */
|
|
21
|
+
export interface FooterHintKey extends FooterHintBase {
|
|
22
|
+
type: "key"
|
|
23
|
+
key: string
|
|
24
|
+
value: string
|
|
25
|
+
/** Color for the key part (default: bright/highlighted) */
|
|
26
|
+
keyColor?: string
|
|
27
|
+
/** Color for the value part (default: dimmer) */
|
|
28
|
+
valueColor?: string
|
|
29
|
+
/** Background color for the key badge */
|
|
30
|
+
keyBgColor?: string
|
|
31
|
+
/** Whether to show brackets around the key */
|
|
32
|
+
withBrackets?: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Separator between hint groups */
|
|
36
|
+
export interface FooterHintSeparator extends FooterHintBase {
|
|
37
|
+
type: "separator"
|
|
38
|
+
char?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Union type for all hint item types */
|
|
42
|
+
export type FooterHintItem = FooterHintText | FooterHintKey | FooterHintSeparator
|
|
43
|
+
|
|
44
|
+
/** Array of hint items */
|
|
45
|
+
export type FooterHint = FooterHintItem[]
|
|
46
|
+
|
|
47
|
+
/** Default separator character */
|
|
48
|
+
const DEFAULT_SEPARATOR = " "
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Render footer hints to a plain string
|
|
52
|
+
* Used by PageLayout for backward-compatible rendering
|
|
53
|
+
*/
|
|
54
|
+
export function renderFooterHint(hints: FooterHint): string {
|
|
55
|
+
return hints
|
|
56
|
+
.map((item) => {
|
|
57
|
+
switch (item.type) {
|
|
58
|
+
case "text":
|
|
59
|
+
return item.value
|
|
60
|
+
case "key":
|
|
61
|
+
return `${item.key}: ${item.value}`
|
|
62
|
+
case "separator":
|
|
63
|
+
return item.char ?? DEFAULT_SEPARATOR
|
|
64
|
+
default:
|
|
65
|
+
return ""
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
.join(DEFAULT_SEPARATOR)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parse legacy string format to FooterHint array
|
|
73
|
+
* Supports both "Key: Action" and "Key Action" formats
|
|
74
|
+
*/
|
|
75
|
+
export function parseFooterHintString(hint: string): FooterHint {
|
|
76
|
+
// Split on double spaces (common separator in existing hints)
|
|
77
|
+
const parts = hint.split(/\s{2,}/)
|
|
78
|
+
|
|
79
|
+
return parts.map((part): FooterHintItem => {
|
|
80
|
+
// Try to parse as "Key: Action" or "Key Action" format
|
|
81
|
+
const colonMatch = part.match(/^([^\s:]+):\s*(.+)$/)
|
|
82
|
+
if (colonMatch) {
|
|
83
|
+
return { type: "key", key: colonMatch[1], value: colonMatch[2] }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const spaceMatch = part.match(/^([^\s]+)\s+(.+)$/)
|
|
87
|
+
if (spaceMatch) {
|
|
88
|
+
return { type: "key", key: spaceMatch[1], value: spaceMatch[2] }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Fallback to text
|
|
92
|
+
return { type: "text", value: part }
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Helper to create a key hint
|
|
98
|
+
*/
|
|
99
|
+
export function key(
|
|
100
|
+
key: string,
|
|
101
|
+
value: string,
|
|
102
|
+
options?: { keyColor?: string; valueColor?: string; keyBgColor?: string; withBrackets?: boolean }
|
|
103
|
+
): FooterHintKey {
|
|
104
|
+
return { type: "key", key, value, ...options }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Helper to create a text hint
|
|
109
|
+
*/
|
|
110
|
+
export function text(value: string, fg?: string): FooterHintText {
|
|
111
|
+
return { type: "text", value, fg }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Helper to create a separator
|
|
116
|
+
*/
|
|
117
|
+
export function separator(char?: string): FooterHintSeparator {
|
|
118
|
+
return { type: "separator", char }
|
|
119
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { BoxRenderable, TextRenderable, type CliRenderer } from "@opentui/core"
|
|
1
|
+
import { BoxRenderable, TextRenderable, TextNodeRenderable, type CliRenderer } from "@opentui/core"
|
|
2
2
|
import { getVersion } from "../../VersionInfo"
|
|
3
|
+
import { type FooterHint } from "./FooterHint"
|
|
3
4
|
|
|
4
5
|
export interface PageLayoutOptions {
|
|
5
6
|
title: string
|
|
6
7
|
stepInfo?: string
|
|
7
|
-
footerHint?: string
|
|
8
|
+
footerHint?: FooterHint | string
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export interface PageLayoutResult {
|
|
@@ -79,15 +80,62 @@ export function createPageLayout(renderer: CliRenderer, options: PageLayoutOptio
|
|
|
79
80
|
backgroundColor: "#1a1a2e",
|
|
80
81
|
})
|
|
81
82
|
|
|
82
|
-
// Hint text
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
// Hint text - handle both array and string formats
|
|
84
|
+
// Always append separator + Ctrl+C Exit when hints are provided
|
|
85
|
+
const hintContainer = new TextRenderable(renderer, {
|
|
86
|
+
id: `${idPrefix}-footer-hint`,
|
|
87
|
+
content: "",
|
|
88
|
+
fg: "#aaaaaa",
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
if (!footerHint) {
|
|
92
|
+
hintContainer.content = "↑↓: Navigate Enter: Select Ctrl+C: Exit"
|
|
93
|
+
} else if (typeof footerHint === "string") {
|
|
94
|
+
hintContainer.content = footerHint + " Ctrl+C: Exit"
|
|
95
|
+
} else {
|
|
96
|
+
// Append separator and global Ctrl+C hint (styled red for demo)
|
|
97
|
+
const hintsWithExit: FooterHint = [
|
|
98
|
+
...footerHint,
|
|
99
|
+
{ type: "separator", char: " | " },
|
|
100
|
+
{ type: "key", key: "Ctrl+C", value: "Exit", keyColor: "#ff6666", valueColor: "#888888" },
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
// Build styled content using TextNodeRenderable
|
|
104
|
+
const DEFAULT_KEY_COLOR = "#8be9fd" // cyan/bright
|
|
105
|
+
const DEFAULT_VALUE_COLOR = "#aaaaaa" // dim
|
|
106
|
+
const DEFAULT_SEP_COLOR = "#555555"
|
|
107
|
+
|
|
108
|
+
// Helper to create a styled text node
|
|
109
|
+
const styledText = (text: string, fg?: string, bg?: string): TextNodeRenderable => {
|
|
110
|
+
const node = new TextNodeRenderable({ fg, bg })
|
|
111
|
+
node.add(text)
|
|
112
|
+
return node
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
hintsWithExit.forEach((item, idx) => {
|
|
116
|
+
if (item.type === "separator") {
|
|
117
|
+
hintContainer.add(styledText(item.char ?? " ", DEFAULT_SEP_COLOR))
|
|
118
|
+
} else if (item.type === "text") {
|
|
119
|
+
hintContainer.add(styledText(item.value, item.fg ?? DEFAULT_VALUE_COLOR))
|
|
120
|
+
// Add spacing after text (except last)
|
|
121
|
+
if (idx < hintsWithExit.length - 1 && hintsWithExit[idx + 1]?.type !== "separator") {
|
|
122
|
+
hintContainer.add(styledText(" "))
|
|
123
|
+
}
|
|
124
|
+
} else if (item.type === "key") {
|
|
125
|
+
const keyDisplay = item.withBrackets ? `[${item.key}]` : item.key
|
|
126
|
+
// Key part (styled)
|
|
127
|
+
hintContainer.add(styledText(keyDisplay, item.keyColor ?? DEFAULT_KEY_COLOR, item.keyBgColor))
|
|
128
|
+
// Colon + Value
|
|
129
|
+
hintContainer.add(styledText(`: ${item.value}`, item.valueColor ?? DEFAULT_VALUE_COLOR))
|
|
130
|
+
// Add spacing after (except last or before separator)
|
|
131
|
+
if (idx < hintsWithExit.length - 1 && hintsWithExit[idx + 1]?.type !== "separator") {
|
|
132
|
+
hintContainer.add(styledText(" "))
|
|
133
|
+
}
|
|
134
|
+
}
|
|
89
135
|
})
|
|
90
|
-
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
footerBox.add(hintContainer)
|
|
91
139
|
|
|
92
140
|
// Version
|
|
93
141
|
footerBox.add(
|
|
@@ -58,7 +58,10 @@ export class AdvancedSettings {
|
|
|
58
58
|
const { container: page, content } = createPageLayout(this.renderer, {
|
|
59
59
|
title: "Advanced Settings",
|
|
60
60
|
stepInfo: "Direct File Editing",
|
|
61
|
-
footerHint:
|
|
61
|
+
footerHint: [
|
|
62
|
+
{ type: "key", key: "Enter", value: "Select" },
|
|
63
|
+
{ type: "key", key: "Esc", value: "Back" },
|
|
64
|
+
],
|
|
62
65
|
})
|
|
63
66
|
|
|
64
67
|
const menu = new SelectRenderable(this.renderer, {
|
|
@@ -235,7 +235,12 @@ export class ApiKeyViewer extends BoxRenderable {
|
|
|
235
235
|
const { container, content } = createPageLayout(this.cliRenderer, {
|
|
236
236
|
title: "API Key Extractor",
|
|
237
237
|
stepInfo: "Found Keys",
|
|
238
|
-
footerHint: hasFoundKeys
|
|
238
|
+
footerHint: hasFoundKeys
|
|
239
|
+
? [
|
|
240
|
+
{ type: "key", key: "S", value: "Save to .env" },
|
|
241
|
+
{ type: "key", key: "Esc/Enter", value: "Return" },
|
|
242
|
+
]
|
|
243
|
+
: [{ type: "key", key: "Esc/Enter", value: "Return" }],
|
|
239
244
|
})
|
|
240
245
|
this.add(container)
|
|
241
246
|
|
|
@@ -95,7 +95,12 @@ export class AppConfigurator extends BoxRenderable {
|
|
|
95
95
|
const { container, content } = createPageLayout(this.cliRenderer, {
|
|
96
96
|
title: "Configure Apps",
|
|
97
97
|
stepInfo: "Global Credentials",
|
|
98
|
-
footerHint:
|
|
98
|
+
footerHint: [
|
|
99
|
+
{ type: "key", key: "Tab", value: "Cycle Fields/Shortcuts" },
|
|
100
|
+
{ type: "key", key: "O", value: "Override" },
|
|
101
|
+
{ type: "key", key: "Enter", value: "Continue" },
|
|
102
|
+
{ type: "key", key: "Esc", value: "Skip" },
|
|
103
|
+
],
|
|
99
104
|
})
|
|
100
105
|
this.pageContainer = container
|
|
101
106
|
this.add(container)
|
|
@@ -358,7 +363,7 @@ export class AppConfigurator extends BoxRenderable {
|
|
|
358
363
|
const { container, content } = createPageLayout(this.cliRenderer, {
|
|
359
364
|
title: "Configure Apps",
|
|
360
365
|
stepInfo: "Setting up root folders",
|
|
361
|
-
footerHint: "Please wait...",
|
|
366
|
+
footerHint: [{ type: "text", value: "Please wait..." }],
|
|
362
367
|
})
|
|
363
368
|
this.pageContainer = container
|
|
364
369
|
this.contentBox = content
|
|
@@ -427,7 +432,10 @@ export class AppConfigurator extends BoxRenderable {
|
|
|
427
432
|
const { container, content } = createPageLayout(this.cliRenderer, {
|
|
428
433
|
title: "Configure Apps",
|
|
429
434
|
stepInfo: "qBittorrent Credentials",
|
|
430
|
-
footerHint:
|
|
435
|
+
footerHint: [
|
|
436
|
+
{ type: "text", value: "Enter credentials from qBittorrent WebUI" },
|
|
437
|
+
{ type: "key", key: "Esc", value: "Skip" },
|
|
438
|
+
],
|
|
431
439
|
})
|
|
432
440
|
this.pageContainer = container
|
|
433
441
|
this.add(container)
|
|
@@ -483,7 +491,10 @@ export class AppConfigurator extends BoxRenderable {
|
|
|
483
491
|
const { container, content } = createPageLayout(this.cliRenderer, {
|
|
484
492
|
title: "Configure Apps",
|
|
485
493
|
stepInfo: "SABnzbd Credentials",
|
|
486
|
-
footerHint:
|
|
494
|
+
footerHint: [
|
|
495
|
+
{ type: "text", value: "Enter API key from SABnzbd Config → General" },
|
|
496
|
+
{ type: "key", key: "Esc", value: "Skip" },
|
|
497
|
+
],
|
|
487
498
|
})
|
|
488
499
|
this.pageContainer = container
|
|
489
500
|
this.add(container)
|
|
@@ -615,7 +626,7 @@ export class AppConfigurator extends BoxRenderable {
|
|
|
615
626
|
const { container, content } = createPageLayout(this.cliRenderer, {
|
|
616
627
|
title: "Configure Apps",
|
|
617
628
|
stepInfo: "Complete",
|
|
618
|
-
footerHint: "Press any key to return",
|
|
629
|
+
footerHint: [{ type: "text", value: "Press any key to return" }],
|
|
619
630
|
})
|
|
620
631
|
this.add(container)
|
|
621
632
|
|
|
@@ -54,7 +54,12 @@ export class AppManager {
|
|
|
54
54
|
const { container: page, content } = createPageLayout(this.renderer as CliRenderer, {
|
|
55
55
|
title: "Manage Apps",
|
|
56
56
|
stepInfo: "Toggle apps linked to your configuration",
|
|
57
|
-
footerHint:
|
|
57
|
+
footerHint: [
|
|
58
|
+
{ type: "key", key: "←→", value: "Tab" },
|
|
59
|
+
{ type: "key", key: "Enter", value: "Toggle" },
|
|
60
|
+
{ type: "key", key: "s", value: "Save" },
|
|
61
|
+
{ type: "key", key: "q", value: "Back" },
|
|
62
|
+
],
|
|
58
63
|
})
|
|
59
64
|
this.page = page
|
|
60
65
|
|
|
@@ -47,7 +47,10 @@ export class ContainerControl {
|
|
|
47
47
|
const { container: page, content } = createPageLayout(this.renderer as CliRenderer, {
|
|
48
48
|
title: "Container Control",
|
|
49
49
|
stepInfo: finalStepInfo,
|
|
50
|
-
footerHint:
|
|
50
|
+
footerHint: [
|
|
51
|
+
{ type: "key", key: "Enter", value: "Select/Action" },
|
|
52
|
+
{ type: "key", key: "q", value: "Back" },
|
|
53
|
+
],
|
|
51
54
|
})
|
|
52
55
|
|
|
53
56
|
if (!dockerOk) {
|
|
@@ -47,7 +47,10 @@ export class FullAutoSetup extends BoxRenderable {
|
|
|
47
47
|
const { container: pageContainer, content: contentBox } = createPageLayout(cliRenderer, {
|
|
48
48
|
title: "Full Auto Setup",
|
|
49
49
|
stepInfo: "Configure all services automatically",
|
|
50
|
-
footerHint:
|
|
50
|
+
footerHint: [
|
|
51
|
+
{ type: "key", key: "Enter", value: "Start/Continue" },
|
|
52
|
+
{ type: "key", key: "Esc", value: "Back" },
|
|
53
|
+
],
|
|
51
54
|
})
|
|
52
55
|
super(cliRenderer, { width: "100%", height: "100%" })
|
|
53
56
|
this.add(pageContainer)
|
|
@@ -15,6 +15,7 @@ import { TRaSHProfileSetup } from "./TRaSHProfileSetup"
|
|
|
15
15
|
import { ProwlarrSetup } from "./ProwlarrSetup"
|
|
16
16
|
import { QBittorrentSetup } from "./QBittorrentSetup"
|
|
17
17
|
import { FullAutoSetup } from "./FullAutoSetup"
|
|
18
|
+
import { MonitorDashboard } from "./MonitorDashboard"
|
|
18
19
|
|
|
19
20
|
export class MainMenu {
|
|
20
21
|
private renderer: RenderContext
|
|
@@ -37,7 +38,7 @@ export class MainMenu {
|
|
|
37
38
|
const { container: page, content } = createPageLayout(this.renderer as CliRenderer, {
|
|
38
39
|
title: "Main Menu",
|
|
39
40
|
stepInfo: "Docker Compose Generator for *arr Ecosystem",
|
|
40
|
-
footerHint: "Enter Select
|
|
41
|
+
footerHint: [{ type: "key", key: "Enter", value: "Select" }],
|
|
41
42
|
})
|
|
42
43
|
this.page = page
|
|
43
44
|
|
|
@@ -82,7 +83,7 @@ export class MainMenu {
|
|
|
82
83
|
this.menu = new SelectRenderable(this.renderer, {
|
|
83
84
|
id: "main-menu-select",
|
|
84
85
|
width: "100%",
|
|
85
|
-
|
|
86
|
+
flexGrow: 1,
|
|
86
87
|
options: [
|
|
87
88
|
{
|
|
88
89
|
name: "📦 Manage Apps",
|
|
@@ -124,6 +125,10 @@ export class MainMenu {
|
|
|
124
125
|
name: "🚀 Full Auto Setup",
|
|
125
126
|
description: "Run all configurations (Auth, Root Folders, Prowlarr, etc.)",
|
|
126
127
|
},
|
|
128
|
+
{
|
|
129
|
+
name: "📊 Monitor Dashboard",
|
|
130
|
+
description: "Configure app health monitoring",
|
|
131
|
+
},
|
|
127
132
|
{ name: "❌ Exit", description: "Close easiarr" },
|
|
128
133
|
],
|
|
129
134
|
})
|
|
@@ -211,7 +216,18 @@ export class MainMenu {
|
|
|
211
216
|
this.container.add(autoSetup)
|
|
212
217
|
break
|
|
213
218
|
}
|
|
214
|
-
case 10:
|
|
219
|
+
case 10: {
|
|
220
|
+
// Monitor Dashboard
|
|
221
|
+
this.menu.blur()
|
|
222
|
+
this.page.visible = false
|
|
223
|
+
const monitor = new MonitorDashboard(this.renderer as CliRenderer, this.config, () => {
|
|
224
|
+
this.page.visible = true
|
|
225
|
+
this.menu.focus()
|
|
226
|
+
})
|
|
227
|
+
this.container.add(monitor)
|
|
228
|
+
break
|
|
229
|
+
}
|
|
230
|
+
case 11:
|
|
215
231
|
process.exit(0)
|
|
216
232
|
break
|
|
217
233
|
}
|