more-compute 0.4.4__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- frontend/app/globals.css +734 -27
- frontend/app/layout.tsx +13 -3
- frontend/components/Notebook.tsx +2 -14
- frontend/components/cell/MonacoCell.tsx +99 -5
- frontend/components/layout/Sidebar.tsx +39 -4
- frontend/components/panels/ClaudePanel.tsx +461 -0
- frontend/components/popups/ComputePopup.tsx +738 -447
- frontend/components/popups/FilterPopup.tsx +305 -189
- frontend/components/popups/MetricsPopup.tsx +20 -1
- frontend/components/popups/ProviderConfigModal.tsx +322 -0
- frontend/components/popups/ProviderDropdown.tsx +398 -0
- frontend/components/popups/SettingsPopup.tsx +1 -1
- frontend/contexts/ClaudeContext.tsx +392 -0
- frontend/contexts/PodWebSocketContext.tsx +16 -21
- frontend/hooks/useInlineDiff.ts +269 -0
- frontend/lib/api.ts +323 -12
- frontend/lib/settings.ts +5 -0
- frontend/lib/websocket-native.ts +4 -8
- frontend/lib/websocket.ts +1 -2
- frontend/package-lock.json +733 -36
- frontend/package.json +2 -0
- frontend/public/assets/icons/providers/lambda_labs.svg +22 -0
- frontend/public/assets/icons/providers/prime_intellect.svg +18 -0
- frontend/public/assets/icons/providers/runpod.svg +9 -0
- frontend/public/assets/icons/providers/vastai.svg +1 -0
- frontend/settings.md +54 -0
- frontend/tsconfig.tsbuildinfo +1 -0
- frontend/types/claude.ts +194 -0
- kernel_run.py +13 -0
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/METADATA +53 -11
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/RECORD +56 -37
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/WHEEL +1 -1
- morecompute/__init__.py +1 -1
- morecompute/__version__.py +1 -1
- morecompute/execution/executor.py +24 -67
- morecompute/execution/worker.py +6 -72
- morecompute/models/api_models.py +62 -0
- morecompute/notebook.py +11 -0
- morecompute/server.py +641 -133
- morecompute/services/claude_service.py +392 -0
- morecompute/services/pod_manager.py +168 -67
- morecompute/services/pod_monitor.py +67 -39
- morecompute/services/prime_intellect.py +0 -4
- morecompute/services/providers/__init__.py +92 -0
- morecompute/services/providers/base_provider.py +336 -0
- morecompute/services/providers/lambda_labs_provider.py +394 -0
- morecompute/services/providers/provider_factory.py +194 -0
- morecompute/services/providers/runpod_provider.py +504 -0
- morecompute/services/providers/vastai_provider.py +407 -0
- morecompute/utils/cell_magics.py +0 -3
- morecompute/utils/config_util.py +93 -3
- morecompute/utils/special_commands.py +5 -32
- morecompute/utils/version_check.py +117 -0
- frontend/styling_README.md +0 -23
- {more_compute-0.4.4.dist-info/licenses → more_compute-0.5.0.dist-info}/LICENSE +0 -0
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/entry_points.txt +0 -0
- {more_compute-0.4.4.dist-info → more_compute-0.5.0.dist-info}/top_level.txt +0 -0
|
@@ -7,54 +7,84 @@ interface FilterPopupProps {
|
|
|
7
7
|
filters: GpuAvailabilityParams;
|
|
8
8
|
onFiltersChange: (filters: GpuAvailabilityParams) => void;
|
|
9
9
|
onApply: () => void;
|
|
10
|
+
providerName?: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
// Common GPU types across providers
|
|
12
14
|
const GPU_TYPES = [
|
|
13
|
-
{ value: "
|
|
14
|
-
{ value: "
|
|
15
|
-
{ value: "
|
|
16
|
-
{ value: "
|
|
17
|
-
{ value: "
|
|
18
|
-
{ value: "
|
|
19
|
-
{ value: "
|
|
20
|
-
{ value: "
|
|
21
|
-
{ value: "
|
|
22
|
-
{ value: "
|
|
23
|
-
{ value: "
|
|
24
|
-
{ value: "
|
|
25
|
-
{ value: "
|
|
26
|
-
{ value: "
|
|
27
|
-
{ value: "
|
|
28
|
-
{ value: "
|
|
29
|
-
{ value: "
|
|
30
|
-
{ value: "
|
|
31
|
-
{ value: "
|
|
32
|
-
{ value: "
|
|
33
|
-
{ value: "
|
|
34
|
-
{ value: "
|
|
35
|
-
{ value: "
|
|
36
|
-
{ value: "
|
|
37
|
-
{ value: "V100_16GB", label: "V100 16GB" },
|
|
38
|
-
{ value: "T4_16GB", label: "T4 16GB" },
|
|
39
|
-
{ value: "P100_16GB", label: "P100 16GB" },
|
|
40
|
-
{ value: "A6000_48GB", label: "A6000 48GB" },
|
|
41
|
-
{ value: "A5000_24GB", label: "A5000 24GB" },
|
|
42
|
-
{ value: "A4000_16GB", label: "A4000 16GB" },
|
|
43
|
-
{ value: "RTX6000Ada_48GB", label: "RTX 6000 Ada 48GB" },
|
|
44
|
-
{ value: "RTX5000Ada_32GB", label: "RTX 5000 Ada 32GB" },
|
|
45
|
-
{ value: "RTX4000Ada_20GB", label: "RTX 4000 Ada 20GB" },
|
|
15
|
+
{ value: "H100", label: "H100" },
|
|
16
|
+
{ value: "H200", label: "H200" },
|
|
17
|
+
{ value: "A100", label: "A100" },
|
|
18
|
+
{ value: "A10", label: "A10" },
|
|
19
|
+
{ value: "A30", label: "A30" },
|
|
20
|
+
{ value: "A40", label: "A40" },
|
|
21
|
+
{ value: "A6000", label: "A6000" },
|
|
22
|
+
{ value: "A5000", label: "A5000" },
|
|
23
|
+
{ value: "A4000", label: "A4000" },
|
|
24
|
+
{ value: "L40S", label: "L40S" },
|
|
25
|
+
{ value: "L40", label: "L40" },
|
|
26
|
+
{ value: "L4", label: "L4" },
|
|
27
|
+
{ value: "RTX 4090", label: "RTX 4090" },
|
|
28
|
+
{ value: "RTX 4080", label: "RTX 4080" },
|
|
29
|
+
{ value: "RTX 4070", label: "RTX 4070" },
|
|
30
|
+
{ value: "RTX 3090", label: "RTX 3090" },
|
|
31
|
+
{ value: "RTX 3080", label: "RTX 3080" },
|
|
32
|
+
{ value: "RTX 3070", label: "RTX 3070" },
|
|
33
|
+
{ value: "RTX 6000", label: "RTX 6000 Ada" },
|
|
34
|
+
{ value: "RTX 5000", label: "RTX 5000 Ada" },
|
|
35
|
+
{ value: "RTX 4000", label: "RTX 4000 Ada" },
|
|
36
|
+
{ value: "V100", label: "V100" },
|
|
37
|
+
{ value: "T4", label: "T4" },
|
|
38
|
+
{ value: "P100", label: "P100" },
|
|
46
39
|
];
|
|
47
40
|
|
|
41
|
+
// Provider-specific filter categories
|
|
42
|
+
type FilterCategory = "gpu_type" | "gpu_count" | "cloud_type" | "verified" | "reliability";
|
|
43
|
+
|
|
44
|
+
const getFilterCategoriesForProvider = (provider: string): { value: FilterCategory; label: string }[] => {
|
|
45
|
+
const common = [
|
|
46
|
+
{ value: "gpu_type" as FilterCategory, label: "GPU Type" },
|
|
47
|
+
{ value: "gpu_count" as FilterCategory, label: "GPU Count" },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
switch (provider) {
|
|
51
|
+
case "runpod":
|
|
52
|
+
return [
|
|
53
|
+
...common,
|
|
54
|
+
{ value: "cloud_type" as FilterCategory, label: "Cloud Type" },
|
|
55
|
+
];
|
|
56
|
+
case "vastai":
|
|
57
|
+
return [
|
|
58
|
+
...common,
|
|
59
|
+
{ value: "verified" as FilterCategory, label: "Verified" },
|
|
60
|
+
{ value: "reliability" as FilterCategory, label: "Reliability" },
|
|
61
|
+
];
|
|
62
|
+
case "lambda_labs":
|
|
63
|
+
default:
|
|
64
|
+
return common;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
48
68
|
const FilterPopup: React.FC<FilterPopupProps> = ({
|
|
49
69
|
isOpen,
|
|
50
70
|
onClose,
|
|
51
71
|
filters,
|
|
52
72
|
onFiltersChange,
|
|
53
73
|
onApply,
|
|
74
|
+
providerName = "runpod",
|
|
54
75
|
}) => {
|
|
55
|
-
const
|
|
76
|
+
const categories = getFilterCategoriesForProvider(providerName);
|
|
77
|
+
const [filterCategory, setFilterCategory] = React.useState<FilterCategory>(categories[0]?.value || "gpu_type");
|
|
56
78
|
const [filterSearch, setFilterSearch] = React.useState<string>("");
|
|
57
79
|
|
|
80
|
+
// Reset category when provider changes
|
|
81
|
+
React.useEffect(() => {
|
|
82
|
+
const validCategories = getFilterCategoriesForProvider(providerName);
|
|
83
|
+
if (!validCategories.find(c => c.value === filterCategory)) {
|
|
84
|
+
setFilterCategory(validCategories[0]?.value || "gpu_type");
|
|
85
|
+
}
|
|
86
|
+
}, [providerName, filterCategory]);
|
|
87
|
+
|
|
58
88
|
if (!isOpen) return null;
|
|
59
89
|
|
|
60
90
|
const handleClearAll = () => {
|
|
@@ -62,6 +92,17 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
|
|
|
62
92
|
setFilterSearch("");
|
|
63
93
|
};
|
|
64
94
|
|
|
95
|
+
// Get the count of active filters
|
|
96
|
+
const getActiveFilterCount = (): number => {
|
|
97
|
+
let count = 0;
|
|
98
|
+
if (filters.gpu_type) count++;
|
|
99
|
+
if (filters.gpu_count) count++;
|
|
100
|
+
if (filters.secure_cloud !== undefined || filters.community_cloud !== undefined) count++;
|
|
101
|
+
if (filters.verified !== undefined) count++;
|
|
102
|
+
if (filters.min_reliability !== undefined) count++;
|
|
103
|
+
return count;
|
|
104
|
+
};
|
|
105
|
+
|
|
65
106
|
return (
|
|
66
107
|
<>
|
|
67
108
|
{/* Backdrop */}
|
|
@@ -113,7 +154,7 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
|
|
|
113
154
|
color: "var(--mc-text-color)",
|
|
114
155
|
}}
|
|
115
156
|
>
|
|
116
|
-
Filter
|
|
157
|
+
Filter {getActiveFilterCount() > 0 && `(${getActiveFilterCount()})`}
|
|
117
158
|
</h4>
|
|
118
159
|
<button
|
|
119
160
|
onClick={handleClearAll}
|
|
@@ -135,7 +176,7 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
|
|
|
135
176
|
<select
|
|
136
177
|
value={filterCategory}
|
|
137
178
|
onChange={(e) => {
|
|
138
|
-
setFilterCategory(e.target.value);
|
|
179
|
+
setFilterCategory(e.target.value as FilterCategory);
|
|
139
180
|
setFilterSearch("");
|
|
140
181
|
}}
|
|
141
182
|
style={{
|
|
@@ -150,30 +191,33 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
|
|
|
150
191
|
cursor: "pointer",
|
|
151
192
|
}}
|
|
152
193
|
>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
194
|
+
{categories.map((cat) => (
|
|
195
|
+
<option key={cat.value} value={cat.value}>
|
|
196
|
+
{cat.label}
|
|
197
|
+
</option>
|
|
198
|
+
))}
|
|
157
199
|
</select>
|
|
158
200
|
|
|
159
|
-
{/* Search within category */}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
201
|
+
{/* Search within category (only for GPU type) */}
|
|
202
|
+
{filterCategory === "gpu_type" && (
|
|
203
|
+
<input
|
|
204
|
+
type="text"
|
|
205
|
+
placeholder="Search GPU types..."
|
|
206
|
+
value={filterSearch}
|
|
207
|
+
onChange={(e) => setFilterSearch(e.target.value)}
|
|
208
|
+
style={{
|
|
209
|
+
width: "100%",
|
|
210
|
+
padding: "8px 10px",
|
|
211
|
+
borderRadius: "6px",
|
|
212
|
+
border: "1px solid var(--mc-border)",
|
|
213
|
+
backgroundColor: "var(--mc-input-background)",
|
|
214
|
+
color: "var(--mc-text-color)",
|
|
215
|
+
fontSize: "12px",
|
|
216
|
+
marginBottom: "12px",
|
|
217
|
+
boxSizing: "border-box",
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
220
|
+
)}
|
|
177
221
|
|
|
178
222
|
{/* Options List */}
|
|
179
223
|
<div
|
|
@@ -187,8 +231,40 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
|
|
|
187
231
|
padding: "4px",
|
|
188
232
|
}}
|
|
189
233
|
>
|
|
234
|
+
{/* GPU Type Filter - Universal */}
|
|
190
235
|
{filterCategory === "gpu_type" && (
|
|
191
236
|
<>
|
|
237
|
+
<label
|
|
238
|
+
style={{
|
|
239
|
+
display: "flex",
|
|
240
|
+
alignItems: "center",
|
|
241
|
+
padding: "8px 6px",
|
|
242
|
+
cursor: "pointer",
|
|
243
|
+
fontSize: "12px",
|
|
244
|
+
color: "var(--mc-text-color)",
|
|
245
|
+
borderRadius: "4px",
|
|
246
|
+
transition: "background-color 0.15s",
|
|
247
|
+
}}
|
|
248
|
+
onMouseEnter={(e) =>
|
|
249
|
+
(e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
|
|
250
|
+
}
|
|
251
|
+
onMouseLeave={(e) =>
|
|
252
|
+
(e.currentTarget.style.backgroundColor = "transparent")
|
|
253
|
+
}
|
|
254
|
+
>
|
|
255
|
+
<input
|
|
256
|
+
type="radio"
|
|
257
|
+
checked={!filters.gpu_type}
|
|
258
|
+
onChange={() =>
|
|
259
|
+
onFiltersChange({
|
|
260
|
+
...filters,
|
|
261
|
+
gpu_type: undefined,
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
265
|
+
/>
|
|
266
|
+
All GPUs
|
|
267
|
+
</label>
|
|
192
268
|
{GPU_TYPES.filter((gpu) =>
|
|
193
269
|
gpu.label.toLowerCase().includes(filterSearch.toLowerCase())
|
|
194
270
|
).map((gpu) => (
|
|
@@ -228,155 +304,195 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
|
|
|
228
304
|
</>
|
|
229
305
|
)}
|
|
230
306
|
|
|
307
|
+
{/* GPU Count Filter - Universal */}
|
|
231
308
|
{filterCategory === "gpu_count" && (
|
|
232
309
|
<>
|
|
233
310
|
{[
|
|
234
|
-
{ value:
|
|
235
|
-
{ value:
|
|
236
|
-
{ value:
|
|
237
|
-
{ value:
|
|
238
|
-
{ value:
|
|
239
|
-
]
|
|
240
|
-
|
|
241
|
-
option.label
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
311
|
+
{ value: undefined, label: "Any" },
|
|
312
|
+
{ value: 1, label: "1 GPU" },
|
|
313
|
+
{ value: 2, label: "2 GPUs" },
|
|
314
|
+
{ value: 4, label: "4 GPUs" },
|
|
315
|
+
{ value: 8, label: "8 GPUs" },
|
|
316
|
+
].map((option) => (
|
|
317
|
+
<label
|
|
318
|
+
key={option.label}
|
|
319
|
+
style={{
|
|
320
|
+
display: "flex",
|
|
321
|
+
alignItems: "center",
|
|
322
|
+
padding: "8px 6px",
|
|
323
|
+
cursor: "pointer",
|
|
324
|
+
fontSize: "12px",
|
|
325
|
+
color: "var(--mc-text-color)",
|
|
326
|
+
borderRadius: "4px",
|
|
327
|
+
transition: "background-color 0.15s",
|
|
328
|
+
}}
|
|
329
|
+
onMouseEnter={(e) =>
|
|
330
|
+
(e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
|
|
331
|
+
}
|
|
332
|
+
onMouseLeave={(e) =>
|
|
333
|
+
(e.currentTarget.style.backgroundColor = "transparent")
|
|
334
|
+
}
|
|
335
|
+
>
|
|
336
|
+
<input
|
|
337
|
+
type="radio"
|
|
338
|
+
checked={filters.gpu_count === option.value}
|
|
339
|
+
onChange={() =>
|
|
340
|
+
onFiltersChange({
|
|
341
|
+
...filters,
|
|
342
|
+
gpu_count: option.value,
|
|
343
|
+
})
|
|
261
344
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
onChange={() =>
|
|
269
|
-
onFiltersChange({
|
|
270
|
-
...filters,
|
|
271
|
-
gpu_count: option.value
|
|
272
|
-
? parseInt(option.value)
|
|
273
|
-
: undefined,
|
|
274
|
-
})
|
|
275
|
-
}
|
|
276
|
-
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
277
|
-
/>
|
|
278
|
-
{option.label}
|
|
279
|
-
</label>
|
|
280
|
-
))}
|
|
345
|
+
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
346
|
+
/>
|
|
347
|
+
{option.label}
|
|
348
|
+
</label>
|
|
349
|
+
))}
|
|
281
350
|
</>
|
|
282
351
|
)}
|
|
283
352
|
|
|
284
|
-
{
|
|
353
|
+
{/* Cloud Type Filter - RunPod specific */}
|
|
354
|
+
{filterCategory === "cloud_type" && providerName === "runpod" && (
|
|
285
355
|
<>
|
|
286
356
|
{[
|
|
287
|
-
{
|
|
288
|
-
{
|
|
289
|
-
{
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
357
|
+
{ secure: undefined, community: undefined, label: "All Clouds" },
|
|
358
|
+
{ secure: true, community: undefined, label: "Secure Cloud Only" },
|
|
359
|
+
{ secure: undefined, community: true, label: "Community Cloud Only" },
|
|
360
|
+
].map((option) => (
|
|
361
|
+
<label
|
|
362
|
+
key={option.label}
|
|
363
|
+
style={{
|
|
364
|
+
display: "flex",
|
|
365
|
+
alignItems: "center",
|
|
366
|
+
padding: "8px 6px",
|
|
367
|
+
cursor: "pointer",
|
|
368
|
+
fontSize: "12px",
|
|
369
|
+
color: "var(--mc-text-color)",
|
|
370
|
+
borderRadius: "4px",
|
|
371
|
+
transition: "background-color 0.15s",
|
|
372
|
+
}}
|
|
373
|
+
onMouseEnter={(e) =>
|
|
374
|
+
(e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
|
|
375
|
+
}
|
|
376
|
+
onMouseLeave={(e) =>
|
|
377
|
+
(e.currentTarget.style.backgroundColor = "transparent")
|
|
378
|
+
}
|
|
379
|
+
>
|
|
380
|
+
<input
|
|
381
|
+
type="radio"
|
|
382
|
+
checked={
|
|
383
|
+
filters.secure_cloud === option.secure &&
|
|
384
|
+
filters.community_cloud === option.community
|
|
312
385
|
}
|
|
313
|
-
|
|
314
|
-
(
|
|
386
|
+
onChange={() =>
|
|
387
|
+
onFiltersChange({
|
|
388
|
+
...filters,
|
|
389
|
+
secure_cloud: option.secure,
|
|
390
|
+
community_cloud: option.community,
|
|
391
|
+
})
|
|
315
392
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
327
|
-
/>
|
|
328
|
-
{option.label}
|
|
329
|
-
</label>
|
|
330
|
-
))}
|
|
393
|
+
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
394
|
+
/>
|
|
395
|
+
{option.label}
|
|
396
|
+
</label>
|
|
397
|
+
))}
|
|
398
|
+
<div style={{ padding: "8px 6px", fontSize: "11px", color: "var(--mc-text-secondary)", borderTop: "1px solid var(--mc-border)", marginTop: "8px" }}>
|
|
399
|
+
Secure Cloud: T3/T4 certified data centers<br />
|
|
400
|
+
Community Cloud: User-hosted GPUs
|
|
401
|
+
</div>
|
|
331
402
|
</>
|
|
332
403
|
)}
|
|
333
404
|
|
|
334
|
-
{
|
|
405
|
+
{/* Verified Filter - Vast.ai specific */}
|
|
406
|
+
{filterCategory === "verified" && providerName === "vastai" && (
|
|
335
407
|
<>
|
|
336
408
|
{[
|
|
337
|
-
{ value:
|
|
338
|
-
{ value:
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
409
|
+
{ value: undefined, label: "All Hosts" },
|
|
410
|
+
{ value: true, label: "Verified Hosts Only" },
|
|
411
|
+
].map((option) => (
|
|
412
|
+
<label
|
|
413
|
+
key={option.label}
|
|
414
|
+
style={{
|
|
415
|
+
display: "flex",
|
|
416
|
+
alignItems: "center",
|
|
417
|
+
padding: "8px 6px",
|
|
418
|
+
cursor: "pointer",
|
|
419
|
+
fontSize: "12px",
|
|
420
|
+
color: "var(--mc-text-color)",
|
|
421
|
+
borderRadius: "4px",
|
|
422
|
+
transition: "background-color 0.15s",
|
|
423
|
+
}}
|
|
424
|
+
onMouseEnter={(e) =>
|
|
425
|
+
(e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
|
|
426
|
+
}
|
|
427
|
+
onMouseLeave={(e) =>
|
|
428
|
+
(e.currentTarget.style.backgroundColor = "transparent")
|
|
429
|
+
}
|
|
430
|
+
>
|
|
431
|
+
<input
|
|
432
|
+
type="radio"
|
|
433
|
+
checked={filters.verified === option.value}
|
|
434
|
+
onChange={() =>
|
|
435
|
+
onFiltersChange({
|
|
436
|
+
...filters,
|
|
437
|
+
verified: option.value,
|
|
438
|
+
})
|
|
361
439
|
}
|
|
362
|
-
|
|
363
|
-
|
|
440
|
+
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
441
|
+
/>
|
|
442
|
+
{option.label}
|
|
443
|
+
</label>
|
|
444
|
+
))}
|
|
445
|
+
<div style={{ padding: "8px 6px", fontSize: "11px", color: "var(--mc-text-secondary)", borderTop: "1px solid var(--mc-border)", marginTop: "8px" }}>
|
|
446
|
+
Verified hosts have been validated by Vast.ai for reliability
|
|
447
|
+
</div>
|
|
448
|
+
</>
|
|
449
|
+
)}
|
|
450
|
+
|
|
451
|
+
{/* Reliability Filter - Vast.ai specific */}
|
|
452
|
+
{filterCategory === "reliability" && providerName === "vastai" && (
|
|
453
|
+
<>
|
|
454
|
+
{[
|
|
455
|
+
{ value: undefined, label: "Any Reliability" },
|
|
456
|
+
{ value: 0.9, label: "90%+ Reliability" },
|
|
457
|
+
{ value: 0.95, label: "95%+ Reliability" },
|
|
458
|
+
{ value: 0.99, label: "99%+ Reliability" },
|
|
459
|
+
].map((option) => (
|
|
460
|
+
<label
|
|
461
|
+
key={option.label}
|
|
462
|
+
style={{
|
|
463
|
+
display: "flex",
|
|
464
|
+
alignItems: "center",
|
|
465
|
+
padding: "8px 6px",
|
|
466
|
+
cursor: "pointer",
|
|
467
|
+
fontSize: "12px",
|
|
468
|
+
color: "var(--mc-text-color)",
|
|
469
|
+
borderRadius: "4px",
|
|
470
|
+
transition: "background-color 0.15s",
|
|
471
|
+
}}
|
|
472
|
+
onMouseEnter={(e) =>
|
|
473
|
+
(e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
|
|
474
|
+
}
|
|
475
|
+
onMouseLeave={(e) =>
|
|
476
|
+
(e.currentTarget.style.backgroundColor = "transparent")
|
|
477
|
+
}
|
|
478
|
+
>
|
|
479
|
+
<input
|
|
480
|
+
type="radio"
|
|
481
|
+
checked={filters.min_reliability === option.value}
|
|
482
|
+
onChange={() =>
|
|
483
|
+
onFiltersChange({
|
|
484
|
+
...filters,
|
|
485
|
+
min_reliability: option.value,
|
|
486
|
+
})
|
|
364
487
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
})
|
|
374
|
-
}
|
|
375
|
-
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
376
|
-
/>
|
|
377
|
-
{option.label}
|
|
378
|
-
</label>
|
|
379
|
-
))}
|
|
488
|
+
style={{ marginRight: "10px", cursor: "pointer" }}
|
|
489
|
+
/>
|
|
490
|
+
{option.label}
|
|
491
|
+
</label>
|
|
492
|
+
))}
|
|
493
|
+
<div style={{ padding: "8px 6px", fontSize: "11px", color: "var(--mc-text-secondary)", borderTop: "1px solid var(--mc-border)", marginTop: "8px" }}>
|
|
494
|
+
Higher reliability means fewer unexpected interruptions
|
|
495
|
+
</div>
|
|
380
496
|
</>
|
|
381
497
|
)}
|
|
382
498
|
</div>
|
|
@@ -14,9 +14,10 @@ const POLL_MS = 3000;
|
|
|
14
14
|
interface MetricsPopupProps {
|
|
15
15
|
onClose?: () => void;
|
|
16
16
|
sharedHistory?: MetricsSnapshot[]; // Passed from parent when in persistent mode
|
|
17
|
+
connectedProvider?: string; // Provider name for the connected pod
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
const MetricsPopup: React.FC<MetricsPopupProps> = ({ onClose, sharedHistory }) => {
|
|
20
|
+
const MetricsPopup: React.FC<MetricsPopupProps> = ({ onClose, sharedHistory, connectedProvider }) => {
|
|
20
21
|
const [metrics, setMetrics] = useState<MetricsSnapshot | null>(null);
|
|
21
22
|
const [localHistory, setLocalHistory] = useState<MetricsSnapshot[]>([]);
|
|
22
23
|
const intervalRef = useRef<number | null>(null);
|
|
@@ -58,8 +59,26 @@ const MetricsPopup: React.FC<MetricsPopupProps> = ({ onClose, sharedHistory }) =
|
|
|
58
59
|
|
|
59
60
|
const hasGPU = metrics?.gpu && metrics.gpu.length > 0;
|
|
60
61
|
|
|
62
|
+
// Provider display name mapping (SSH-based providers only)
|
|
63
|
+
const getProviderDisplayName = (provider?: string) => {
|
|
64
|
+
const names: Record<string, string> = {
|
|
65
|
+
prime_intellect: "Prime Intellect",
|
|
66
|
+
runpod: "RunPod",
|
|
67
|
+
lambda_labs: "Lambda Labs",
|
|
68
|
+
vastai: "Vast.ai",
|
|
69
|
+
};
|
|
70
|
+
return provider ? names[provider] || provider : "Local";
|
|
71
|
+
};
|
|
72
|
+
|
|
61
73
|
return (
|
|
62
74
|
<div className="metrics-container">
|
|
75
|
+
{/* Provider badge */}
|
|
76
|
+
{connectedProvider && (
|
|
77
|
+
<div className="metrics-provider-badge ssh-provider">
|
|
78
|
+
<span className="provider-dot" />
|
|
79
|
+
<span>Metrics from {getProviderDisplayName(connectedProvider)}</span>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
63
82
|
<div className="metrics-grid">
|
|
64
83
|
{metrics?.cpu && (
|
|
65
84
|
<Panel title="CPU Utilization" icon={<Cpu size={14} />}>
|