@runloop/rl-cli 1.2.0 → 1.4.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/README.md +29 -8
- package/dist/commands/blueprint/from-dockerfile.js +182 -0
- package/dist/commands/blueprint/list.js +97 -28
- package/dist/commands/blueprint/prune.js +7 -19
- package/dist/commands/devbox/create.js +3 -0
- package/dist/commands/devbox/list.js +44 -65
- package/dist/commands/menu.js +2 -1
- package/dist/commands/network-policy/create.js +27 -0
- package/dist/commands/network-policy/delete.js +21 -0
- package/dist/commands/network-policy/get.js +15 -0
- package/dist/commands/network-policy/list.js +494 -0
- package/dist/commands/object/list.js +516 -24
- package/dist/commands/snapshot/list.js +90 -29
- package/dist/components/Banner.js +109 -8
- package/dist/components/ConfirmationPrompt.js +45 -0
- package/dist/components/DevboxActionsMenu.js +42 -6
- package/dist/components/DevboxCard.js +1 -1
- package/dist/components/DevboxCreatePage.js +174 -168
- package/dist/components/DevboxDetailPage.js +218 -272
- package/dist/components/LogsViewer.js +8 -1
- package/dist/components/MainMenu.js +35 -4
- package/dist/components/NavigationTips.js +24 -0
- package/dist/components/NetworkPolicyCreatePage.js +263 -0
- package/dist/components/OperationsMenu.js +9 -1
- package/dist/components/ResourceActionsMenu.js +5 -1
- package/dist/components/ResourceDetailPage.js +204 -0
- package/dist/components/ResourceListView.js +19 -2
- package/dist/components/StatusBadge.js +2 -2
- package/dist/components/Table.js +6 -8
- package/dist/components/form/FormActionButton.js +7 -0
- package/dist/components/form/FormField.js +7 -0
- package/dist/components/form/FormListManager.js +112 -0
- package/dist/components/form/FormSelect.js +34 -0
- package/dist/components/form/FormTextInput.js +8 -0
- package/dist/components/form/index.js +8 -0
- package/dist/hooks/useViewportHeight.js +38 -20
- package/dist/router/Router.js +23 -1
- package/dist/screens/BlueprintDetailScreen.js +355 -0
- package/dist/screens/DevboxDetailScreen.js +4 -4
- package/dist/screens/MenuScreen.js +6 -0
- package/dist/screens/NetworkPolicyCreateScreen.js +7 -0
- package/dist/screens/NetworkPolicyDetailScreen.js +247 -0
- package/dist/screens/NetworkPolicyListScreen.js +7 -0
- package/dist/screens/ObjectDetailScreen.js +377 -0
- package/dist/screens/ObjectListScreen.js +7 -0
- package/dist/screens/SnapshotDetailScreen.js +208 -0
- package/dist/services/blueprintService.js +30 -11
- package/dist/services/networkPolicyService.js +108 -0
- package/dist/services/objectService.js +101 -0
- package/dist/services/snapshotService.js +39 -3
- package/dist/store/blueprintStore.js +4 -10
- package/dist/store/index.js +1 -0
- package/dist/store/networkPolicyStore.js +83 -0
- package/dist/store/objectStore.js +92 -0
- package/dist/store/snapshotStore.js +4 -8
- package/dist/utils/commands.js +65 -0
- package/package.json +2 -2
|
@@ -8,9 +8,21 @@ import { SpinnerComponent } from "./Spinner.js";
|
|
|
8
8
|
import { ErrorMessage } from "./ErrorMessage.js";
|
|
9
9
|
import { SuccessMessage } from "./SuccessMessage.js";
|
|
10
10
|
import { Breadcrumb } from "./Breadcrumb.js";
|
|
11
|
+
import { NavigationTips } from "./NavigationTips.js";
|
|
11
12
|
import { MetadataDisplay } from "./MetadataDisplay.js";
|
|
13
|
+
import { FormTextInput, FormSelect, FormActionButton, useFormSelectNavigation, } from "./form/index.js";
|
|
12
14
|
import { colors } from "../utils/theme.js";
|
|
13
15
|
import { useExitOnCtrlC } from "../hooks/useExitOnCtrlC.js";
|
|
16
|
+
const architectures = ["arm64", "x86_64"];
|
|
17
|
+
const resourceSizes = [
|
|
18
|
+
"X_SMALL",
|
|
19
|
+
"SMALL",
|
|
20
|
+
"MEDIUM",
|
|
21
|
+
"LARGE",
|
|
22
|
+
"X_LARGE",
|
|
23
|
+
"XX_LARGE",
|
|
24
|
+
"CUSTOM_SIZE",
|
|
25
|
+
];
|
|
14
26
|
export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initialSnapshotId, }) => {
|
|
15
27
|
const [currentField, setCurrentField] = React.useState("create");
|
|
16
28
|
const [formData, setFormData] = React.useState({
|
|
@@ -24,53 +36,80 @@ export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initial
|
|
|
24
36
|
metadata: {},
|
|
25
37
|
blueprint_id: initialBlueprintId || "",
|
|
26
38
|
snapshot_id: initialSnapshotId || "",
|
|
39
|
+
network_policy_id: "",
|
|
27
40
|
});
|
|
28
41
|
const [metadataKey, setMetadataKey] = React.useState("");
|
|
29
42
|
const [metadataValue, setMetadataValue] = React.useState("");
|
|
30
43
|
const [inMetadataSection, setInMetadataSection] = React.useState(false);
|
|
31
44
|
const [metadataInputMode, setMetadataInputMode] = React.useState(null);
|
|
32
|
-
const [selectedMetadataIndex, setSelectedMetadataIndex] = React.useState(
|
|
45
|
+
const [selectedMetadataIndex, setSelectedMetadataIndex] = React.useState(0);
|
|
33
46
|
const [creating, setCreating] = React.useState(false);
|
|
34
47
|
const [result, setResult] = React.useState(null);
|
|
35
48
|
const [error, setError] = React.useState(null);
|
|
36
49
|
const baseFields = [
|
|
37
50
|
{ key: "create", label: "Devbox Create", type: "action" },
|
|
38
|
-
{ key: "name", label: "Name", type: "text" },
|
|
51
|
+
{ key: "name", label: "Name", type: "text", placeholder: "my-devbox" },
|
|
39
52
|
{ key: "architecture", label: "Architecture", type: "select" },
|
|
40
53
|
{ key: "resource_size", label: "Resource Size", type: "select" },
|
|
41
54
|
];
|
|
42
55
|
// Add custom resource fields if CUSTOM_SIZE is selected
|
|
43
56
|
const customFields = formData.resource_size === "CUSTOM_SIZE"
|
|
44
57
|
? [
|
|
45
|
-
{
|
|
58
|
+
{
|
|
59
|
+
key: "custom_cpu",
|
|
60
|
+
label: "CPU Cores (2-16, even)",
|
|
61
|
+
type: "text",
|
|
62
|
+
placeholder: "4",
|
|
63
|
+
},
|
|
46
64
|
{
|
|
47
65
|
key: "custom_memory",
|
|
48
66
|
label: "Memory GB (2-64, even)",
|
|
49
67
|
type: "text",
|
|
68
|
+
placeholder: "8",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: "custom_disk",
|
|
72
|
+
label: "Disk GB (2-64, even)",
|
|
73
|
+
type: "text",
|
|
74
|
+
placeholder: "16",
|
|
50
75
|
},
|
|
51
|
-
{ key: "custom_disk", label: "Disk GB (2-64, even)", type: "text" },
|
|
52
76
|
]
|
|
53
77
|
: [];
|
|
54
78
|
const remainingFields = [
|
|
55
|
-
{
|
|
56
|
-
|
|
57
|
-
|
|
79
|
+
{
|
|
80
|
+
key: "keep_alive",
|
|
81
|
+
label: "Keep Alive (seconds)",
|
|
82
|
+
type: "text",
|
|
83
|
+
placeholder: "3600",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: "blueprint_id",
|
|
87
|
+
label: "Blueprint ID (optional)",
|
|
88
|
+
type: "text",
|
|
89
|
+
placeholder: "bpt_xxx",
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
key: "snapshot_id",
|
|
93
|
+
label: "Snapshot ID (optional)",
|
|
94
|
+
type: "text",
|
|
95
|
+
placeholder: "snp_xxx",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: "network_policy_id",
|
|
99
|
+
label: "Network Policy ID (optional)",
|
|
100
|
+
type: "text",
|
|
101
|
+
placeholder: "np_xxx",
|
|
102
|
+
},
|
|
58
103
|
{ key: "metadata", label: "Metadata (optional)", type: "metadata" },
|
|
59
104
|
];
|
|
60
105
|
const fields = [...baseFields, ...customFields, ...remainingFields];
|
|
61
|
-
const architectures = ["arm64", "x86_64"];
|
|
62
|
-
const resourceSizes = [
|
|
63
|
-
"X_SMALL",
|
|
64
|
-
"SMALL",
|
|
65
|
-
"MEDIUM",
|
|
66
|
-
"LARGE",
|
|
67
|
-
"X_LARGE",
|
|
68
|
-
"XX_LARGE",
|
|
69
|
-
"CUSTOM_SIZE",
|
|
70
|
-
];
|
|
71
106
|
const currentFieldIndex = fields.findIndex((f) => f.key === currentField);
|
|
72
107
|
// Handle Ctrl+C to exit
|
|
73
108
|
useExitOnCtrlC();
|
|
109
|
+
// Select navigation handlers using shared hook
|
|
110
|
+
const handleArchitectureNav = useFormSelectNavigation(formData.architecture, architectures, (value) => setFormData({ ...formData, architecture: value }), currentField === "architecture");
|
|
111
|
+
const handleResourceSizeNav = useFormSelectNavigation(formData.resource_size || "SMALL", resourceSizes, (value) => setFormData({ ...formData, resource_size: value }), currentField === "resource_size");
|
|
112
|
+
// Main form input handler - active when not in metadata section
|
|
74
113
|
useInput((input, key) => {
|
|
75
114
|
// Handle result screen
|
|
76
115
|
if (result) {
|
|
@@ -78,7 +117,9 @@ export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initial
|
|
|
78
117
|
if (onCreate) {
|
|
79
118
|
onCreate(result);
|
|
80
119
|
}
|
|
81
|
-
|
|
120
|
+
else {
|
|
121
|
+
onBack();
|
|
122
|
+
}
|
|
82
123
|
}
|
|
83
124
|
return;
|
|
84
125
|
}
|
|
@@ -103,161 +144,127 @@ export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initial
|
|
|
103
144
|
onBack();
|
|
104
145
|
return;
|
|
105
146
|
}
|
|
106
|
-
// Submit form
|
|
147
|
+
// Submit form with Ctrl+S
|
|
107
148
|
if (input === "s" && key.ctrl) {
|
|
108
149
|
handleCreate();
|
|
109
150
|
return;
|
|
110
151
|
}
|
|
111
|
-
//
|
|
112
|
-
if (currentField === "
|
|
152
|
+
// Enter key on metadata field to enter metadata section
|
|
153
|
+
if (currentField === "metadata" && key.return) {
|
|
154
|
+
setInMetadataSection(true);
|
|
155
|
+
setSelectedMetadataIndex(0);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Handle Enter on any field to submit
|
|
159
|
+
if (key.return) {
|
|
113
160
|
handleCreate();
|
|
114
161
|
return;
|
|
115
162
|
}
|
|
116
|
-
// Handle
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
else if (key.escape) {
|
|
144
|
-
// Cancel input
|
|
145
|
-
setMetadataKey("");
|
|
146
|
-
setMetadataValue("");
|
|
147
|
-
setMetadataInputMode(null);
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
else if (key.tab) {
|
|
151
|
-
// Tab between key and value
|
|
152
|
-
setMetadataInputMode(metadataInputMode === "key" ? "value" : "key");
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
return; // Don't process other keys while in input mode
|
|
156
|
-
}
|
|
157
|
-
// Navigation mode
|
|
158
|
-
if (key.upArrow && selectedMetadataIndex > 0) {
|
|
159
|
-
setSelectedMetadataIndex(selectedMetadataIndex - 1);
|
|
160
|
-
}
|
|
161
|
-
else if (key.downArrow && selectedMetadataIndex < maxIndex) {
|
|
162
|
-
setSelectedMetadataIndex(selectedMetadataIndex + 1);
|
|
163
|
-
}
|
|
164
|
-
else if (key.return) {
|
|
165
|
-
if (selectedMetadataIndex === 0) {
|
|
166
|
-
// Add new
|
|
167
|
-
setMetadataKey("");
|
|
168
|
-
setMetadataValue("");
|
|
169
|
-
setMetadataInputMode("key");
|
|
170
|
-
}
|
|
171
|
-
else if (selectedMetadataIndex === maxIndex) {
|
|
172
|
-
// Done - exit metadata section
|
|
173
|
-
setInMetadataSection(false);
|
|
174
|
-
setSelectedMetadataIndex(0);
|
|
175
|
-
setMetadataKey("");
|
|
176
|
-
setMetadataValue("");
|
|
177
|
-
setMetadataInputMode(null);
|
|
178
|
-
}
|
|
179
|
-
else if (selectedMetadataIndex >= 1 &&
|
|
180
|
-
selectedMetadataIndex <= metadataKeys.length) {
|
|
181
|
-
// Edit existing (selectedMetadataIndex - 1 gives array index)
|
|
182
|
-
const keyToEdit = metadataKeys[selectedMetadataIndex - 1];
|
|
183
|
-
setMetadataKey(keyToEdit || "");
|
|
184
|
-
setMetadataValue(formData.metadata[keyToEdit] || "");
|
|
185
|
-
// Remove old entry
|
|
186
|
-
const newMetadata = { ...formData.metadata };
|
|
187
|
-
delete newMetadata[keyToEdit];
|
|
188
|
-
setFormData({ ...formData, metadata: newMetadata });
|
|
189
|
-
setMetadataInputMode("key");
|
|
190
|
-
}
|
|
163
|
+
// Handle select field navigation using shared hooks
|
|
164
|
+
if (handleArchitectureNav(input, key))
|
|
165
|
+
return;
|
|
166
|
+
if (handleResourceSizeNav(input, key))
|
|
167
|
+
return;
|
|
168
|
+
// Navigation (up/down arrows and tab/shift+tab)
|
|
169
|
+
if ((key.upArrow || (key.tab && key.shift)) && currentFieldIndex > 0) {
|
|
170
|
+
setCurrentField(fields[currentFieldIndex - 1].key);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if ((key.downArrow || (key.tab && !key.shift)) &&
|
|
174
|
+
currentFieldIndex < fields.length - 1) {
|
|
175
|
+
setCurrentField(fields[currentFieldIndex + 1].key);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
}, { isActive: !inMetadataSection });
|
|
179
|
+
// Metadata section input handler - active when in metadata section
|
|
180
|
+
useInput((input, key) => {
|
|
181
|
+
const metadataKeys = Object.keys(formData.metadata);
|
|
182
|
+
const maxIndex = metadataKeys.length + 1;
|
|
183
|
+
// Handle input mode (typing key or value)
|
|
184
|
+
if (metadataInputMode) {
|
|
185
|
+
if (metadataInputMode === "key" && key.return && metadataKey.trim()) {
|
|
186
|
+
setMetadataInputMode("value");
|
|
187
|
+
return;
|
|
191
188
|
}
|
|
192
|
-
else if (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const newLength = Object.keys(newMetadata).length;
|
|
202
|
-
if (selectedMetadataIndex > newLength) {
|
|
203
|
-
setSelectedMetadataIndex(Math.max(0, newLength));
|
|
189
|
+
else if (metadataInputMode === "value" && key.return) {
|
|
190
|
+
if (metadataKey.trim() && metadataValue.trim()) {
|
|
191
|
+
setFormData({
|
|
192
|
+
...formData,
|
|
193
|
+
metadata: {
|
|
194
|
+
...formData.metadata,
|
|
195
|
+
[metadataKey.trim()]: metadataValue.trim(),
|
|
196
|
+
},
|
|
197
|
+
});
|
|
204
198
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
setInMetadataSection(false);
|
|
199
|
+
setMetadataKey("");
|
|
200
|
+
setMetadataValue("");
|
|
201
|
+
setMetadataInputMode(null);
|
|
209
202
|
setSelectedMetadataIndex(0);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
else if (key.escape) {
|
|
210
206
|
setMetadataKey("");
|
|
211
207
|
setMetadataValue("");
|
|
212
208
|
setMetadataInputMode(null);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
else if (key.tab) {
|
|
212
|
+
setMetadataInputMode(metadataInputMode === "key" ? "value" : "key");
|
|
213
|
+
return;
|
|
213
214
|
}
|
|
214
215
|
return;
|
|
215
216
|
}
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (key.upArrow && currentFieldIndex > 0) {
|
|
220
|
-
setCurrentField(fields[currentFieldIndex - 1].key);
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
if (key.downArrow && currentFieldIndex < fields.length - 1) {
|
|
224
|
-
setCurrentField(fields[currentFieldIndex + 1].key);
|
|
225
|
-
return;
|
|
217
|
+
// Navigation mode in metadata section
|
|
218
|
+
if (key.upArrow && selectedMetadataIndex > 0) {
|
|
219
|
+
setSelectedMetadataIndex(selectedMetadataIndex - 1);
|
|
226
220
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
setInMetadataSection(true);
|
|
230
|
-
setSelectedMetadataIndex(0); // Start at "add new" row
|
|
231
|
-
return;
|
|
221
|
+
else if (key.downArrow && selectedMetadataIndex < maxIndex) {
|
|
222
|
+
setSelectedMetadataIndex(selectedMetadataIndex + 1);
|
|
232
223
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
? Math.max(0, currentIndex - 1)
|
|
239
|
-
: Math.min(architectures.length - 1, currentIndex + 1);
|
|
240
|
-
setFormData({
|
|
241
|
-
...formData,
|
|
242
|
-
architecture: architectures[newIndex],
|
|
243
|
-
});
|
|
224
|
+
else if (key.return) {
|
|
225
|
+
if (selectedMetadataIndex === 0) {
|
|
226
|
+
setMetadataKey("");
|
|
227
|
+
setMetadataValue("");
|
|
228
|
+
setMetadataInputMode("key");
|
|
244
229
|
}
|
|
245
|
-
else if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
230
|
+
else if (selectedMetadataIndex === maxIndex) {
|
|
231
|
+
setInMetadataSection(false);
|
|
232
|
+
setSelectedMetadataIndex(0);
|
|
233
|
+
setMetadataKey("");
|
|
234
|
+
setMetadataValue("");
|
|
235
|
+
setMetadataInputMode(null);
|
|
236
|
+
}
|
|
237
|
+
else if (selectedMetadataIndex >= 1 &&
|
|
238
|
+
selectedMetadataIndex <= metadataKeys.length) {
|
|
239
|
+
const keyToEdit = metadataKeys[selectedMetadataIndex - 1];
|
|
240
|
+
setMetadataKey(keyToEdit || "");
|
|
241
|
+
setMetadataValue(formData.metadata[keyToEdit] || "");
|
|
242
|
+
const newMetadata = { ...formData.metadata };
|
|
243
|
+
delete newMetadata[keyToEdit];
|
|
244
|
+
setFormData({ ...formData, metadata: newMetadata });
|
|
245
|
+
setMetadataInputMode("key");
|
|
257
246
|
}
|
|
258
|
-
return;
|
|
259
247
|
}
|
|
260
|
-
|
|
248
|
+
else if ((input === "d" || key.delete) &&
|
|
249
|
+
selectedMetadataIndex >= 1 &&
|
|
250
|
+
selectedMetadataIndex <= metadataKeys.length) {
|
|
251
|
+
const keyToDelete = metadataKeys[selectedMetadataIndex - 1];
|
|
252
|
+
const newMetadata = { ...formData.metadata };
|
|
253
|
+
delete newMetadata[keyToDelete];
|
|
254
|
+
setFormData({ ...formData, metadata: newMetadata });
|
|
255
|
+
const newLength = Object.keys(newMetadata).length;
|
|
256
|
+
if (selectedMetadataIndex > newLength) {
|
|
257
|
+
setSelectedMetadataIndex(Math.max(0, newLength));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else if (key.escape || input === "q") {
|
|
261
|
+
setInMetadataSection(false);
|
|
262
|
+
setSelectedMetadataIndex(0);
|
|
263
|
+
setMetadataKey("");
|
|
264
|
+
setMetadataValue("");
|
|
265
|
+
setMetadataInputMode(null);
|
|
266
|
+
}
|
|
267
|
+
}, { isActive: inMetadataSection });
|
|
261
268
|
// Validate custom resource configuration
|
|
262
269
|
const validateCustomResources = () => {
|
|
263
270
|
if (formData.resource_size !== "CUSTOM_SIZE") {
|
|
@@ -329,6 +336,9 @@ export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initial
|
|
|
329
336
|
if (formData.snapshot_id) {
|
|
330
337
|
createParams.snapshot_id = formData.snapshot_id;
|
|
331
338
|
}
|
|
339
|
+
if (formData.network_policy_id) {
|
|
340
|
+
launchParameters.network_policy_id = formData.network_policy_id;
|
|
341
|
+
}
|
|
332
342
|
if (Object.keys(launchParameters).length > 0) {
|
|
333
343
|
createParams.launch_parameters = launchParameters;
|
|
334
344
|
}
|
|
@@ -344,11 +354,14 @@ export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initial
|
|
|
344
354
|
};
|
|
345
355
|
// Result screen
|
|
346
356
|
if (result) {
|
|
347
|
-
return (_jsxs(_Fragment, { children: [_jsx(Breadcrumb, { items: [{ label: "Devboxes" }, { label: "Create", active: true }] }), _jsx(SuccessMessage, { message: "Devbox created successfully!" }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.textDim, dimColor: true, children: ["ID:", " "] }), _jsx(Text, { color: colors.idColor, children: result.id })] }), _jsx(Box, { children: _jsxs(Text, { color: colors.textDim, dimColor: true, children: ["Name: ", result.name || "(none)"] }) }), _jsx(Box, { children: _jsxs(Text, { color: colors.textDim, dimColor: true, children: ["Status: ", result.status] }) })] }), _jsx(
|
|
357
|
+
return (_jsxs(_Fragment, { children: [_jsx(Breadcrumb, { items: [{ label: "Devboxes" }, { label: "Create", active: true }] }), _jsx(SuccessMessage, { message: "Devbox created successfully!" }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.textDim, dimColor: true, children: ["ID:", " "] }), _jsx(Text, { color: colors.idColor, children: result.id })] }), _jsx(Box, { children: _jsxs(Text, { color: colors.textDim, dimColor: true, children: ["Name: ", result.name || "(none)"] }) }), _jsx(Box, { children: _jsxs(Text, { color: colors.textDim, dimColor: true, children: ["Status: ", result.status] }) })] }), _jsx(NavigationTips, { tips: [{ key: "Enter/q/esc", label: "Return to list" }] })] }));
|
|
348
358
|
}
|
|
349
359
|
// Error screen
|
|
350
360
|
if (error) {
|
|
351
|
-
return (_jsxs(_Fragment, { children: [_jsx(Breadcrumb, { items: [{ label: "Devboxes" }, { label: "Create", active: true }] }), _jsx(ErrorMessage, { message: "Failed to create devbox", error: error }), _jsx(
|
|
361
|
+
return (_jsxs(_Fragment, { children: [_jsx(Breadcrumb, { items: [{ label: "Devboxes" }, { label: "Create", active: true }] }), _jsx(ErrorMessage, { message: "Failed to create devbox", error: error }), _jsx(NavigationTips, { tips: [
|
|
362
|
+
{ key: "Enter/r", label: "Retry" },
|
|
363
|
+
{ key: "q/esc", label: "Cancel" },
|
|
364
|
+
] })] }));
|
|
352
365
|
}
|
|
353
366
|
// Creating screen
|
|
354
367
|
if (creating) {
|
|
@@ -359,24 +372,14 @@ export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initial
|
|
|
359
372
|
const isActive = currentField === field.key;
|
|
360
373
|
const fieldData = formData[field.key];
|
|
361
374
|
if (field.type === "action") {
|
|
362
|
-
return (
|
|
375
|
+
return (_jsx(FormActionButton, { label: field.label, isActive: isActive, hint: "[Enter to create]" }, field.key));
|
|
363
376
|
}
|
|
364
377
|
if (field.type === "text") {
|
|
365
|
-
return (
|
|
366
|
-
setFormData({ ...formData, [field.key]: value });
|
|
367
|
-
}, placeholder: field.key === "name"
|
|
368
|
-
? "my-devbox"
|
|
369
|
-
: field.key === "keep_alive"
|
|
370
|
-
? "3600"
|
|
371
|
-
: field.key === "blueprint_id"
|
|
372
|
-
? "bp_xxx"
|
|
373
|
-
: field.key === "snapshot_id"
|
|
374
|
-
? "snap_xxx"
|
|
375
|
-
: "" })) : (_jsx(Text, { color: colors.text, children: String(fieldData || "(empty)") }))] }, field.key));
|
|
378
|
+
return (_jsx(FormTextInput, { label: field.label, value: String(fieldData || ""), onChange: (value) => setFormData({ ...formData, [field.key]: value }), onSubmit: handleCreate, isActive: isActive, placeholder: field.placeholder }, field.key));
|
|
376
379
|
}
|
|
377
380
|
if (field.type === "select") {
|
|
378
381
|
const value = fieldData;
|
|
379
|
-
return (
|
|
382
|
+
return (_jsx(FormSelect, { label: field.label, value: value || "", options: field.key === "architecture" ? architectures : resourceSizes, onChange: (newValue) => setFormData({ ...formData, [field.key]: newValue }), isActive: isActive }, field.key));
|
|
380
383
|
}
|
|
381
384
|
if (field.type === "metadata") {
|
|
382
385
|
if (!inMetadataSection) {
|
|
@@ -413,5 +416,8 @@ export const DevboxCreatePage = ({ onBack, onCreate, initialBlueprintId, initial
|
|
|
413
416
|
}
|
|
414
417
|
return null;
|
|
415
418
|
}) }), formData.resource_size === "CUSTOM_SIZE" &&
|
|
416
|
-
validateCustomResources() && (_jsxs(Box, { borderStyle: "round", borderColor: colors.error, paddingX: 1, paddingY: 0, marginTop: 1, children: [_jsxs(Text, { color: colors.error, bold: true, children: [figures.cross, " Validation Error"] }), _jsx(Text, { color: colors.error, dimColor: true, children: validateCustomResources() })] })), !inMetadataSection && (_jsx(
|
|
419
|
+
validateCustomResources() && (_jsxs(Box, { borderStyle: "round", borderColor: colors.error, paddingX: 1, paddingY: 0, marginTop: 1, children: [_jsxs(Text, { color: colors.error, bold: true, children: [figures.cross, " Validation Error"] }), _jsx(Text, { color: colors.error, dimColor: true, children: validateCustomResources() })] })), !inMetadataSection && (_jsx(NavigationTips, { showArrows: true, tips: [
|
|
420
|
+
{ key: "Enter", label: "Create" },
|
|
421
|
+
{ key: "q", label: "Cancel" },
|
|
422
|
+
] }))] }));
|
|
417
423
|
};
|