heyvm 1.0.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/LICENSE +21 -0
- package/README.md +621 -0
- package/bin/file-browser +0 -0
- package/bin/heyvm +0 -0
- package/bin/heyvm-core +0 -0
- package/bin/heyvm.js +61 -0
- package/core/README.md +51 -0
- package/core/cmd/heyvm-core/main.go +73 -0
- package/core/go.mod +25 -0
- package/core/go.sum +47 -0
- package/core/internal/auth/errors.go +29 -0
- package/core/internal/auth/password.go +187 -0
- package/core/internal/auth/provider.go +33 -0
- package/core/internal/auth/ssh_key.go +142 -0
- package/core/internal/config/config.go +111 -0
- package/core/internal/ipc/actions.go +738 -0
- package/core/internal/ipc/handler.go +281 -0
- package/core/internal/ipc/protocol.go +126 -0
- package/core/internal/sftp/errors.go +29 -0
- package/core/internal/sftp/manager.go +303 -0
- package/core/internal/sftp/types.go +30 -0
- package/core/internal/ssh/errors.go +23 -0
- package/core/internal/ssh/manager.go +226 -0
- package/core/internal/ssh/session.go +105 -0
- package/core/internal/vm/errors.go +35 -0
- package/core/internal/vm/models.go +84 -0
- package/core/internal/vm/registry.go +240 -0
- package/package.json +59 -0
- package/scripts/install.js +100 -0
- package/ui/README.md +43 -0
- package/ui/dist/App.d.ts +3 -0
- package/ui/dist/App.d.ts.map +1 -0
- package/ui/dist/App.js +142 -0
- package/ui/dist/App.js.map +1 -0
- package/ui/dist/components/ConfirmDialog.d.ts +9 -0
- package/ui/dist/components/ConfirmDialog.d.ts.map +1 -0
- package/ui/dist/components/ConfirmDialog.js +22 -0
- package/ui/dist/components/ConfirmDialog.js.map +1 -0
- package/ui/dist/components/ErrorMessage.d.ts +8 -0
- package/ui/dist/components/ErrorMessage.d.ts.map +1 -0
- package/ui/dist/components/ErrorMessage.js +10 -0
- package/ui/dist/components/ErrorMessage.js.map +1 -0
- package/ui/dist/components/Header.d.ts +8 -0
- package/ui/dist/components/Header.d.ts.map +1 -0
- package/ui/dist/components/Header.js +10 -0
- package/ui/dist/components/Header.js.map +1 -0
- package/ui/dist/components/LoadingSpinner.d.ts +7 -0
- package/ui/dist/components/LoadingSpinner.d.ts.map +1 -0
- package/ui/dist/components/LoadingSpinner.js +7 -0
- package/ui/dist/components/LoadingSpinner.js.map +1 -0
- package/ui/dist/components/StatusBar.d.ts +11 -0
- package/ui/dist/components/StatusBar.d.ts.map +1 -0
- package/ui/dist/components/StatusBar.js +11 -0
- package/ui/dist/components/StatusBar.js.map +1 -0
- package/ui/dist/core/ipc.d.ts +96 -0
- package/ui/dist/core/ipc.d.ts.map +1 -0
- package/ui/dist/core/ipc.js +310 -0
- package/ui/dist/core/ipc.js.map +1 -0
- package/ui/dist/core/types.d.ts +45 -0
- package/ui/dist/core/types.d.ts.map +1 -0
- package/ui/dist/core/types.js +3 -0
- package/ui/dist/core/types.js.map +1 -0
- package/ui/dist/hooks/useFiles.d.ts +14 -0
- package/ui/dist/hooks/useFiles.d.ts.map +1 -0
- package/ui/dist/hooks/useFiles.js +102 -0
- package/ui/dist/hooks/useFiles.js.map +1 -0
- package/ui/dist/hooks/useVM.d.ts +10 -0
- package/ui/dist/hooks/useVM.d.ts.map +1 -0
- package/ui/dist/hooks/useVM.js +54 -0
- package/ui/dist/hooks/useVM.js.map +1 -0
- package/ui/dist/hooks/useVMList.d.ts +10 -0
- package/ui/dist/hooks/useVMList.d.ts.map +1 -0
- package/ui/dist/hooks/useVMList.js +56 -0
- package/ui/dist/hooks/useVMList.js.map +1 -0
- package/ui/dist/index.d.ts +3 -0
- package/ui/dist/index.d.ts.map +1 -0
- package/ui/dist/index.js +7488 -0
- package/ui/dist/index.js.map +1 -0
- package/ui/dist/keybindings.d.ts +146 -0
- package/ui/dist/keybindings.d.ts.map +1 -0
- package/ui/dist/keybindings.js +96 -0
- package/ui/dist/keybindings.js.map +1 -0
- package/ui/dist/screens/AddVMScreen.d.ts +9 -0
- package/ui/dist/screens/AddVMScreen.d.ts.map +1 -0
- package/ui/dist/screens/AddVMScreen.js +163 -0
- package/ui/dist/screens/AddVMScreen.js.map +1 -0
- package/ui/dist/screens/VMDetailScreen.d.ts +12 -0
- package/ui/dist/screens/VMDetailScreen.d.ts.map +1 -0
- package/ui/dist/screens/VMDetailScreen.js +96 -0
- package/ui/dist/screens/VMDetailScreen.js.map +1 -0
- package/ui/dist/screens/VMListScreen.d.ts +12 -0
- package/ui/dist/screens/VMListScreen.d.ts.map +1 -0
- package/ui/dist/screens/VMListScreen.js +158 -0
- package/ui/dist/screens/VMListScreen.js.map +1 -0
- package/ui/dist/screens/tabs/FilesTab.d.ts +9 -0
- package/ui/dist/screens/tabs/FilesTab.d.ts.map +1 -0
- package/ui/dist/screens/tabs/FilesTab.js +374 -0
- package/ui/dist/screens/tabs/FilesTab.js.map +1 -0
- package/ui/dist/screens/tabs/OverviewTab.d.ts +10 -0
- package/ui/dist/screens/tabs/OverviewTab.d.ts.map +1 -0
- package/ui/dist/screens/tabs/OverviewTab.js +110 -0
- package/ui/dist/screens/tabs/OverviewTab.js.map +1 -0
- package/ui/dist/screens/tabs/TerminalTab.d.ts +9 -0
- package/ui/dist/screens/tabs/TerminalTab.d.ts.map +1 -0
- package/ui/dist/screens/tabs/TerminalTab.js +270 -0
- package/ui/dist/screens/tabs/TerminalTab.js.map +1 -0
- package/ui/dist/utils/terminalEmulator.d.ts +49 -0
- package/ui/dist/utils/terminalEmulator.d.ts.map +1 -0
- package/ui/dist/utils/terminalEmulator.js +88 -0
- package/ui/dist/utils/terminalEmulator.js.map +1 -0
- package/ui/package.json +34 -0
- package/ui/scripts/start-with-core.js +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,GAAG,MAAM,UAAU,CAAC;AAE3B,iBAAiB;AACjB,MAAM,CAAC,oBAAC,GAAG,OAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized key bindings configuration for heyvm
|
|
3
|
+
* This defines all keyboard shortcuts used throughout the application
|
|
4
|
+
*/
|
|
5
|
+
export declare const KEYBINDINGS: {
|
|
6
|
+
readonly global: {
|
|
7
|
+
readonly quit: {
|
|
8
|
+
readonly keys: readonly ["q"];
|
|
9
|
+
readonly description: "quit";
|
|
10
|
+
};
|
|
11
|
+
readonly back: {
|
|
12
|
+
readonly keys: readonly ["escape"];
|
|
13
|
+
readonly description: "back";
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
readonly vmList: {
|
|
17
|
+
readonly up: {
|
|
18
|
+
readonly keys: readonly ["k", "up"];
|
|
19
|
+
readonly description: "move up";
|
|
20
|
+
};
|
|
21
|
+
readonly down: {
|
|
22
|
+
readonly keys: readonly ["j", "down"];
|
|
23
|
+
readonly description: "move down";
|
|
24
|
+
};
|
|
25
|
+
readonly select: {
|
|
26
|
+
readonly keys: readonly ["return"];
|
|
27
|
+
readonly description: "select";
|
|
28
|
+
};
|
|
29
|
+
readonly add: {
|
|
30
|
+
readonly keys: readonly ["a"];
|
|
31
|
+
readonly description: "add VM";
|
|
32
|
+
};
|
|
33
|
+
readonly delete: {
|
|
34
|
+
readonly keys: readonly ["d"];
|
|
35
|
+
readonly description: "delete";
|
|
36
|
+
};
|
|
37
|
+
readonly refresh: {
|
|
38
|
+
readonly keys: readonly ["r"];
|
|
39
|
+
readonly description: "refresh";
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
readonly addVM: {
|
|
43
|
+
readonly nextField: {
|
|
44
|
+
readonly keys: readonly ["return"];
|
|
45
|
+
readonly description: "next field";
|
|
46
|
+
};
|
|
47
|
+
readonly prevField: {
|
|
48
|
+
readonly keys: readonly ["shift+tab"];
|
|
49
|
+
readonly description: "previous field";
|
|
50
|
+
};
|
|
51
|
+
readonly navigate: {
|
|
52
|
+
readonly keys: readonly ["up", "down"];
|
|
53
|
+
readonly description: "navigate fields";
|
|
54
|
+
};
|
|
55
|
+
readonly cancel: {
|
|
56
|
+
readonly keys: readonly ["escape"];
|
|
57
|
+
readonly description: "cancel";
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
readonly vmDetail: {
|
|
61
|
+
readonly tab1: {
|
|
62
|
+
readonly keys: readonly ["1"];
|
|
63
|
+
readonly description: "overview";
|
|
64
|
+
};
|
|
65
|
+
readonly tab2: {
|
|
66
|
+
readonly keys: readonly ["2"];
|
|
67
|
+
readonly description: "terminal";
|
|
68
|
+
};
|
|
69
|
+
readonly tab3: {
|
|
70
|
+
readonly keys: readonly ["3"];
|
|
71
|
+
readonly description: "files";
|
|
72
|
+
};
|
|
73
|
+
readonly back: {
|
|
74
|
+
readonly keys: readonly ["escape"];
|
|
75
|
+
readonly description: "back to list";
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
readonly overview: {
|
|
79
|
+
readonly connect: {
|
|
80
|
+
readonly keys: readonly ["c"];
|
|
81
|
+
readonly description: "connect";
|
|
82
|
+
};
|
|
83
|
+
readonly disconnect: {
|
|
84
|
+
readonly keys: readonly ["d"];
|
|
85
|
+
readonly description: "disconnect";
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
readonly terminal: {};
|
|
89
|
+
readonly files: {
|
|
90
|
+
readonly switchPane: {
|
|
91
|
+
readonly keys: readonly ["tab"];
|
|
92
|
+
readonly description: "switch pane";
|
|
93
|
+
};
|
|
94
|
+
readonly up: {
|
|
95
|
+
readonly keys: readonly ["k", "up"];
|
|
96
|
+
readonly description: "move up";
|
|
97
|
+
};
|
|
98
|
+
readonly down: {
|
|
99
|
+
readonly keys: readonly ["j", "down"];
|
|
100
|
+
readonly description: "move down";
|
|
101
|
+
};
|
|
102
|
+
readonly enter: {
|
|
103
|
+
readonly keys: readonly ["return"];
|
|
104
|
+
readonly description: "open directory";
|
|
105
|
+
};
|
|
106
|
+
readonly push: {
|
|
107
|
+
readonly keys: readonly ["p"];
|
|
108
|
+
readonly description: "push (local→remote)";
|
|
109
|
+
};
|
|
110
|
+
readonly get: {
|
|
111
|
+
readonly keys: readonly ["g"];
|
|
112
|
+
readonly description: "get (remote→local)";
|
|
113
|
+
};
|
|
114
|
+
readonly delete: {
|
|
115
|
+
readonly keys: readonly ["d"];
|
|
116
|
+
readonly description: "delete file";
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
readonly confirm: {
|
|
120
|
+
readonly yes: {
|
|
121
|
+
readonly keys: readonly ["y", "Y"];
|
|
122
|
+
readonly description: "confirm";
|
|
123
|
+
};
|
|
124
|
+
readonly no: {
|
|
125
|
+
readonly keys: readonly ["n", "N", "escape"];
|
|
126
|
+
readonly description: "cancel";
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Helper function to check if a key matches a binding
|
|
132
|
+
*/
|
|
133
|
+
export declare function matchesKey(input: string, key: any, binding: {
|
|
134
|
+
keys: readonly string[];
|
|
135
|
+
}): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Format key bindings for status bar display
|
|
138
|
+
*/
|
|
139
|
+
export declare function formatKeybindings(bindings: Array<{
|
|
140
|
+
keys: readonly string[];
|
|
141
|
+
description: string;
|
|
142
|
+
}>): Array<{
|
|
143
|
+
key: string;
|
|
144
|
+
description: string;
|
|
145
|
+
}>;
|
|
146
|
+
//# sourceMappingURL=keybindings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkEd,CAAC;AAEX;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE;IAAE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,OAAO,CAWjG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAKhJ"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized key bindings configuration for heyvm
|
|
3
|
+
* This defines all keyboard shortcuts used throughout the application
|
|
4
|
+
*/
|
|
5
|
+
export const KEYBINDINGS = {
|
|
6
|
+
// Global navigation
|
|
7
|
+
global: {
|
|
8
|
+
quit: { keys: ['q'], description: 'quit' },
|
|
9
|
+
back: { keys: ['escape'], description: 'back' },
|
|
10
|
+
},
|
|
11
|
+
// VM List Screen
|
|
12
|
+
vmList: {
|
|
13
|
+
up: { keys: ['k', 'up'], description: 'move up' },
|
|
14
|
+
down: { keys: ['j', 'down'], description: 'move down' },
|
|
15
|
+
select: { keys: ['return'], description: 'select' },
|
|
16
|
+
add: { keys: ['a'], description: 'add VM' },
|
|
17
|
+
delete: { keys: ['d'], description: 'delete' },
|
|
18
|
+
refresh: { keys: ['r'], description: 'refresh' },
|
|
19
|
+
},
|
|
20
|
+
// Add VM Form
|
|
21
|
+
addVM: {
|
|
22
|
+
nextField: { keys: ['return'], description: 'next field' },
|
|
23
|
+
prevField: { keys: ['shift+tab'], description: 'previous field' },
|
|
24
|
+
navigate: { keys: ['up', 'down'], description: 'navigate fields' },
|
|
25
|
+
cancel: { keys: ['escape'], description: 'cancel' },
|
|
26
|
+
},
|
|
27
|
+
// VM Detail Tabs
|
|
28
|
+
vmDetail: {
|
|
29
|
+
tab1: { keys: ['1'], description: 'overview' },
|
|
30
|
+
tab2: { keys: ['2'], description: 'terminal' },
|
|
31
|
+
tab3: { keys: ['3'], description: 'files' },
|
|
32
|
+
back: { keys: ['escape'], description: 'back to list' },
|
|
33
|
+
},
|
|
34
|
+
// Overview Tab
|
|
35
|
+
overview: {
|
|
36
|
+
connect: { keys: ['c'], description: 'connect' },
|
|
37
|
+
disconnect: { keys: ['d'], description: 'disconnect' },
|
|
38
|
+
},
|
|
39
|
+
// Terminal Tab
|
|
40
|
+
terminal: {
|
|
41
|
+
// All input is passed directly to the PTY session
|
|
42
|
+
// Special keys:
|
|
43
|
+
// - Ctrl+C: Send interrupt signal
|
|
44
|
+
// - Ctrl+D: Send EOF/exit signal
|
|
45
|
+
// - Ctrl+Z: Send suspend signal
|
|
46
|
+
// - Arrow keys: Navigate command history and cursor
|
|
47
|
+
// - Tab: Auto-complete (if supported by shell)
|
|
48
|
+
},
|
|
49
|
+
// Files Tab
|
|
50
|
+
files: {
|
|
51
|
+
switchPane: { keys: ['tab'], description: 'switch pane' },
|
|
52
|
+
up: { keys: ['k', 'up'], description: 'move up' },
|
|
53
|
+
down: { keys: ['j', 'down'], description: 'move down' },
|
|
54
|
+
enter: { keys: ['return'], description: 'open directory' },
|
|
55
|
+
push: { keys: ['p'], description: 'push (local→remote)' },
|
|
56
|
+
get: { keys: ['g'], description: 'get (remote→local)' },
|
|
57
|
+
delete: { keys: ['d'], description: 'delete file' },
|
|
58
|
+
},
|
|
59
|
+
// Confirmation Dialog
|
|
60
|
+
confirm: {
|
|
61
|
+
yes: { keys: ['y', 'Y'], description: 'confirm' },
|
|
62
|
+
no: { keys: ['n', 'N', 'escape'], description: 'cancel' },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Helper function to check if a key matches a binding
|
|
67
|
+
*/
|
|
68
|
+
export function matchesKey(input, key, binding) {
|
|
69
|
+
return binding.keys.some(k => {
|
|
70
|
+
if (k === 'return')
|
|
71
|
+
return key.return;
|
|
72
|
+
if (k === 'escape')
|
|
73
|
+
return key.escape;
|
|
74
|
+
if (k === 'tab')
|
|
75
|
+
return key.tab;
|
|
76
|
+
if (k === 'up')
|
|
77
|
+
return key.upArrow;
|
|
78
|
+
if (k === 'down')
|
|
79
|
+
return key.downArrow;
|
|
80
|
+
if (k === 'left')
|
|
81
|
+
return key.leftArrow;
|
|
82
|
+
if (k === 'right')
|
|
83
|
+
return key.rightArrow;
|
|
84
|
+
return input === k;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Format key bindings for status bar display
|
|
89
|
+
*/
|
|
90
|
+
export function formatKeybindings(bindings) {
|
|
91
|
+
return bindings.map(binding => ({
|
|
92
|
+
key: binding.keys[0], // Use first key as display
|
|
93
|
+
description: binding.description,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=keybindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { VM } from '../core/types.js';
|
|
3
|
+
interface AddVMScreenProps {
|
|
4
|
+
onCancel: () => void;
|
|
5
|
+
onSubmit: (vm: Partial<VM>, password?: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export default function AddVMScreen({ onCancel, onSubmit }: AddVMScreenProps): React.JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=AddVMScreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AddVMScreen.d.ts","sourceRoot":"","sources":["../../src/screens/AddVMScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,OAAO,KAAK,EAAE,EAAE,EAAY,MAAM,kBAAkB,CAAC;AAGrD,UAAU,gBAAgB;IACzB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAKD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,gBAAgB,qBAqN3E"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
import TextInput from 'ink-text-input';
|
|
4
|
+
import SelectInput from 'ink-select-input';
|
|
5
|
+
import { ipcClient } from '../core/ipc.js';
|
|
6
|
+
export default function AddVMScreen({ onCancel, onSubmit }) {
|
|
7
|
+
const [step, setStep] = useState('auth-type');
|
|
8
|
+
const [authType, setAuthType] = useState('key');
|
|
9
|
+
const [currentField, setCurrentField] = useState('name');
|
|
10
|
+
const [error, setError] = useState(null);
|
|
11
|
+
const [testing, setTesting] = useState(false);
|
|
12
|
+
// Form data
|
|
13
|
+
const [formData, setFormData] = useState({
|
|
14
|
+
name: '',
|
|
15
|
+
host: '',
|
|
16
|
+
port: '22',
|
|
17
|
+
username: '',
|
|
18
|
+
keyPath: '~/.ssh/id_rsa',
|
|
19
|
+
password: ''
|
|
20
|
+
});
|
|
21
|
+
// Handle auth type selection
|
|
22
|
+
const handleAuthTypeSelect = (item) => {
|
|
23
|
+
setAuthType(item.value);
|
|
24
|
+
setStep('details');
|
|
25
|
+
};
|
|
26
|
+
// Field definitions
|
|
27
|
+
const fields = authType === 'key'
|
|
28
|
+
? ['name', 'host', 'port', 'username', 'keyPath']
|
|
29
|
+
: ['name', 'host', 'port', 'username', 'password'];
|
|
30
|
+
const fieldLabels = {
|
|
31
|
+
name: 'VM Name',
|
|
32
|
+
host: 'Host (IP or hostname)',
|
|
33
|
+
port: 'Port',
|
|
34
|
+
username: 'Username',
|
|
35
|
+
keyPath: 'SSH Key Path',
|
|
36
|
+
password: 'Password'
|
|
37
|
+
};
|
|
38
|
+
const currentFieldIndex = fields.indexOf(currentField);
|
|
39
|
+
// Handle field input
|
|
40
|
+
const handleFieldChange = (value) => {
|
|
41
|
+
setFormData(prev => ({ ...prev, [currentField]: value }));
|
|
42
|
+
};
|
|
43
|
+
// Move to next field
|
|
44
|
+
const handleFieldSubmit = () => {
|
|
45
|
+
if (currentFieldIndex < fields.length - 1) {
|
|
46
|
+
setCurrentField(fields[currentFieldIndex + 1]);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
handleFormSubmit();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
// Test connection and submit
|
|
53
|
+
const handleFormSubmit = async () => {
|
|
54
|
+
try {
|
|
55
|
+
setError(null);
|
|
56
|
+
setTesting(true);
|
|
57
|
+
// Validate required fields
|
|
58
|
+
const requiredFields = fields;
|
|
59
|
+
const missingFields = requiredFields.filter(field => !formData[field]);
|
|
60
|
+
if (missingFields.length > 0) {
|
|
61
|
+
setError(`Missing required fields: ${missingFields.map(f => fieldLabels[f]).join(', ')}`);
|
|
62
|
+
setTesting(false);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Build VM object
|
|
66
|
+
const vm = {
|
|
67
|
+
name: formData.name,
|
|
68
|
+
host: formData.host,
|
|
69
|
+
port: parseInt(formData.port, 10),
|
|
70
|
+
username: formData.username,
|
|
71
|
+
auth: {
|
|
72
|
+
type: authType,
|
|
73
|
+
keyPath: authType === 'key' ? formData.keyPath : undefined,
|
|
74
|
+
rememberPassword: authType === 'password'
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
// Test connection (pass password for testing, don't store yet)
|
|
78
|
+
await ipcClient.testConnection(vm, authType === 'password' ? formData.password : undefined);
|
|
79
|
+
// Submit - pass password to parent for storage after VM is added
|
|
80
|
+
onSubmit(vm, authType === 'password' ? formData.password : undefined);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
setError(err instanceof Error ? err.message : 'Failed to add VM');
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
setTesting(false);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
// Key handlers for navigation
|
|
90
|
+
useInput((input, key) => {
|
|
91
|
+
if (key.escape) {
|
|
92
|
+
onCancel();
|
|
93
|
+
}
|
|
94
|
+
// Navigate between fields with arrow keys (when not editing)
|
|
95
|
+
if (step === 'details' && !testing) {
|
|
96
|
+
if (key.upArrow && currentFieldIndex > 0) {
|
|
97
|
+
setCurrentField(fields[currentFieldIndex - 1]);
|
|
98
|
+
}
|
|
99
|
+
if (key.downArrow && currentFieldIndex < fields.length - 1) {
|
|
100
|
+
setCurrentField(fields[currentFieldIndex + 1]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
// Auth type selection step
|
|
105
|
+
if (step === 'auth-type') {
|
|
106
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
107
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
108
|
+
React.createElement(Text, { bold: true, color: "magenta" }, "Add New VM")),
|
|
109
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
110
|
+
React.createElement(Text, null, "Select authentication method:")),
|
|
111
|
+
React.createElement(SelectInput, { items: [
|
|
112
|
+
{ label: 'SSH Key (recommended)', value: 'key' },
|
|
113
|
+
{ label: 'Password', value: 'password' }
|
|
114
|
+
], onSelect: handleAuthTypeSelect }),
|
|
115
|
+
React.createElement(Box, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 },
|
|
116
|
+
React.createElement(Text, { dimColor: true },
|
|
117
|
+
React.createElement(Text, { bold: true }, "\u2191/\u2193"),
|
|
118
|
+
" navigate \u2022 ",
|
|
119
|
+
React.createElement(Text, { bold: true }, "Enter"),
|
|
120
|
+
" select \u2022 ",
|
|
121
|
+
React.createElement(Text, { bold: true }, "Esc"),
|
|
122
|
+
" cancel"))));
|
|
123
|
+
}
|
|
124
|
+
// Details form step
|
|
125
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
126
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
127
|
+
React.createElement(Text, { bold: true, color: "magenta" }, "Add New VM")),
|
|
128
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
129
|
+
React.createElement(Text, { dimColor: true },
|
|
130
|
+
"Auth: ",
|
|
131
|
+
authType === 'key' ? 'SSH Key' : 'Password')),
|
|
132
|
+
error && (React.createElement(Box, { marginBottom: 1 },
|
|
133
|
+
React.createElement(Text, { color: "red" },
|
|
134
|
+
"Error: ",
|
|
135
|
+
error))),
|
|
136
|
+
testing && (React.createElement(Box, { marginBottom: 1 },
|
|
137
|
+
React.createElement(Text, { color: "yellow" }, "Testing connection..."))),
|
|
138
|
+
!testing && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, fields.map((field, index) => {
|
|
139
|
+
const isActive = field === currentField;
|
|
140
|
+
const value = formData[field];
|
|
141
|
+
const label = fieldLabels[field];
|
|
142
|
+
return (React.createElement(Box, { key: field, marginBottom: 1, flexDirection: "column" },
|
|
143
|
+
React.createElement(Text, { bold: isActive },
|
|
144
|
+
isActive ? '>' : ' ',
|
|
145
|
+
" ",
|
|
146
|
+
label,
|
|
147
|
+
":"),
|
|
148
|
+
isActive ? (React.createElement(Box, { marginLeft: 2 },
|
|
149
|
+
React.createElement(TextInput, { value: value, onChange: handleFieldChange, onSubmit: handleFieldSubmit, placeholder: label, mask: field === 'password' ? '*' : undefined }))) : (React.createElement(Box, { marginLeft: 2 },
|
|
150
|
+
React.createElement(Text, { dimColor: true }, value || React.createElement(Text, { italic: true }, "(empty)"))))));
|
|
151
|
+
}))),
|
|
152
|
+
React.createElement(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1 },
|
|
153
|
+
React.createElement(Text, { dimColor: true },
|
|
154
|
+
React.createElement(Text, { bold: true }, "Enter"),
|
|
155
|
+
" next field \u2022 ",
|
|
156
|
+
' ',
|
|
157
|
+
React.createElement(Text, { bold: true }, "\u2191/\u2193"),
|
|
158
|
+
" navigate \u2022 ",
|
|
159
|
+
' ',
|
|
160
|
+
React.createElement(Text, { bold: true }, "Esc"),
|
|
161
|
+
" cancel"))));
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=AddVMScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AddVMScreen.js","sourceRoot":"","sources":["../../src/screens/AddVMScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,WAAW,MAAM,kBAAkB,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAU3C,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAoB;IAC3E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAW,WAAW,CAAC,CAAC;IACxD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAW,KAAK,CAAC,CAAC;IAC1D,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAY,MAAM,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,YAAY;IACZ,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC;QACxC,IAAI,EAAE,EAAE;QACR,IAAI,EAAE,EAAE;QACR,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,eAAe;QACxB,QAAQ,EAAE,EAAE;KACZ,CAAC,CAAC;IAEH,6BAA6B;IAC7B,MAAM,oBAAoB,GAAG,CAAC,IAAyB,EAAE,EAAE;QAC1D,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,CAAC,SAAS,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,oBAAoB;IACpB,MAAM,MAAM,GAAgB,QAAQ,KAAK,KAAK;QAC7C,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC;QACjD,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAEpD,MAAM,WAAW,GAA8B;QAC9C,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,UAAU;QACpB,OAAO,EAAE,cAAc;QACvB,QAAQ,EAAE,UAAU;KACpB,CAAC;IAEF,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAEvD,qBAAqB;IACrB,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAE,EAAE;QAC3C,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,qBAAqB;IACrB,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC9B,IAAI,iBAAiB,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,eAAe,CAAC,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACP,gBAAgB,EAAE,CAAC;QACpB,CAAC;IACF,CAAC,CAAC;IAEF,6BAA6B;IAC7B,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;QACnC,IAAI,CAAC;YACJ,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,CAAC;YAEjB,2BAA2B;YAC3B,MAAM,cAAc,GAAG,MAAM,CAAC;YAC9B,MAAM,aAAa,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAEvE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,QAAQ,CAAC,4BAA4B,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1F,UAAU,CAAC,KAAK,CAAC,CAAC;gBAClB,OAAO;YACR,CAAC;YAED,kBAAkB;YAClB,MAAM,EAAE,GAAgB;gBACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;gBACjC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,IAAI,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;oBAC1D,gBAAgB,EAAE,QAAQ,KAAK,UAAU;iBACzC;aACD,CAAC;YAEF,+DAA+D;YAC/D,MAAM,SAAS,CAAC,cAAc,CAAC,EAAE,EAAE,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAE5F,iEAAiE;YACjE,QAAQ,CAAC,EAAE,EAAE,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QACnE,CAAC;gBAAS,CAAC;YACV,UAAU,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACF,CAAC,CAAC;IAEF,8BAA8B;IAC9B,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAChB,QAAQ,EAAE,CAAC;QACZ,CAAC;QAED,6DAA6D;QAC7D,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,OAAO,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;gBAC1C,eAAe,CAAC,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC;YAChD,CAAC;YACD,IAAI,GAAG,CAAC,SAAS,IAAI,iBAAiB,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5D,eAAe,CAAC,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC;YAChD,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QAC1B,OAAO,CACN,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC;YACrC,oBAAC,GAAG,IAAC,YAAY,EAAE,CAAC;gBACnB,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,iBAAkB,CACvC;YAEN,oBAAC,GAAG,IAAC,YAAY,EAAE,CAAC;gBACnB,oBAAC,IAAI,wCAAqC,CACrC;YAEN,oBAAC,WAAW,IACX,KAAK,EAAE;oBACN,EAAE,KAAK,EAAE,uBAAuB,EAAE,KAAK,EAAE,KAAiB,EAAE;oBAC5D,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAsB,EAAE;iBACpD,EACD,QAAQ,EAAE,oBAAoB,GAC7B;YAEF,oBAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,WAAW,EAAC,QAAQ,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC;gBACrE,oBAAC,IAAI,IAAC,QAAQ;oBACb,oBAAC,IAAI,IAAC,IAAI,0BAAW;;oBAAY,oBAAC,IAAI,IAAC,IAAI,kBAAa;;oBAAU,oBAAC,IAAI,IAAC,IAAI,gBAAW;8BACjF,CACF,CACD,CACN,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,OAAO,CACN,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC;QACrC,oBAAC,GAAG,IAAC,YAAY,EAAE,CAAC;YACnB,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,iBAAkB,CACvC;QAEN,oBAAC,GAAG,IAAC,YAAY,EAAE,CAAC;YACnB,oBAAC,IAAI,IAAC,QAAQ;;gBACN,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAC5C,CACF;QAGL,KAAK,IAAI,CACT,oBAAC,GAAG,IAAC,YAAY,EAAE,CAAC;YACnB,oBAAC,IAAI,IAAC,KAAK,EAAC,KAAK;;gBAAS,KAAK,CAAQ,CAClC,CACN;QAGA,OAAO,IAAI,CACX,oBAAC,GAAG,IAAC,YAAY,EAAE,CAAC;YACnB,oBAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,4BAA6B,CAC5C,CACN;QAGA,CAAC,OAAO,IAAI,CACZ,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,IACzC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAC5B,MAAM,QAAQ,GAAG,KAAK,KAAK,YAAY,CAAC;YACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC9B,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YAEjC,OAAO,CACN,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ;gBACvD,oBAAC,IAAI,IAAC,IAAI,EAAE,QAAQ;oBAClB,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;;oBAAG,KAAK;wBACvB;gBACN,QAAQ,CAAC,CAAC,CAAC,CACX,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;oBACjB,oBAAC,SAAS,IACT,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,iBAAiB,EAC3B,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,KAAK,EAClB,IAAI,EAAE,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,GAC3C,CACG,CACN,CAAC,CAAC,CAAC,CACH,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;oBACjB,oBAAC,IAAI,IAAC,QAAQ,UACZ,KAAK,IAAI,oBAAC,IAAI,IAAC,MAAM,oBAAe,CAC/B,CACF,CACN,CACI,CACN,CAAC;QACH,CAAC,CAAC,CACG,CACN;QAGD,oBAAC,GAAG,IAAC,WAAW,EAAC,QAAQ,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC;YACvD,oBAAC,IAAI,IAAC,QAAQ;gBACb,oBAAC,IAAI,IAAC,IAAI,kBAAa;;gBAAe,GAAG;gBACzC,oBAAC,IAAI,IAAC,IAAI,0BAAW;;gBAAa,GAAG;gBACrC,oBAAC,IAAI,IAAC,IAAI,gBAAW;0BACf,CACF,CACD,CACN,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { VM, Tab } from '../core/types.js';
|
|
3
|
+
interface VMDetailScreenProps {
|
|
4
|
+
vm: VM;
|
|
5
|
+
activeTab: Tab;
|
|
6
|
+
onTabChange: (tab: Tab) => void;
|
|
7
|
+
isActive: boolean;
|
|
8
|
+
onVMUpdated?: () => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
declare const _default: React.NamedExoticComponent<VMDetailScreenProps>;
|
|
11
|
+
export default _default;
|
|
12
|
+
//# sourceMappingURL=VMDetailScreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VMDetailScreen.d.ts","sourceRoot":"","sources":["../../src/screens/VMDetailScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAKhD,UAAU,mBAAmB;IAC5B,EAAE,EAAE,EAAE,CAAC;IACP,SAAS,EAAE,GAAG,CAAC;IACf,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;;AAED,wBAiGG"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import OverviewTab from './tabs/OverviewTab.js';
|
|
4
|
+
import TerminalTab from './tabs/TerminalTab.js';
|
|
5
|
+
import FilesTab from './tabs/FilesTab.js';
|
|
6
|
+
export default React.memo(function VMDetailScreen({ vm, activeTab, onTabChange, isActive, onVMUpdated }) {
|
|
7
|
+
// Tab state is now controlled by parent (no local state or key handlers)
|
|
8
|
+
const getStatusColor = () => {
|
|
9
|
+
if (vm.status === 'connected')
|
|
10
|
+
return 'green';
|
|
11
|
+
if (vm.status === 'connecting')
|
|
12
|
+
return 'yellow';
|
|
13
|
+
return 'gray';
|
|
14
|
+
};
|
|
15
|
+
const getStatusText = () => {
|
|
16
|
+
if (vm.status === 'connected')
|
|
17
|
+
return 'CONNECTED';
|
|
18
|
+
if (vm.status === 'connecting')
|
|
19
|
+
return 'CONNECTING';
|
|
20
|
+
return 'DISCONNECTED';
|
|
21
|
+
};
|
|
22
|
+
const getContextHelp = () => {
|
|
23
|
+
switch (activeTab) {
|
|
24
|
+
case 'overview':
|
|
25
|
+
return (React.createElement(Text, { dimColor: true },
|
|
26
|
+
React.createElement(Text, { bold: true }, "c"),
|
|
27
|
+
" connect \u2022 ",
|
|
28
|
+
React.createElement(Text, { bold: true }, "d"),
|
|
29
|
+
" disconnect \u2022 ",
|
|
30
|
+
React.createElement(Text, { bold: true }, "1/2/3"),
|
|
31
|
+
" tabs \u2022 ",
|
|
32
|
+
React.createElement(Text, { bold: true }, "Esc"),
|
|
33
|
+
" back"));
|
|
34
|
+
case 'terminal':
|
|
35
|
+
return (React.createElement(Text, { dimColor: true },
|
|
36
|
+
React.createElement(Text, { bold: true }, "PgUp/PgDn"),
|
|
37
|
+
" or ",
|
|
38
|
+
React.createElement(Text, { bold: true }, "Shift+\u2191\u2193"),
|
|
39
|
+
" scroll \u2022 ",
|
|
40
|
+
React.createElement(Text, { bold: true }, "Ctrl+O"),
|
|
41
|
+
" overview \u2022 ",
|
|
42
|
+
React.createElement(Text, { bold: true }, "Esc"),
|
|
43
|
+
" back"));
|
|
44
|
+
case 'files':
|
|
45
|
+
return (React.createElement(Text, { dimColor: true },
|
|
46
|
+
React.createElement(Text, { bold: true }, "j/k"),
|
|
47
|
+
" navigate \u2022 ",
|
|
48
|
+
React.createElement(Text, { bold: true }, "Tab"),
|
|
49
|
+
" pane \u2022 ",
|
|
50
|
+
React.createElement(Text, { bold: true }, "p"),
|
|
51
|
+
" push \u2022 ",
|
|
52
|
+
React.createElement(Text, { bold: true }, "g"),
|
|
53
|
+
" get \u2022 ",
|
|
54
|
+
React.createElement(Text, { bold: true }, "/"),
|
|
55
|
+
" search \u2022 ",
|
|
56
|
+
React.createElement(Text, { bold: true }, "Esc"),
|
|
57
|
+
" back"));
|
|
58
|
+
default:
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1, height: "100%" },
|
|
63
|
+
React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
64
|
+
React.createElement(Box, null,
|
|
65
|
+
React.createElement(Text, { bold: true, color: "cyan" }, vm.status === 'connected' ? '● ' : vm.status === 'connecting' ? '◐ ' : '○ '),
|
|
66
|
+
React.createElement(Text, { bold: true }, vm.name),
|
|
67
|
+
React.createElement(Text, null, ' '),
|
|
68
|
+
React.createElement(Text, { bold: true, color: getStatusColor() }, getStatusText())),
|
|
69
|
+
React.createElement(Box, null,
|
|
70
|
+
React.createElement(Text, { dimColor: true },
|
|
71
|
+
" ",
|
|
72
|
+
vm.username,
|
|
73
|
+
"@",
|
|
74
|
+
vm.host)),
|
|
75
|
+
React.createElement(Box, { marginTop: 1 },
|
|
76
|
+
React.createElement(Text, { dimColor: true }, '─'.repeat(60)))),
|
|
77
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
78
|
+
React.createElement(Text, null,
|
|
79
|
+
React.createElement(Text, { bold: activeTab === 'overview', color: activeTab === 'overview' ? 'cyan' : 'gray' }, "Overview"),
|
|
80
|
+
React.createElement(Text, { dimColor: true },
|
|
81
|
+
" ",
|
|
82
|
+
activeTab === 'overview' ? '▶' : '|',
|
|
83
|
+
" "),
|
|
84
|
+
React.createElement(Text, { bold: activeTab === 'terminal', color: activeTab === 'terminal' ? 'cyan' : 'gray' }, "Terminal"),
|
|
85
|
+
React.createElement(Text, { dimColor: true },
|
|
86
|
+
" ",
|
|
87
|
+
activeTab === 'terminal' ? '▶' : '|',
|
|
88
|
+
" "),
|
|
89
|
+
React.createElement(Text, { bold: activeTab === 'files', color: activeTab === 'files' ? 'cyan' : 'gray' }, "Files"))),
|
|
90
|
+
React.createElement(Box, { flexGrow: 1, flexDirection: "column" },
|
|
91
|
+
activeTab === 'overview' && React.createElement(OverviewTab, { vm: vm, isActive: isActive, onVMUpdated: onVMUpdated }),
|
|
92
|
+
activeTab === 'terminal' && React.createElement(TerminalTab, { vm: vm, isActive: isActive }),
|
|
93
|
+
activeTab === 'files' && React.createElement(FilesTab, { vm: vm, isActive: isActive })),
|
|
94
|
+
React.createElement(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, getContextHelp())));
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=VMDetailScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VMDetailScreen.js","sourceRoot":"","sources":["../../src/screens/VMDetailScreen.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { VM } from '../core/types.js';
|
|
3
|
+
interface VMListScreenProps {
|
|
4
|
+
selectedVM: VM | null;
|
|
5
|
+
onSelectVM: (vm: VM) => void;
|
|
6
|
+
isActive: boolean;
|
|
7
|
+
onVMDeleted?: () => void;
|
|
8
|
+
vmListVersion?: number;
|
|
9
|
+
}
|
|
10
|
+
export default function VMListScreen({ selectedVM, onSelectVM, isActive, onVMDeleted, vmListVersion }: VMListScreenProps): React.JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=VMListScreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VMListScreen.d.ts","sourceRoot":"","sources":["../../src/screens/VMListScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAG3C,UAAU,iBAAiB;IAC1B,UAAU,EAAE,EAAE,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,iBAAiB,qBAsLvH"}
|