fix(kube): configure Monaco for offline use and fix pod column data (IP/Node/CPU/Memory)
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m48s
Test / frontend-typecheck (pull_request) Successful in 1m55s
PR Review Automation / review (pull_request) Successful in 4m9s
Test / rust-fmt-check (pull_request) Failing after 12m32s
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled

Monaco: install monaco-editor and configure @monaco-editor/react loader to use the locally
bundled module in main.tsx instead of the CDN, resolving the perpetual spinner in YamlEditor
under Tauri's offline WebView. Added worker format and optimizeDeps entries to vite.config.ts.

Pod columns: extend PodInfo struct with ip, node, and restarts fields; extract podIP, nodeName,
and restartCount from kubectl JSON output in parse_pods_json so the IP, Node columns render
real data instead of blanks.

Also fix ref-during-render lint error in useKeyboardShortcuts.
This commit is contained in:
Shaun Arman 2026-06-09 20:39:10 -05:00
parent 399ba30c6b
commit f993672b78
5 changed files with 85 additions and 1 deletions

39
package-lock.json generated
View File

@ -20,6 +20,7 @@
"class-variance-authority": "^0.7", "class-variance-authority": "^0.7",
"clsx": "^2", "clsx": "^2",
"lucide-react": "latest", "lucide-react": "latest",
"monaco-editor": "^0.55.1",
"react": "^19", "react": "^19",
"react-chartjs-2": "^5.3.1", "react-chartjs-2": "^5.3.1",
"react-diff-viewer-continued": "^4", "react-diff-viewer-continued": "^4",
@ -3001,6 +3002,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT",
"optional": true
},
"node_modules/@types/unist": { "node_modules/@types/unist": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
@ -5706,6 +5714,15 @@
"url": "https://github.com/fb55/domhandler?sponsor=1" "url": "https://github.com/fb55/domhandler?sponsor=1"
} }
}, },
"node_modules/dompurify": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz",
"integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==",
"license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
},
"node_modules/domutils": { "node_modules/domutils": {
"version": "3.2.2", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
@ -9404,6 +9421,18 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/marked": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz",
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -10603,6 +10632,16 @@
"node": ">=18.0.0" "node": ">=18.0.0"
} }
}, },
"node_modules/monaco-editor": {
"version": "0.55.1",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
"license": "MIT",
"dependencies": {
"dompurify": "3.2.7",
"marked": "14.0.0"
}
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",

View File

@ -27,6 +27,7 @@
"class-variance-authority": "^0.7", "class-variance-authority": "^0.7",
"clsx": "^2", "clsx": "^2",
"lucide-react": "latest", "lucide-react": "latest",
"monaco-editor": "^0.55.1",
"react": "^19", "react": "^19",
"react-chartjs-2": "^5.3.1", "react-chartjs-2": "^5.3.1",
"react-diff-viewer-continued": "^4", "react-diff-viewer-continued": "^4",

View File

@ -96,6 +96,9 @@ pub struct PodInfo {
pub ready: String, pub ready: String,
pub age: String, pub age: String,
pub containers: Vec<String>, pub containers: Vec<String>,
pub restarts: Option<u32>,
pub ip: Option<String>,
pub node: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -1159,6 +1162,35 @@ fn parse_pods_json(json_str: &str) -> Result<Vec<PodInfo>, String> {
}) })
.unwrap_or_default(); .unwrap_or_default();
let restarts = item
.get("status")
.and_then(|s| s.get("containerStatuses"))
.and_then(|c| c.as_array())
.map(|container_statuses| {
container_statuses
.iter()
.map(|c| {
c.get("restartCount")
.and_then(|r| r.as_u64())
.unwrap_or(0) as u32
})
.sum::<u32>()
});
let ip = item
.get("status")
.and_then(|s| s.get("podIP"))
.and_then(|v| v.as_str())
.filter(|s| !s.is_empty())
.map(|s| s.to_string());
let node = item
.get("spec")
.and_then(|s| s.get("nodeName"))
.and_then(|v| v.as_str())
.filter(|s| !s.is_empty())
.map(|s| s.to_string());
pods.push(PodInfo { pods.push(PodInfo {
name, name,
namespace, namespace,
@ -1166,6 +1198,9 @@ fn parse_pods_json(json_str: &str) -> Result<Vec<PodInfo>, String> {
ready, ready,
age, age,
containers, containers,
restarts,
ip,
node,
}); });
} }

View File

@ -13,7 +13,10 @@ export interface KeyboardShortcut {
export function useKeyboardShortcuts(shortcuts: KeyboardShortcut[]): void { export function useKeyboardShortcuts(shortcuts: KeyboardShortcut[]): void {
const shortcutsRef = useRef(shortcuts); const shortcutsRef = useRef(shortcuts);
useEffect(() => {
shortcutsRef.current = shortcuts; shortcutsRef.current = shortcuts;
}, [shortcuts]);
const handleKeyDown = useCallback((event: KeyboardEvent) => { const handleKeyDown = useCallback((event: KeyboardEvent) => {
for (const shortcut of shortcutsRef.current) { for (const shortcut of shortcutsRef.current) {

View File

@ -1,9 +1,15 @@
import React from "react"; import React from "react";
import ReactDOM from "react-dom/client"; import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter } from "react-router-dom";
import { loader } from "@monaco-editor/react";
import * as monaco from "monaco-editor";
import App from "./App"; import App from "./App";
import "./styles/globals.css"; import "./styles/globals.css";
// Use the locally bundled Monaco instead of loading from CDN.
// Tauri's WebView has no internet access so the default CDN loader never resolves.
loader.config({ monaco });
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode> <React.StrictMode>
<BrowserRouter> <BrowserRouter>