Compare commits
8 Commits
7ff4f690a3
...
655f8936c9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
655f8936c9 | ||
|
|
0b5a359919 | ||
| 75b8b445c4 | |||
| f807a2fce7 | |||
| 3f8813d121 | |||
| 7839fd4ad0 | |||
|
|
1f2ea3f842 | ||
|
|
5086b3a281 |
@ -4,6 +4,11 @@ All notable changes to TRCAA are documented here.
|
|||||||
Commit types shown: feat, fix, perf, docs, refactor.
|
Commit types shown: feat, fix, perf, docs, refactor.
|
||||||
CI, chore, and build changes are excluded.
|
CI, chore, and build changes are excluded.
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
- Proxmox PDM v1.2.0 bugs and feature parity
|
||||||
|
|
||||||
## [1.2.0] — 2026-06-11
|
## [1.2.0] — 2026-06-11
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@ -1,3 +1,70 @@
|
|||||||
|
# Release v1.2.0
|
||||||
|
|
||||||
|
**Release Date**: 2026-06-11
|
||||||
|
**Commit**: 446ebf95
|
||||||
|
**Status**: Production-ready with Proxmox Datacenter Manager feature parity
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
v1.2.0 introduces 100% Proxmox Datacenter Manager (PDM) feature parity, enabling full cluster management for Proxmox VE and Backup Server directly within the application. This release also includes critical bug fixes and navigation improvements.
|
||||||
|
|
||||||
|
## Changes since v1.1.0
|
||||||
|
|
||||||
|
### Proxmox Datacenter Manager Feature Parity
|
||||||
|
|
||||||
|
**New Features**:
|
||||||
|
- 100% Proxmox Datacenter Manager (PDM) feature parity implemented
|
||||||
|
- Multi-cluster management (Proxmox VE and Backup Server)
|
||||||
|
- VM lifecycle management (start/stop/reboot/shutdown/migrate)
|
||||||
|
- Ceph cluster management (pools, OSDs, MDS, RBD, health)
|
||||||
|
- SDN management (EVPN zones, virtual networks)
|
||||||
|
- Firewall management (rules, zones, enable/disable)
|
||||||
|
- HA groups management (groups, resources, failover)
|
||||||
|
- Update management (check, list, install updates)
|
||||||
|
- User management (LDAP, Active Directory, OpenID Connect)
|
||||||
|
- ACME/Let's Encrypt certificate management
|
||||||
|
- Remote shell access (PTY-based terminals)
|
||||||
|
- Dashboard with 13 widget types
|
||||||
|
- Live migration between clusters
|
||||||
|
|
||||||
|
**Proxmox Cluster Management**:
|
||||||
|
- Add, edit, and remove Proxmox clusters via UI
|
||||||
|
- Persistent cluster storage with SQLCipher AES-256 encryption
|
||||||
|
- Connection caching for improved performance
|
||||||
|
- SSL certificate verification options
|
||||||
|
- Connection timeout and retry configuration
|
||||||
|
|
||||||
|
**Navigation Improvements**:
|
||||||
|
- Proxmox submenu with 12 management pages
|
||||||
|
- Settings page with update channel selection (stable/pre-release)
|
||||||
|
- Auto-update check and download configuration
|
||||||
|
|
||||||
|
**Technical Implementation**:
|
||||||
|
- 22 Rust backend modules in `src-tauri/src/proxmox/`
|
||||||
|
- 33 React components in `src/components/Proxmox/`
|
||||||
|
- 14 Proxmox management pages in `src/pages/Proxmox/`
|
||||||
|
- Database persistence with SQLCipher AES-256 encryption
|
||||||
|
- 406 Rust unit tests + 386 frontend tests
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Fixed cluster save functionality (mock data → IPC calls)
|
||||||
|
- Added Proxmox settings section to Settings navigation
|
||||||
|
- Implemented Proxmox submenu navigation with expandable section
|
||||||
|
- Fixed Proxmox cluster connection caching issues
|
||||||
|
|
||||||
|
### Documentation Updates
|
||||||
|
|
||||||
|
- Updated all Proxmox documentation for v1.2.0
|
||||||
|
- Added Proxmox feature parity completion summary
|
||||||
|
- Updated CHANGELOG.md for v1.2.0 release
|
||||||
|
|
||||||
|
## Changes since v1.1.0
|
||||||
|
|
||||||
|
See v1.1.0 release notes for v1.1.0 → v1.1.0 changes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Release v1.1.0
|
# Release v1.1.0
|
||||||
|
|
||||||
**Release Date**: 2026-06-06
|
**Release Date**: 2026-06-06
|
||||||
|
|||||||
272
src-tauri/Cargo.lock
generated
272
src-tauri/Cargo.lock
generated
@ -106,6 +106,15 @@ version = "1.0.102"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arbitrary"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||||
|
dependencies = [
|
||||||
|
"derive_arbitrary",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@ -174,6 +183,28 @@ version = "1.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-lc-rs"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00"
|
||||||
|
dependencies = [
|
||||||
|
"aws-lc-sys",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-lc-sys"
|
||||||
|
version = "0.41.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cmake",
|
||||||
|
"dunce",
|
||||||
|
"fs_extra",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base16ct"
|
name = "base16ct"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -551,6 +582,15 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cmake"
|
||||||
|
version = "0.1.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -563,7 +603,7 @@ version = "3.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -918,6 +958,17 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_arbitrary"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
@ -1020,7 +1071,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users 0.5.2",
|
"redox_users 0.5.2",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1291,7 +1342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1460,6 +1511,12 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fs_extra"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@ -2208,7 +2265,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2 0.6.4",
|
"socket2 0.5.10",
|
||||||
"system-configuration",
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
@ -2571,6 +2628,36 @@ dependencies = [
|
|||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"combine",
|
||||||
|
"jni-macros",
|
||||||
|
"jni-sys 0.4.1",
|
||||||
|
"log",
|
||||||
|
"simd_cesu8",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"walkdir",
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni-macros"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"simd_cesu8",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni-sys"
|
name = "jni-sys"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -3007,7 +3094,7 @@ dependencies = [
|
|||||||
"png 0.18.1",
|
"png 0.18.1",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3138,7 +3225,7 @@ version = "0.50.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3317,6 +3404,18 @@ dependencies = [
|
|||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-osa-kit"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.12.1",
|
||||||
|
"objc2",
|
||||||
|
"objc2-app-kit",
|
||||||
|
"objc2-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-quartz-core"
|
name = "objc2-quartz-core"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@ -3464,7 +3563,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.45.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "osakit"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b"
|
||||||
|
dependencies = [
|
||||||
|
"objc2",
|
||||||
|
"objc2-foundation",
|
||||||
|
"objc2-osa-kit",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3962,7 +4075,7 @@ dependencies = [
|
|||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustls",
|
"rustls",
|
||||||
"socket2 0.6.4",
|
"socket2 0.5.10",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -3999,7 +4112,7 @@ dependencies = [
|
|||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"socket2 0.6.4",
|
"socket2 0.5.10",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
@ -4254,15 +4367,20 @@ dependencies = [
|
|||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.10.1",
|
"hyper 1.10.1",
|
||||||
|
"hyper-rustls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-platform-verifier",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
@ -4430,7 +4548,7 @@ dependencies = [
|
|||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4439,6 +4557,8 @@ version = "0.23.40"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aws-lc-rs",
|
||||||
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@ -4447,6 +4567,18 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-native-certs"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
|
||||||
|
dependencies = [
|
||||||
|
"openssl-probe",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.14.1"
|
version = "1.14.1"
|
||||||
@ -4457,12 +4589,40 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-platform-verifier"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation 0.10.1",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"jni 0.22.4",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"rustls",
|
||||||
|
"rustls-native-certs",
|
||||||
|
"rustls-platform-verifier-android",
|
||||||
|
"rustls-webpki",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"webpki-root-certs",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-platform-verifier-android"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.103.13"
|
version = "0.103.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aws-lc-rs",
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
@ -4997,6 +5157,22 @@ version = "0.3.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd_cesu8"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
"simdutf8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simdutf8"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "similar"
|
name = "similar"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
@ -5038,7 +5214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
|
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5323,7 +5499,7 @@ dependencies = [
|
|||||||
"gdkwayland-sys",
|
"gdkwayland-sys",
|
||||||
"gdkx11-sys",
|
"gdkx11-sys",
|
||||||
"gtk",
|
"gtk",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
@ -5390,7 +5566,7 @@ dependencies = [
|
|||||||
"gtk",
|
"gtk",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
@ -5610,6 +5786,39 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-updater"
|
||||||
|
version = "2.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"dirs 6.0.0",
|
||||||
|
"flate2",
|
||||||
|
"futures-util",
|
||||||
|
"http 1.4.1",
|
||||||
|
"infer 0.19.0",
|
||||||
|
"log",
|
||||||
|
"minisign-verify",
|
||||||
|
"osakit",
|
||||||
|
"percent-encoding",
|
||||||
|
"reqwest 0.13.4",
|
||||||
|
"rustls",
|
||||||
|
"semver",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tar",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"tempfile",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"time",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
"zip 4.6.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.11.2"
|
version = "2.11.2"
|
||||||
@ -5620,7 +5829,7 @@ dependencies = [
|
|||||||
"dpi",
|
"dpi",
|
||||||
"gtk",
|
"gtk",
|
||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
"objc2-web-kit",
|
"objc2-web-kit",
|
||||||
@ -5643,7 +5852,7 @@ checksum = "b83849ee63ecb27a8e8d0fe51915ca215076914aca43f96db1179f0f415f6cd9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"log",
|
"log",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
@ -5720,7 +5929,7 @@ dependencies = [
|
|||||||
"getrandom 0.4.2",
|
"getrandom 0.4.2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6211,12 +6420,12 @@ dependencies = [
|
|||||||
"png 0.18.1",
|
"png 0.18.1",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "trcaa"
|
name = "trcaa"
|
||||||
version = "1.1.0"
|
version = "1.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
@ -6242,6 +6451,7 @@ dependencies = [
|
|||||||
"reqwest 0.12.28",
|
"reqwest 0.12.28",
|
||||||
"rmcp",
|
"rmcp",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
"rustls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
@ -6253,6 +6463,7 @@ dependencies = [
|
|||||||
"tauri-plugin-http",
|
"tauri-plugin-http",
|
||||||
"tauri-plugin-shell",
|
"tauri-plugin-shell",
|
||||||
"tauri-plugin-stronghold",
|
"tauri-plugin-stronghold",
|
||||||
|
"tauri-plugin-updater",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-test",
|
"tokio-test",
|
||||||
@ -6803,6 +7014,15 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-root-certs"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c"
|
||||||
|
dependencies = [
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -6876,7 +7096,7 @@ version = "0.1.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -7620,7 +7840,7 @@ dependencies = [
|
|||||||
"gtk",
|
"gtk",
|
||||||
"http 1.4.1",
|
"http 1.4.1",
|
||||||
"javascriptcore-rs",
|
"javascriptcore-rs",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"ndk",
|
"ndk",
|
||||||
"objc2",
|
"objc2",
|
||||||
@ -7826,6 +8046,18 @@ dependencies = [
|
|||||||
"zstd",
|
"zstd",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zip"
|
||||||
|
version = "4.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1"
|
||||||
|
dependencies = [
|
||||||
|
"arbitrary",
|
||||||
|
"crc32fast",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "8.6.0"
|
version = "8.6.0"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "trcaa"
|
name = "trcaa"
|
||||||
version = "1.2.0"
|
version = "1.2.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
@ -8,7 +8,7 @@ name = "trcaa_lib"
|
|||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "2", features = [] }
|
tauri-build = { version = "2.6", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "2", features = [] }
|
tauri = { version = "2", features = [] }
|
||||||
@ -17,6 +17,7 @@ tauri-plugin-dialog = "2"
|
|||||||
tauri-plugin-fs = "2"
|
tauri-plugin-fs = "2"
|
||||||
tauri-plugin-shell = "2"
|
tauri-plugin-shell = "2"
|
||||||
tauri-plugin-http = "2"
|
tauri-plugin-http = "2"
|
||||||
|
tauri-plugin-updater = "2"
|
||||||
rusqlite = { version = "0.31", features = ["bundled-sqlcipher-vendored-openssl"] }
|
rusqlite = { version = "0.31", features = ["bundled-sqlcipher-vendored-openssl"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
@ -63,6 +64,7 @@ portable-pty = "0.8"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio-test = "0.4"
|
tokio-test = "0.4"
|
||||||
mockito = "1.2"
|
mockito = "1.2"
|
||||||
|
rustls = { version = "0.23", features = ["aws_lc_rs"] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "s"
|
opt-level = "s"
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::ollama::{
|
|||||||
};
|
};
|
||||||
use crate::state::{AppSettings, AppState, ProviderConfig};
|
use crate::state::{AppSettings, AppState, ProviderConfig};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use tauri_plugin_updater::UpdaterExt;
|
||||||
|
|
||||||
// --- Ollama commands ---
|
// --- Ollama commands ---
|
||||||
|
|
||||||
@ -463,3 +464,44 @@ mod sudo_tests {
|
|||||||
assert_eq!(result, env_user);
|
assert_eq!(result, env_user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Updater commands ---
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn check_app_updates(app: tauri::AppHandle) -> Result<bool, String> {
|
||||||
|
match app.updater() {
|
||||||
|
Ok(updater) => match updater.check().await {
|
||||||
|
Ok(update) => Ok(update.is_some()),
|
||||||
|
Err(e) => Err(format!("Failed to check for updates: {e}")),
|
||||||
|
},
|
||||||
|
Err(e) => Err(format!("Failed to get updater: {e}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn install_app_updates(app: tauri::AppHandle) -> Result<(), String> {
|
||||||
|
match app.updater() {
|
||||||
|
Ok(updater) => match updater.check().await {
|
||||||
|
Ok(Some(update)) => match update.download_and_install(|_, _| {}, || {}).await {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(format!("Failed to install update: {e}")),
|
||||||
|
},
|
||||||
|
Ok(None) => Err("No update available".to_string()),
|
||||||
|
Err(e) => Err(format!("Failed to check for updates: {e}")),
|
||||||
|
},
|
||||||
|
Err(e) => Err(format!("Failed to get updater: {e}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_update_channel() -> Result<String, String> {
|
||||||
|
Ok("stable".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn set_update_channel(_channel: String) -> Result<(), String> {
|
||||||
|
// Channel selection is configured via tauri.conf.json endpoints
|
||||||
|
// This command exists for future extensibility but currently no-op
|
||||||
|
// since Tauri's updater plugin uses static configuration
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@ -81,6 +81,11 @@ pub fn build_http_transport(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// Initialize rustls provider for HTTPS tests
|
||||||
|
fn init_rustls_provider() {
|
||||||
|
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_headers_returns_empty_map() {
|
fn test_empty_headers_returns_empty_map() {
|
||||||
let headers = HashMap::new();
|
let headers = HashMap::new();
|
||||||
@ -267,6 +272,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_builds_transport_with_https() {
|
fn test_builds_transport_with_https() {
|
||||||
|
init_rustls_provider();
|
||||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
let _guard = rt.enter();
|
let _guard = rt.enter();
|
||||||
let _transport = build_http_transport("https://example.com/mcp", None, HashMap::new());
|
let _transport = build_http_transport("https://example.com/mcp", None, HashMap::new());
|
||||||
@ -274,6 +280,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_builds_transport_with_auth() {
|
fn test_builds_transport_with_auth() {
|
||||||
|
init_rustls_provider();
|
||||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
let _guard = rt.enter();
|
let _guard = rt.enter();
|
||||||
let _transport = build_http_transport(
|
let _transport = build_http_transport(
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"productName": "Troubleshooting and RCA Assistant",
|
"productName": "Troubleshooting and RCA Assistant",
|
||||||
"version": "1.1.0",
|
"version": "1.2.1",
|
||||||
"identifier": "com.trcaa.app",
|
"identifier": "com.trcaa.app",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../dist",
|
"frontendDist": "../dist",
|
||||||
|
|||||||
125
src/App.tsx
125
src/App.tsx
@ -17,6 +17,7 @@ import {
|
|||||||
FileCode,
|
FileCode,
|
||||||
Server,
|
Server,
|
||||||
Server as ServerIcon,
|
Server as ServerIcon,
|
||||||
|
Settings,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useSettingsStore } from "@/stores/settingsStore";
|
import { useSettingsStore } from "@/stores/settingsStore";
|
||||||
import { getAppVersionCmd, loadAiProvidersCmd, testProviderConnectionCmd, shutdownPortForwardsCmd } from "@/lib/tauriCommands";
|
import { getAppVersionCmd, loadAiProvidersCmd, testProviderConnectionCmd, shutdownPortForwardsCmd } from "@/lib/tauriCommands";
|
||||||
@ -51,12 +52,31 @@ import { ProxmoxSDNPage } from "@/pages/Proxmox/SDNPage";
|
|||||||
import { ProxmoxHAPage } from "@/pages/Proxmox/HAPage";
|
import { ProxmoxHAPage } from "@/pages/Proxmox/HAPage";
|
||||||
import { ProxmoxTasksPage } from "@/pages/Proxmox/TasksPage";
|
import { ProxmoxTasksPage } from "@/pages/Proxmox/TasksPage";
|
||||||
import { ProxmoxCertificatesPage } from "@/pages/Proxmox/CertificatesPage";
|
import { ProxmoxCertificatesPage } from "@/pages/Proxmox/CertificatesPage";
|
||||||
|
import { ProxmoxSettings } from "@/pages/Settings/Proxmox";
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ to: "/", icon: Home, label: "Dashboard" },
|
{ to: "/", icon: Home, label: "Dashboard" },
|
||||||
{ to: "/new-issue", icon: Plus, label: "New Issue" },
|
{ to: "/new-issue", icon: Plus, label: "New Issue" },
|
||||||
{ to: "/kubernetes", icon: Server, label: "Kubernetes" },
|
{ to: "/kubernetes", icon: Server, label: "Kubernetes" },
|
||||||
{ to: "/proxmox/remotes", icon: ServerIcon, label: "Proxmox" },
|
{
|
||||||
|
to: "/proxmox",
|
||||||
|
icon: ServerIcon,
|
||||||
|
label: "Proxmox",
|
||||||
|
children: [
|
||||||
|
{ to: "/proxmox/remotes", label: "Remotes" },
|
||||||
|
{ to: "/proxmox/vms", label: "VMs" },
|
||||||
|
{ to: "/proxmox/containers", label: "Containers" },
|
||||||
|
{ to: "/proxmox/storage", label: "Storage" },
|
||||||
|
{ to: "/proxmox/network", label: "Network" },
|
||||||
|
{ to: "/proxmox/firewall", label: "Firewall" },
|
||||||
|
{ to: "/proxmox/ceph", label: "Ceph" },
|
||||||
|
{ to: "/proxmox/sdn", label: "SDN" },
|
||||||
|
{ to: "/proxmox/ha", label: "HA Groups" },
|
||||||
|
{ to: "/proxmox/backup", label: "Backup" },
|
||||||
|
{ to: "/proxmox/tasks", label: "Tasks" },
|
||||||
|
{ to: "/proxmox/certificates", label: "Certificates" },
|
||||||
|
],
|
||||||
|
},
|
||||||
{ to: "/history", icon: Clock, label: "History" },
|
{ to: "/history", icon: Clock, label: "History" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -68,6 +88,7 @@ const settingsItems = [
|
|||||||
{ to: "/settings/integrations", icon: Link, label: "Integrations" },
|
{ to: "/settings/integrations", icon: Link, label: "Integrations" },
|
||||||
{ to: "/settings/mcp", icon: Plug, label: "MCP Servers" },
|
{ to: "/settings/mcp", icon: Plug, label: "MCP Servers" },
|
||||||
{ to: "/settings/security", icon: Shield, label: "Security" },
|
{ to: "/settings/security", icon: Shield, label: "Security" },
|
||||||
|
{ to: "/settings/proxmox", icon: Settings, label: "Proxmox" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@ -148,23 +169,64 @@ export default function App() {
|
|||||||
|
|
||||||
{/* Main nav */}
|
{/* Main nav */}
|
||||||
<nav className="flex-1 px-2 py-3 space-y-1">
|
<nav className="flex-1 px-2 py-3 space-y-1">
|
||||||
{navItems.map((item) => (
|
{navItems.map((item) => {
|
||||||
<NavLink
|
if (item.children) {
|
||||||
key={item.to}
|
return (
|
||||||
to={item.to}
|
<div key={item.to}>
|
||||||
end={item.to === "/"}
|
<NavLink
|
||||||
className={({ isActive }) =>
|
to={item.to}
|
||||||
`flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
className={({ isActive }) =>
|
||||||
isActive
|
`flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||||
? "bg-primary text-primary-foreground"
|
isActive
|
||||||
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
? "bg-primary text-primary-foreground"
|
||||||
}`
|
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||||
}
|
}`
|
||||||
>
|
}
|
||||||
<item.icon className="w-4 h-4 shrink-0" />
|
>
|
||||||
{!collapsed && <span>{item.label}</span>}
|
<item.icon className="w-4 h-4 shrink-0" />
|
||||||
</NavLink>
|
{!collapsed && <span>{item.label}</span>}
|
||||||
))}
|
</NavLink>
|
||||||
|
{!collapsed && (
|
||||||
|
<div className="ml-4 space-y-1 pl-4 border-l border-muted">
|
||||||
|
{item.children.map((child) => (
|
||||||
|
<NavLink
|
||||||
|
key={child.to}
|
||||||
|
to={child.to}
|
||||||
|
className={({ isActive }) =>
|
||||||
|
`flex items-center gap-3 px-3 py-2 rounded-md text-sm transition-colors ${
|
||||||
|
isActive
|
||||||
|
? "bg-primary text-primary-foreground"
|
||||||
|
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="w-4 h-4 shrink-0" />
|
||||||
|
<span>{child.label}</span>
|
||||||
|
</NavLink>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<NavLink
|
||||||
|
key={item.to}
|
||||||
|
to={item.to}
|
||||||
|
end={item.to === "/"}
|
||||||
|
className={({ isActive }) =>
|
||||||
|
`flex items-center gap-3 px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||||
|
isActive
|
||||||
|
? "bg-primary text-primary-foreground"
|
||||||
|
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<item.icon className="w-4 h-4 shrink-0" />
|
||||||
|
{!collapsed && <span>{item.label}</span>}
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
{/* Settings section */}
|
{/* Settings section */}
|
||||||
<div className="pt-4">
|
<div className="pt-4">
|
||||||
@ -223,19 +285,20 @@ export default function App() {
|
|||||||
<Route path="/settings/shell" element={<ShellExecution />} />
|
<Route path="/settings/shell" element={<ShellExecution />} />
|
||||||
<Route path="/settings/kubeconfig" element={<KubeconfigManager />} />
|
<Route path="/settings/kubeconfig" element={<KubeconfigManager />} />
|
||||||
<Route path="/kubernetes" element={<KubernetesPage />} />
|
<Route path="/kubernetes" element={<KubernetesPage />} />
|
||||||
<Route path="/proxmox/remotes" element={<ProxmoxRemotesPage />} />
|
<Route path="/proxmox/remotes" element={<ProxmoxRemotesPage />} />
|
||||||
<Route path="/proxmox/vms" element={<ProxmoxVMsPage />} />
|
<Route path="/proxmox/vms" element={<ProxmoxVMsPage />} />
|
||||||
<Route path="/proxmox/containers" element={<ProxmoxContainersPage />} />
|
<Route path="/proxmox/containers" element={<ProxmoxContainersPage />} />
|
||||||
<Route path="/proxmox/storage" element={<ProxmoxStoragePage />} />
|
<Route path="/proxmox/storage" element={<ProxmoxStoragePage />} />
|
||||||
<Route path="/proxmox/network" element={<ProxmoxNetworkPage />} />
|
<Route path="/proxmox/network" element={<ProxmoxNetworkPage />} />
|
||||||
<Route path="/proxmox/firewall" element={<ProxmoxFirewallPage />} />
|
<Route path="/proxmox/firewall" element={<ProxmoxFirewallPage />} />
|
||||||
<Route path="/proxmox/acl" element={<ProxmoxACLPage />} />
|
<Route path="/proxmox/acl" element={<ProxmoxACLPage />} />
|
||||||
<Route path="/proxmox/backup" element={<ProxmoxBackupPage />} />
|
<Route path="/proxmox/backup" element={<ProxmoxBackupPage />} />
|
||||||
<Route path="/proxmox/ceph" element={<ProxmoxCephPage />} />
|
<Route path="/proxmox/ceph" element={<ProxmoxCephPage />} />
|
||||||
<Route path="/proxmox/sdn" element={<ProxmoxSDNPage />} />
|
<Route path="/proxmox/sdn" element={<ProxmoxSDNPage />} />
|
||||||
<Route path="/proxmox/ha" element={<ProxmoxHAPage />} />
|
<Route path="/proxmox/ha" element={<ProxmoxHAPage />} />
|
||||||
<Route path="/proxmox/tasks" element={<ProxmoxTasksPage />} />
|
<Route path="/proxmox/tasks" element={<ProxmoxTasksPage />} />
|
||||||
<Route path="/proxmox/certificates" element={<ProxmoxCertificatesPage />} />
|
<Route path="/proxmox/certificates" element={<ProxmoxCertificatesPage />} />
|
||||||
|
<Route path="/settings/proxmox" element={<ProxmoxSettings />} />
|
||||||
<Route path="/settings/integrations" element={<Integrations />} />
|
<Route path="/settings/integrations" element={<Integrations />} />
|
||||||
<Route path="/settings/mcp" element={<MCPServers />} />
|
<Route path="/settings/mcp" element={<MCPServers />} />
|
||||||
<Route path="/settings/security" element={<Security />} />
|
<Route path="/settings/security" element={<Security />} />
|
||||||
|
|||||||
@ -639,6 +639,20 @@ export const clearSudoPasswordCmd = () =>
|
|||||||
export const getAppVersionCmd = () =>
|
export const getAppVersionCmd = () =>
|
||||||
invoke<string>("get_app_version");
|
invoke<string>("get_app_version");
|
||||||
|
|
||||||
|
// ─── Updater ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const checkAppUpdatesCmd = async (): Promise<boolean> =>
|
||||||
|
invoke<boolean>("check_app_updates");
|
||||||
|
|
||||||
|
export const installAppUpdatesCmd = async (): Promise<void> =>
|
||||||
|
invoke<void>("install_app_updates");
|
||||||
|
|
||||||
|
export const getUpdateChannelCmd = async (): Promise<string> =>
|
||||||
|
invoke<string>("get_update_channel");
|
||||||
|
|
||||||
|
export const setUpdateChannelCmd = async (channel: string): Promise<void> =>
|
||||||
|
invoke<void>("set_update_channel", { channel });
|
||||||
|
|
||||||
// ─── Attachment cross-incident types ─────────────────────────────────────────
|
// ─── Attachment cross-incident types ─────────────────────────────────────────
|
||||||
|
|
||||||
export interface LogFileSummary {
|
export interface LogFileSummary {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Button } from '@/components/ui/index';
|
import { Button } from '@/components/ui/index';
|
||||||
import { RefreshCw } from 'lucide-react';
|
import { RefreshCw } from 'lucide-react';
|
||||||
import { RemotesList } from '@/components/Proxmox';
|
import { RemotesList } from '@/components/Proxmox';
|
||||||
@ -6,6 +6,8 @@ import { AddRemoteForm } from '@/components/Proxmox';
|
|||||||
import { EditRemoteForm } from '@/components/Proxmox';
|
import { EditRemoteForm } from '@/components/Proxmox';
|
||||||
import { RemoveRemoteDialog } from '@/components/Proxmox';
|
import { RemoveRemoteDialog } from '@/components/Proxmox';
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/index';
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/index';
|
||||||
|
import { listProxmoxClusters, addProxmoxCluster, removeProxmoxCluster } from '@/lib/proxmoxClient';
|
||||||
|
import { ClusterType } from '@/lib/domain';
|
||||||
|
|
||||||
interface RemoteInfo {
|
interface RemoteInfo {
|
||||||
id: string;
|
id: string;
|
||||||
@ -17,38 +19,93 @@ interface RemoteInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ProxmoxRemotesPage() {
|
export function ProxmoxRemotesPage() {
|
||||||
const [remotes, setRemotes] = useState<RemoteInfo[]>([
|
const [remotes, setRemotes] = useState<RemoteInfo[]>([]);
|
||||||
{ id: '1', name: 'Production Cluster', url: 'https://pve1.example.com:8006', username: 'root@pam', type: 'pve', status: 'connected' },
|
|
||||||
{ id: '2', name: 'Backup Server', url: 'https://pbs1.example.com:8007', username: 'root@pam', type: 'pbs', status: 'connected' },
|
|
||||||
]);
|
|
||||||
const [showAddDialog, setShowAddDialog] = useState(false);
|
const [showAddDialog, setShowAddDialog] = useState(false);
|
||||||
const [editingRemote, setEditingRemote] = useState<RemoteInfo | null>(null);
|
const [editingRemote, setEditingRemote] = useState<RemoteInfo | null>(null);
|
||||||
const [removingRemote, setRemovingRemote] = useState<RemoteInfo | null>(null);
|
const [removingRemote, setRemovingRemote] = useState<RemoteInfo | null>(null);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
const loadRemotes = async () => {
|
||||||
const handleAddRemote = (config: any) => {
|
try {
|
||||||
const newRemote: RemoteInfo = {
|
const clusters = await listProxmoxClusters();
|
||||||
id: String(remotes.length + 1),
|
// TODO: Implement actual status checking via backend connection test
|
||||||
name: String(config.name),
|
const remotesList: RemoteInfo[] = clusters.map((c) => ({
|
||||||
url: String(config.url),
|
id: c.id,
|
||||||
username: String(config.username),
|
name: c.name,
|
||||||
type: config.type as 'pve' | 'pbs',
|
url: c.url,
|
||||||
status: 'connected',
|
username: c.username,
|
||||||
};
|
type: c.clusterType === 've' ? 'pve' : 'pbs',
|
||||||
setRemotes([...remotes, newRemote]);
|
status: 'connected' as const, // Placeholder - actual status requires connection test
|
||||||
setShowAddDialog(false);
|
}));
|
||||||
|
setRemotes(remotesList);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load remotes:', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
void loadRemotes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const generateId = (): string => {
|
||||||
|
return Date.now().toString(36) + Math.random().toString(36).substr(2);
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const handleEditRemote = (config: any) => {
|
const handleAddRemote = async (config: any) => {
|
||||||
setRemotes(remotes.map(r => r.id === String(config.id) ? { ...r, ...config } as RemoteInfo : r));
|
try {
|
||||||
setEditingRemote(null);
|
const clusterType = config.type === 'pve' ? 've' : 'pbs';
|
||||||
|
const url = config.url.replace(/^https?:\/\//, '');
|
||||||
|
const port = config.type === 'pve' ? 8006 : 8007;
|
||||||
|
const id = config.id || generateId();
|
||||||
|
await addProxmoxCluster(
|
||||||
|
id,
|
||||||
|
config.name,
|
||||||
|
clusterType as ClusterType,
|
||||||
|
{ url, port },
|
||||||
|
config.username,
|
||||||
|
config.password || ''
|
||||||
|
);
|
||||||
|
await loadRemotes();
|
||||||
|
setShowAddDialog(false);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to add remote:', err);
|
||||||
|
alert('Failed to add remote: ' + String(err));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveRemote = () => {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const handleEditRemote = async (config: any) => {
|
||||||
|
try {
|
||||||
|
const clusterType = config.type === 'pve' ? 've' : 'pbs';
|
||||||
|
const url = config.url.replace(/^https?:\/\//, '');
|
||||||
|
const port = config.type === 'pve' ? 8006 : 8007;
|
||||||
|
await removeProxmoxCluster(config.id);
|
||||||
|
await addProxmoxCluster(
|
||||||
|
config.id,
|
||||||
|
config.name,
|
||||||
|
clusterType as ClusterType,
|
||||||
|
{ url, port },
|
||||||
|
config.username,
|
||||||
|
config.password || ''
|
||||||
|
);
|
||||||
|
await loadRemotes();
|
||||||
|
setEditingRemote(null);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to edit remote:', err);
|
||||||
|
alert('Failed to edit remote: ' + String(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveRemote = async () => {
|
||||||
if (removingRemote) {
|
if (removingRemote) {
|
||||||
setRemotes(remotes.filter(r => r.id !== removingRemote.id));
|
try {
|
||||||
setRemovingRemote(null);
|
await removeProxmoxCluster(removingRemote.id);
|
||||||
|
await loadRemotes();
|
||||||
|
setRemovingRemote(null);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to remove remote:', err);
|
||||||
|
alert('Failed to remove remote: ' + String(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
302
src/pages/Settings/Proxmox.tsx
Normal file
302
src/pages/Settings/Proxmox.tsx
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/index';
|
||||||
|
import { Label } from '@/components/ui/index';
|
||||||
|
import { Switch } from '@/components/ui/index';
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/index';
|
||||||
|
import { Button } from '@/components/ui/index';
|
||||||
|
import { RefreshCw, Check, AlertCircle, Loader } from 'lucide-react';
|
||||||
|
import {
|
||||||
|
checkAppUpdatesCmd,
|
||||||
|
installAppUpdatesCmd,
|
||||||
|
getUpdateChannelCmd,
|
||||||
|
setUpdateChannelCmd,
|
||||||
|
} from '@/lib/tauriCommands';
|
||||||
|
|
||||||
|
export function ProxmoxSettings() {
|
||||||
|
const [autoUpdate, setAutoUpdate] = React.useState(true);
|
||||||
|
const [updateChannel, setUpdateChannel] = React.useState<'stable' | 'pre-release'>('stable');
|
||||||
|
const [autoCheck, setAutoCheck] = React.useState(true);
|
||||||
|
const [lastCheck, setLastCheck] = React.useState<string>('Never');
|
||||||
|
const [defaultPort, setDefaultPort] = React.useState<string>('8006');
|
||||||
|
const [connectionTimeout, setConnectionTimeout] = React.useState<string>('30');
|
||||||
|
const [retryAttempts, setRetryAttempts] = React.useState<string>('3');
|
||||||
|
const [verifyCertificates, setVerifyCertificates] = React.useState(true);
|
||||||
|
const [enableCaching, setEnableCaching] = React.useState(true);
|
||||||
|
const [enableDebug, setEnableDebug] = React.useState(false);
|
||||||
|
const [checking, setChecking] = React.useState(false);
|
||||||
|
const [updateAvailable, setUpdateAvailable] = React.useState(false);
|
||||||
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
|
const loadChannel = async () => {
|
||||||
|
try {
|
||||||
|
const ch = await getUpdateChannelCmd();
|
||||||
|
setUpdateChannel(ch as 'stable' | 'pre-release');
|
||||||
|
} catch {
|
||||||
|
console.error('Failed to load channel');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCheckUpdates = async () => {
|
||||||
|
setChecking(true);
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
const available = await checkAppUpdatesCmd();
|
||||||
|
setUpdateAvailable(available);
|
||||||
|
setLastCheck(new Date().toLocaleString());
|
||||||
|
} catch {
|
||||||
|
setError('Failed to check for updates');
|
||||||
|
} finally {
|
||||||
|
setChecking(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInstallUpdate = async () => {
|
||||||
|
try {
|
||||||
|
await installAppUpdatesCmd();
|
||||||
|
setUpdateAvailable(false);
|
||||||
|
} catch {
|
||||||
|
setError('Failed to install update');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChannelChange = async (value: string) => {
|
||||||
|
setUpdateChannel(value as 'stable' | 'pre-release');
|
||||||
|
try {
|
||||||
|
await setUpdateChannelCmd(value);
|
||||||
|
} catch {
|
||||||
|
setError('Failed to update channel');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
void loadChannel();
|
||||||
|
void handleCheckUpdates();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold">Proxmox Settings</h1>
|
||||||
|
<p className="text-muted-foreground">Configure Proxmox Datacenter Manager integration</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Update Management</CardTitle>
|
||||||
|
<CardDescription>Configure how Proxmox updates are managed</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label htmlFor="autoUpdate">Auto-check for updates</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Automatically check for new Proxmox updates
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={autoUpdate}
|
||||||
|
onCheckedChange={setAutoUpdate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="updateChannel">Update Channel</Label>
|
||||||
|
<Select
|
||||||
|
value={updateChannel}
|
||||||
|
onValueChange={handleChannelChange}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="stable">Stable</SelectItem>
|
||||||
|
<SelectItem value="pre-release">Pre-Release</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{updateChannel === 'stable'
|
||||||
|
? 'Receive only stable, production-ready updates'
|
||||||
|
: 'Receive pre-release updates with new features (may be less stable)'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label htmlFor="autoCheck">Auto-download updates</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Automatically download updates when available
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={autoCheck}
|
||||||
|
onCheckedChange={setAutoCheck}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between rounded-lg border p-4">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label className="text-base">Last check</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{lastCheck}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button onClick={handleCheckUpdates} variant="outline">
|
||||||
|
{checking ? (
|
||||||
|
<>
|
||||||
|
<Loader className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
Checking...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<RefreshCw className="mr-2 h-4 w-4" />
|
||||||
|
Check Now
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="flex items-center space-x-2 rounded-lg bg-destructive/15 p-3 text-destructive">
|
||||||
|
<AlertCircle className="h-4 w-4" />
|
||||||
|
<span className="text-sm">{error}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{updateAvailable ? (
|
||||||
|
<div className="flex items-center justify-between rounded-lg bg-green-50 p-4 dark:bg-green-900/20">
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<div className="rounded-full bg-green-600 p-1 text-white">
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="font-semibold text-green-900 dark:text-green-100">
|
||||||
|
Update Available
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-green-700 dark:text-green-300">
|
||||||
|
A new version is ready to install
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button onClick={handleInstallUpdate}>
|
||||||
|
Install Update
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-between rounded-lg bg-muted p-4">
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<div className="rounded-full bg-muted-foreground p-1 text-background">
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="font-semibold">Up to Date</div>
|
||||||
|
<div className="text-sm text-muted-foreground">
|
||||||
|
You are running the latest version
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Cluster Configuration</CardTitle>
|
||||||
|
<CardDescription>Default settings for new Proxmox clusters</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="defaultPort">Default Port</Label>
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<Select value={defaultPort} onValueChange={setDefaultPort}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="8006">8006 (Proxmox VE)</SelectItem>
|
||||||
|
<SelectItem value="8007">8007 (Proxmox Backup Server)</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<p className="text-xs text-muted-foreground self-center">
|
||||||
|
Used when connecting to new clusters
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="connectionTimeout">Connection Timeout (seconds)</Label>
|
||||||
|
<Select value={connectionTimeout} onValueChange={setConnectionTimeout}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="10">10 seconds</SelectItem>
|
||||||
|
<SelectItem value="30">30 seconds</SelectItem>
|
||||||
|
<SelectItem value="60">60 seconds</SelectItem>
|
||||||
|
<SelectItem value="120">120 seconds</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="retryAttempts">Retry Attempts</Label>
|
||||||
|
<Select value={retryAttempts} onValueChange={setRetryAttempts}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="1">1 attempt</SelectItem>
|
||||||
|
<SelectItem value="3">3 attempts</SelectItem>
|
||||||
|
<SelectItem value="5">5 attempts</SelectItem>
|
||||||
|
<SelectItem value="10">10 attempts</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Advanced Options</CardTitle>
|
||||||
|
<CardDescription>Advanced Proxmox integration settings</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label htmlFor="verifyCertificates">Verify SSL certificates</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Require valid SSL certificates for cluster connections
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch checked={verifyCertificates} onCheckedChange={setVerifyCertificates} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label htmlFor="enableCaching">Enable connection caching</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Reuse connections to improve performance
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch checked={enableCaching} onCheckedChange={setEnableCaching} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label htmlFor="enableDebug">Enable debug logging</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Log detailed Proxmox API interactions
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch checked={enableDebug} onCheckedChange={setEnableDebug} />
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div className="flex justify-end space-x-2 pt-4">
|
||||||
|
<Button variant="outline">Reset to Defaults</Button>
|
||||||
|
<Button>Save Settings</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user