feat(kube): add Kubernetes management support
Some checks failed
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 8s
Test / frontend-tests (push) Successful in 1m31s
Test / frontend-typecheck (push) Successful in 1m39s
Auto Tag / changelog (push) Successful in 1m47s
Auto Tag / build-macos-arm64 (push) Successful in 2m52s
Auto Tag / build-linux-amd64 (push) Has been cancelled
Auto Tag / build-linux-arm64 (push) Has been cancelled
Auto Tag / build-windows-amd64 (push) Has been cancelled
Test / rust-fmt-check (push) Has been cancelled
Test / rust-clippy (push) Has been cancelled
Test / rust-tests (push) Has been cancelled
Some checks failed
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 8s
Test / frontend-tests (push) Successful in 1m31s
Test / frontend-typecheck (push) Successful in 1m39s
Auto Tag / changelog (push) Successful in 1m47s
Auto Tag / build-macos-arm64 (push) Successful in 2m52s
Auto Tag / build-linux-amd64 (push) Has been cancelled
Auto Tag / build-linux-arm64 (push) Has been cancelled
Auto Tag / build-windows-amd64 (push) Has been cancelled
Test / rust-fmt-check (push) Has been cancelled
Test / rust-clippy (push) Has been cancelled
Test / rust-tests (push) Has been cancelled
- Bump version to 1.1.0 - Add kube module with ClusterClient, PortForwardSession, RefreshRegistry - Add Tauri IPC commands: add_cluster, remove_cluster, list_clusters - Add Tauri IPC commands: start_port_forward, stop_port_forward, list_port_forwards - Update AppState with clusters, port_forwards, refresh_registry fields - Update auto-tag.yml to mark releases as draft (pre-release) - Add Buy Me A Coffee section to README - Add serde_yaml dependency for kubeconfig parsing
This commit is contained in:
parent
170990ec00
commit
b96ede35cd
@ -167,7 +167,7 @@ jobs:
|
||||
--arg tag "$TAG" \
|
||||
--arg name "TFTSR $TAG" \
|
||||
--rawfile body /tmp/release_body.md \
|
||||
'{tag_name: $tag, name: $name, body: $body, draft: false}' \
|
||||
'{tag_name: $tag, name: $name, body: $body, draft: true}' \
|
||||
| curl -sf -X POST "$API/releases" \
|
||||
-H "Authorization: token $RELEASE_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
|
||||
12
README.md
12
README.md
@ -327,3 +327,15 @@ Override with the `TRCAA_DATA_DIR` (or legacy `TRCAA_DATA_DIR`) environment vari
|
||||
| 12 | Release Packaging | ✅ linux/amd64 · linux/arm64 (native) · windows/amd64 |
|
||||
|
||||
---
|
||||
|
||||
## Support the Project
|
||||
|
||||
If you find this project helpful, consider buying me a coffee:
|
||||
|
||||
[](https://buymeacoffee.com/tftsr)
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT License — see [LICENSE](LICENSE) for details.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "trcaa",
|
||||
"private": true,
|
||||
"version": "1.0.8",
|
||||
"version": "1.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
22
src-tauri/Cargo.lock
generated
22
src-tauri/Cargo.lock
generated
@ -4733,6 +4733,19 @@ dependencies = [
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap 2.14.0",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serialize-to-javascript"
|
||||
version = "0.1.2"
|
||||
@ -6069,7 +6082,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "trcaa"
|
||||
version = "1.0.8"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"aho-corasick",
|
||||
@ -6096,6 +6109,7 @@ dependencies = [
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
@ -6249,6 +6263,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "trcaa"
|
||||
version = "1.0.8"
|
||||
version = "1.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
@ -55,6 +55,9 @@ rmcp = { version = "1.7.0", features = [
|
||||
] }
|
||||
http = "1.4"
|
||||
flate2 = { version = "1", features = ["rust_backend"] }
|
||||
serde_yaml = "0.9"
|
||||
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-test = "0.4"
|
||||
@ -63,12 +66,3 @@ mockito = "1.2"
|
||||
[profile.release]
|
||||
opt-level = "s"
|
||||
strip = true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1159,12 +1159,24 @@
|
||||
"const": "fs:allow-size",
|
||||
"markdownDescription": "Enables the size command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the start_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:allow-start-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Enables the start_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the stat command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:allow-stat",
|
||||
"markdownDescription": "Enables the stat command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the stop_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:allow-stop-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Enables the stop_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the truncate command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -1315,12 +1327,24 @@
|
||||
"const": "fs:deny-size",
|
||||
"markdownDescription": "Denies the size command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the start_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:deny-start-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Denies the start_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the stat command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:deny-stat",
|
||||
"markdownDescription": "Denies the stat command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the stop_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:deny-stop-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Denies the stop_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the truncate command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -2331,10 +2355,10 @@
|
||||
"markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`",
|
||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`\n- `allow-supports-multiple-windows`",
|
||||
"type": "string",
|
||||
"const": "core:app:default",
|
||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`"
|
||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`\n- `allow-supports-multiple-windows`"
|
||||
},
|
||||
{
|
||||
"description": "Enables the app_hide command without any pre-configured scope.",
|
||||
@ -2408,6 +2432,12 @@
|
||||
"const": "core:app:allow-set-dock-visibility",
|
||||
"markdownDescription": "Enables the set_dock_visibility command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the supports_multiple_windows command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-supports-multiple-windows",
|
||||
"markdownDescription": "Enables the supports_multiple_windows command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the tauri_version command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -2492,6 +2522,12 @@
|
||||
"const": "core:app:deny-set-dock-visibility",
|
||||
"markdownDescription": "Denies the set_dock_visibility command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the supports_multiple_windows command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-supports-multiple-windows",
|
||||
"markdownDescription": "Denies the supports_multiple_windows command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the tauri_version command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -3015,10 +3051,10 @@
|
||||
"markdownDescription": "Denies the close command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`",
|
||||
"description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-icon-with-as-template`\n- `allow-set-show-menu-on-left-click`",
|
||||
"type": "string",
|
||||
"const": "core:tray:default",
|
||||
"markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`"
|
||||
"markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-icon-with-as-template`\n- `allow-set-show-menu-on-left-click`"
|
||||
},
|
||||
{
|
||||
"description": "Enables the get_by_id command without any pre-configured scope.",
|
||||
@ -3050,6 +3086,12 @@
|
||||
"const": "core:tray:allow-set-icon-as-template",
|
||||
"markdownDescription": "Enables the set_icon_as_template command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_icon_with_as_template command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:tray:allow-set-icon-with-as-template",
|
||||
"markdownDescription": "Enables the set_icon_with_as_template command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_menu command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -3116,6 +3158,12 @@
|
||||
"const": "core:tray:deny-set-icon-as-template",
|
||||
"markdownDescription": "Denies the set_icon_as_template command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_icon_with_as_template command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:tray:deny-set-icon-with-as-template",
|
||||
"markdownDescription": "Denies the set_icon_with_as_template command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_menu command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -3375,10 +3423,16 @@
|
||||
"markdownDescription": "Denies the webview_size command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`",
|
||||
"description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-activity-name`\n- `allow-scene-identifier`\n- `allow-internal-toggle-maximize`",
|
||||
"type": "string",
|
||||
"const": "core:window:default",
|
||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`"
|
||||
"markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-activity-name`\n- `allow-scene-identifier`\n- `allow-internal-toggle-maximize`"
|
||||
},
|
||||
{
|
||||
"description": "Enables the activity_name command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-activity-name",
|
||||
"markdownDescription": "Enables the activity_name command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the available_monitors command without any pre-configured scope.",
|
||||
@ -3572,6 +3626,12 @@
|
||||
"const": "core:window:allow-scale-factor",
|
||||
"markdownDescription": "Enables the scale_factor command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the scene_identifier command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-scene-identifier",
|
||||
"markdownDescription": "Enables the scene_identifier command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_always_on_bottom command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -3836,6 +3896,12 @@
|
||||
"const": "core:window:allow-unminimize",
|
||||
"markdownDescription": "Enables the unminimize command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the activity_name command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-activity-name",
|
||||
"markdownDescription": "Denies the activity_name command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the available_monitors command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -4028,6 +4094,12 @@
|
||||
"const": "core:window:deny-scale-factor",
|
||||
"markdownDescription": "Denies the scale_factor command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the scene_identifier command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-scene-identifier",
|
||||
"markdownDescription": "Denies the scene_identifier command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_always_on_bottom command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -4293,22 +4365,22 @@
|
||||
"markdownDescription": "Denies the unminimize command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-ask`\n- `allow-confirm`\n- `allow-message`\n- `allow-save`\n- `allow-open`",
|
||||
"description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-message`\n- `allow-save`\n- `allow-open`",
|
||||
"type": "string",
|
||||
"const": "dialog:default",
|
||||
"markdownDescription": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-ask`\n- `allow-confirm`\n- `allow-message`\n- `allow-save`\n- `allow-open`"
|
||||
"markdownDescription": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-message`\n- `allow-save`\n- `allow-open`"
|
||||
},
|
||||
{
|
||||
"description": "Enables the ask command without any pre-configured scope.",
|
||||
"description": "Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)",
|
||||
"type": "string",
|
||||
"const": "dialog:allow-ask",
|
||||
"markdownDescription": "Enables the ask command without any pre-configured scope."
|
||||
"markdownDescription": "Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)"
|
||||
},
|
||||
{
|
||||
"description": "Enables the confirm command without any pre-configured scope.",
|
||||
"description": "Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)",
|
||||
"type": "string",
|
||||
"const": "dialog:allow-confirm",
|
||||
"markdownDescription": "Enables the confirm command without any pre-configured scope."
|
||||
"markdownDescription": "Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)"
|
||||
},
|
||||
{
|
||||
"description": "Enables the message command without any pre-configured scope.",
|
||||
@ -4329,16 +4401,16 @@
|
||||
"markdownDescription": "Enables the save command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the ask command without any pre-configured scope.",
|
||||
"description": "Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)",
|
||||
"type": "string",
|
||||
"const": "dialog:deny-ask",
|
||||
"markdownDescription": "Denies the ask command without any pre-configured scope."
|
||||
"markdownDescription": "Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)"
|
||||
},
|
||||
{
|
||||
"description": "Denies the confirm command without any pre-configured scope.",
|
||||
"description": "Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)",
|
||||
"type": "string",
|
||||
"const": "dialog:deny-confirm",
|
||||
"markdownDescription": "Denies the confirm command without any pre-configured scope."
|
||||
"markdownDescription": "Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)"
|
||||
},
|
||||
{
|
||||
"description": "Denies the message command without any pre-configured scope.",
|
||||
@ -5378,12 +5450,24 @@
|
||||
"const": "fs:allow-size",
|
||||
"markdownDescription": "Enables the size command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the start_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:allow-start-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Enables the start_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the stat command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:allow-stat",
|
||||
"markdownDescription": "Enables the stat command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the stop_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:allow-stop-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Enables the stop_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the truncate command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@ -5534,12 +5618,24 @@
|
||||
"const": "fs:deny-size",
|
||||
"markdownDescription": "Denies the size command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the start_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:deny-start-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Denies the start_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the stat command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:deny-stat",
|
||||
"markdownDescription": "Denies the stat command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the stop_accessing_security_scoped_resource command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "fs:deny-stop-accessing-security-scoped-resource",
|
||||
"markdownDescription": "Denies the stop_accessing_security_scoped_resource command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the truncate command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
@ -335,6 +335,9 @@ pub async fn initiate_oauth(
|
||||
integration_webviews,
|
||||
mcp_connections,
|
||||
pending_approvals,
|
||||
clusters: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||
port_forwards: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||
refresh_registry: Arc::new(tokio::sync::Mutex::new(crate::kube::RefreshRegistry::new())),
|
||||
};
|
||||
while let Some(callback) = callback_rx.recv().await {
|
||||
tracing::info!("Received OAuth callback for state: {}", callback.state);
|
||||
|
||||
176
src-tauri/src/commands/kube.rs
Normal file
176
src-tauri/src/commands/kube.rs
Normal file
@ -0,0 +1,176 @@
|
||||
use crate::kube::ClusterClient;
|
||||
use crate::state::AppState;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::State;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ClusterInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub context: String,
|
||||
pub cluster_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PortForwardRequest {
|
||||
pub cluster_id: String,
|
||||
pub namespace: String,
|
||||
pub pod: String,
|
||||
pub container_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PortForwardResponse {
|
||||
pub id: String,
|
||||
pub cluster_id: String,
|
||||
pub namespace: String,
|
||||
pub pod: String,
|
||||
pub container_port: u16,
|
||||
pub local_port: u16,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn add_cluster(
|
||||
id: String,
|
||||
name: String,
|
||||
kubeconfig_content: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<ClusterInfo, String> {
|
||||
let context = extract_context(&kubeconfig_content)?;
|
||||
let server_url = extract_server_url(&kubeconfig_content)?;
|
||||
|
||||
let client = ClusterClient::new(
|
||||
id.clone(),
|
||||
name.clone(),
|
||||
context.clone(),
|
||||
server_url.clone(),
|
||||
);
|
||||
|
||||
{
|
||||
let mut clusters = state.clusters.lock().await;
|
||||
clusters.insert(id.clone(), client);
|
||||
}
|
||||
|
||||
Ok(ClusterInfo {
|
||||
id,
|
||||
name,
|
||||
context,
|
||||
cluster_url: server_url,
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn remove_cluster(
|
||||
id: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<(), String> {
|
||||
let mut clusters = state.clusters.lock().await;
|
||||
|
||||
if clusters.remove(&id).is_none() {
|
||||
return Err(format!("Cluster {id} not found"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_clusters(
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<Vec<ClusterInfo>, String> {
|
||||
let clusters = state.clusters.lock().await;
|
||||
|
||||
let cluster_list: Vec<ClusterInfo> = clusters
|
||||
.values()
|
||||
.map(|c| ClusterInfo {
|
||||
id: c.id.clone(),
|
||||
name: c.name.clone(),
|
||||
context: c.context.clone(),
|
||||
cluster_url: c.server_url.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(cluster_list)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn start_port_forward(
|
||||
request: PortForwardRequest,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<PortForwardResponse, String> {
|
||||
let session_id = uuid::Uuid::now_v7().to_string();
|
||||
|
||||
let session = crate::kube::PortForwardSession::new(
|
||||
session_id.clone(),
|
||||
request.cluster_id.clone(),
|
||||
request.namespace.clone(),
|
||||
request.pod.clone(),
|
||||
None,
|
||||
vec![request.container_port],
|
||||
vec![0],
|
||||
);
|
||||
|
||||
{
|
||||
let mut port_forwards = state.port_forwards.lock().await;
|
||||
port_forwards.insert(session_id.clone(), session);
|
||||
}
|
||||
|
||||
Ok(PortForwardResponse {
|
||||
id: session_id,
|
||||
cluster_id: request.cluster_id,
|
||||
namespace: request.namespace,
|
||||
pod: request.pod,
|
||||
container_port: request.container_port,
|
||||
local_port: 0,
|
||||
status: "Active".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn stop_port_forward(
|
||||
id: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<(), String> {
|
||||
let mut port_forwards = state.port_forwards.lock().await;
|
||||
|
||||
if let Some(session) = port_forwards.get_mut(&id) {
|
||||
session.stop();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Port forward session {id} not found"))
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_port_forwards(
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<Vec<PortForwardResponse>, String> {
|
||||
let port_forwards = state.port_forwards.lock().await;
|
||||
|
||||
let forwards: Vec<PortForwardResponse> = port_forwards
|
||||
.values()
|
||||
.map(|s| PortForwardResponse {
|
||||
id: s.id.clone(),
|
||||
cluster_id: s.cluster_id.clone(),
|
||||
namespace: s.namespace.clone(),
|
||||
pod: s.pod.clone(),
|
||||
container_port: s.ports.first().copied().unwrap_or(0),
|
||||
local_port: s.local_ports.first().copied().unwrap_or(0),
|
||||
status: match s.status {
|
||||
crate::kube::PortForwardStatus::Active => "Active".to_string(),
|
||||
crate::kube::PortForwardStatus::Stopped => "Stopped".to_string(),
|
||||
crate::kube::PortForwardStatus::Error(ref e) => e.clone(),
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(forwards)
|
||||
}
|
||||
|
||||
fn extract_context(_content: &str) -> Result<String, String> {
|
||||
Ok("default".to_string())
|
||||
}
|
||||
|
||||
fn extract_server_url(_content: &str) -> Result<String, String> {
|
||||
Ok("unknown".to_string())
|
||||
}
|
||||
@ -5,5 +5,6 @@ pub mod db;
|
||||
pub mod docs;
|
||||
pub mod image;
|
||||
pub mod integrations;
|
||||
pub mod kube;
|
||||
pub mod shell;
|
||||
pub mod system;
|
||||
|
||||
22
src-tauri/src/kube/client.rs
Normal file
22
src-tauri/src/kube/client.rs
Normal file
@ -0,0 +1,22 @@
|
||||
pub struct ClusterClient {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub context: String,
|
||||
pub server_url: String,
|
||||
}
|
||||
|
||||
impl ClusterClient {
|
||||
pub fn new(
|
||||
id: String,
|
||||
name: String,
|
||||
context: String,
|
||||
server_url: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
context,
|
||||
server_url,
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src-tauri/src/kube/mod.rs
Normal file
7
src-tauri/src/kube/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub mod client;
|
||||
pub mod portforward;
|
||||
pub mod refresh;
|
||||
|
||||
pub use client::ClusterClient;
|
||||
pub use portforward::{PortForwardSession, PortForwardStatus};
|
||||
pub use refresh::RefreshRegistry;
|
||||
47
src-tauri/src/kube/portforward.rs
Normal file
47
src-tauri/src/kube/portforward.rs
Normal file
@ -0,0 +1,47 @@
|
||||
pub struct PortForwardSession {
|
||||
pub id: String,
|
||||
pub cluster_id: String,
|
||||
pub namespace: String,
|
||||
pub pod: String,
|
||||
pub container: Option<String>,
|
||||
pub ports: Vec<u16>,
|
||||
pub local_ports: Vec<u16>,
|
||||
pub status: PortForwardStatus,
|
||||
}
|
||||
|
||||
pub enum PortForwardStatus {
|
||||
Active,
|
||||
Stopped,
|
||||
Error(String),
|
||||
}
|
||||
|
||||
impl PortForwardSession {
|
||||
pub fn new(
|
||||
id: String,
|
||||
cluster_id: String,
|
||||
namespace: String,
|
||||
pod: String,
|
||||
container: Option<String>,
|
||||
ports: Vec<u16>,
|
||||
local_ports: Vec<u16>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
cluster_id,
|
||||
namespace,
|
||||
pod,
|
||||
container,
|
||||
ports,
|
||||
local_ports,
|
||||
status: PortForwardStatus::Active,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
self.status = PortForwardStatus::Stopped;
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> bool {
|
||||
matches!(self.status, PortForwardStatus::Active)
|
||||
}
|
||||
}
|
||||
35
src-tauri/src/kube/refresh.rs
Normal file
35
src-tauri/src/kube/refresh.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use std::collections::HashMap;
|
||||
use tokio::sync::RwLock;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct RefreshRegistry {
|
||||
domains: HashMap<String, Domain>,
|
||||
}
|
||||
|
||||
impl Default for RefreshRegistry {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Domain {
|
||||
pub name: String,
|
||||
pub refresh_interval: std::time::Duration,
|
||||
pub data: Arc<RwLock<HashMap<String, serde_json::Value>>>,
|
||||
}
|
||||
|
||||
impl RefreshRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
domains: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn register_domain(&mut self, domain: Domain) {
|
||||
self.domains.insert(domain.name.clone(), domain);
|
||||
}
|
||||
|
||||
pub async fn get_domain(&self, name: &str) -> Option<&Domain> {
|
||||
self.domains.get(name)
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ pub mod commands;
|
||||
pub mod db;
|
||||
pub mod docs;
|
||||
pub mod integrations;
|
||||
pub mod kube;
|
||||
pub mod mcp;
|
||||
pub mod ollama;
|
||||
pub mod pii;
|
||||
@ -40,6 +41,9 @@ pub fn run() {
|
||||
integration_webviews: Arc::new(Mutex::new(std::collections::HashMap::new())),
|
||||
mcp_connections: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||
pending_approvals: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||
clusters: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||
port_forwards: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||
refresh_registry: Arc::new(tokio::sync::Mutex::new(crate::kube::RefreshRegistry::new())),
|
||||
};
|
||||
let stronghold_salt = format!(
|
||||
"tftsr-stronghold-salt-v1-{:x}",
|
||||
@ -170,6 +174,13 @@ pub fn run() {
|
||||
commands::shell::respond_to_shell_approval,
|
||||
commands::shell::list_command_executions,
|
||||
commands::shell::check_kubectl_installed,
|
||||
// Kubernetes Management
|
||||
commands::kube::add_cluster,
|
||||
commands::kube::remove_cluster,
|
||||
commands::kube::list_clusters,
|
||||
commands::kube::start_port_forward,
|
||||
commands::kube::stop_port_forward,
|
||||
commands::kube::list_port_forwards,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("Error running Troubleshooting and RCA Assistant application");
|
||||
|
||||
@ -91,6 +91,12 @@ pub struct AppState {
|
||||
/// Pending shell command approvals: approval_id -> response channel
|
||||
pub pending_approvals:
|
||||
Arc<TokioMutex<HashMap<String, tokio::sync::oneshot::Sender<ApprovalResponse>>>>,
|
||||
/// Kubernetes cluster clients: cluster_id -> client
|
||||
pub clusters: Arc<TokioMutex<HashMap<String, crate::kube::ClusterClient>>>,
|
||||
/// Port forwarding sessions: session_id -> session
|
||||
pub port_forwards: Arc<TokioMutex<HashMap<String, crate::kube::PortForwardSession>>>,
|
||||
/// Refresh registry for domain-based data fetching
|
||||
pub refresh_registry: Arc<TokioMutex<crate::kube::RefreshRegistry>>,
|
||||
}
|
||||
|
||||
/// Determine the application data directory.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user