forked from github-starred/komodo
Compare commits
26 Commits
v2.0.0-dev
...
v2.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0697e812a | ||
|
|
78766463d6 | ||
|
|
0fa1edba2c | ||
|
|
bbd968cac3 | ||
|
|
5f24fc1be3 | ||
|
|
7ecd2b0b0b | ||
|
|
7bf44d2e04 | ||
|
|
24e0672384 | ||
|
|
04f081631f | ||
|
|
b1af956b63 | ||
|
|
370712b29f | ||
|
|
2b6c552964 | ||
|
|
434a1d8ea9 | ||
|
|
0b7f28360f | ||
|
|
3c8ef0ab29 | ||
|
|
930b2423c3 | ||
|
|
546747b5f2 | ||
|
|
c6df866755 | ||
|
|
ea5e684915 | ||
|
|
64db8933de | ||
|
|
7a5580de57 | ||
|
|
b1656bb174 | ||
|
|
559ce103da | ||
|
|
75e278a57b | ||
|
|
430f3ddc34 | ||
|
|
6c30c202e9 |
235
Cargo.lock
generated
235
Cargo.lock
generated
@@ -65,6 +65,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@@ -138,9 +144,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.32"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0"
|
||||
checksum = "93c1f86859c1af3d514fa19e8323147ff10ea98684e6c7b307912509f50e67b2"
|
||||
dependencies = [
|
||||
"compression-codecs",
|
||||
"compression-core",
|
||||
@@ -187,9 +193,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "aws-config"
|
||||
version = "1.8.8"
|
||||
version = "1.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37cf2b6af2a95a20e266782b4f76f1a5e12bf412a9db2de9c1e9123b9d8c0ad8"
|
||||
checksum = "1856b1b48b65f71a4dd940b1c0931f9a7b646d4a924b9828ffefc1454714668a"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -217,9 +223,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-credential-types"
|
||||
version = "1.2.8"
|
||||
version = "1.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf26925f4a5b59eb76722b63c2892b1d70d06fa053c72e4a100ec308c1d47bc"
|
||||
checksum = "86590e57ea40121d47d3f2e131bfd873dea15d78dc2f4604f4734537ad9e56c4"
|
||||
dependencies = [
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-runtime-api",
|
||||
@@ -254,9 +260,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-runtime"
|
||||
version = "1.5.12"
|
||||
version = "1.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa006bb32360ed90ac51203feafb9d02e3d21046e1fd3a450a404b90ea73e5d"
|
||||
checksum = "8fe0fd441565b0b318c76e7206c8d1d0b0166b3e986cf30e890b61feb6192045"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-sigv4",
|
||||
@@ -278,9 +284,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ec2"
|
||||
version = "1.176.0"
|
||||
version = "1.184.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "171b12a84d9c7b43b75bf2ae99e86ce40ff0b5ecc8194a67d547e55c1ad2438e"
|
||||
checksum = "f78a1031a701f3f82e3e9d7087cd09e7ef69bd7e592719521c873d8f02c464d6"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -301,9 +307,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sso"
|
||||
version = "1.86.0"
|
||||
version = "1.89.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a0abbfab841446cce6e87af853a3ba2cc1bc9afcd3f3550dd556c43d434c86d"
|
||||
checksum = "a9c1b1af02288f729e95b72bd17988c009aa72e26dcb59b3200f86d7aea726c9"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -323,9 +329,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ssooidc"
|
||||
version = "1.88.0"
|
||||
version = "1.91.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a68d675582afea0e94d38b6ca9c5aaae4ca14f1d36faa6edb19b42e687e70d7"
|
||||
checksum = "4e8122301558dc7c6c68e878af918880b82ff41897a60c8c4e18e4dc4d93e9f1"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -345,9 +351,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sts"
|
||||
version = "1.88.0"
|
||||
version = "1.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d30990923f4f675523c51eb1c0dec9b752fb267b36a61e83cbc219c9d86da715"
|
||||
checksum = "a0c7808adcff8333eaa76a849e6de926c6ac1a1268b9fd6afe32de9c29ef29d2"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -368,9 +374,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sigv4"
|
||||
version = "1.3.5"
|
||||
version = "1.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bffc03068fbb9c8dd5ce1c6fb240678a5cffb86fb2b7b1985c999c4b83c8df68"
|
||||
checksum = "c35452ec3f001e1f2f6db107b6373f1f48f05ec63ba2c5c9fa91f07dad32af11"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-smithy-http",
|
||||
@@ -401,15 +407,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-http"
|
||||
version = "0.62.4"
|
||||
version = "0.62.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3feafd437c763db26aa04e0cc7591185d0961e64c61885bece0fb9d50ceac671"
|
||||
checksum = "445d5d720c99eed0b4aa674ed00d835d9b1427dd73e04adaf2f94c6b2d6f9fca"
|
||||
dependencies = [
|
||||
"aws-smithy-runtime-api",
|
||||
"aws-smithy-types",
|
||||
"bytes",
|
||||
"bytes-utils",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"http 1.3.1",
|
||||
"http-body 0.4.6",
|
||||
@@ -421,9 +428,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-http-client"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1053b5e587e6fa40ce5a79ea27957b04ba660baa02b28b7436f64850152234f1"
|
||||
checksum = "623254723e8dfd535f566ee7b2381645f8981da086b5c4aa26c0c41582bb1d2c"
|
||||
dependencies = [
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-runtime-api",
|
||||
@@ -440,7 +447,7 @@ dependencies = [
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"rustls 0.21.12",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
@@ -451,9 +458,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-json"
|
||||
version = "0.61.6"
|
||||
version = "0.61.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff418fc8ec5cadf8173b10125f05c2e7e1d46771406187b2c878557d4503390"
|
||||
checksum = "2db31f727935fc63c6eeae8b37b438847639ec330a9161ece694efba257e0c54"
|
||||
dependencies = [
|
||||
"aws-smithy-types",
|
||||
]
|
||||
@@ -479,9 +486,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-runtime"
|
||||
version = "1.9.3"
|
||||
version = "1.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ab99739082da5347660c556689256438defae3bcefd66c52b095905730e404"
|
||||
checksum = "0bbe9d018d646b96c7be063dd07987849862b0e6d07c778aad7d93d1be6c1ef0"
|
||||
dependencies = [
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-http",
|
||||
@@ -503,9 +510,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-runtime-api"
|
||||
version = "1.9.1"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3683c5b152d2ad753607179ed71988e8cfd52964443b4f74fd8e552d0bbfeb46"
|
||||
checksum = "ec7204f9fd94749a7c53b26da1b961b4ac36bf070ef1e0b94bb09f79d4f6c193"
|
||||
dependencies = [
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-types",
|
||||
@@ -520,9 +527,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-types"
|
||||
version = "1.3.3"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f5b3a7486f6690ba25952cabf1e7d75e34d69eaff5081904a47bc79074d6457"
|
||||
checksum = "25f535879a207fce0db74b679cfc3e91a3159c8144d717d55f5832aea9eef46e"
|
||||
dependencies = [
|
||||
"base64-simd",
|
||||
"bytes",
|
||||
@@ -546,18 +553,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-smithy-xml"
|
||||
version = "0.60.11"
|
||||
version = "0.60.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9c34127e8c624bc2999f3b657e749c1393bedc9cd97b92a804db8ced4d2e163"
|
||||
checksum = "eab77cdd036b11056d2a30a7af7b775789fb024bf216acc13884c6c97752ae56"
|
||||
dependencies = [
|
||||
"xmlparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-types"
|
||||
version = "1.3.9"
|
||||
version = "1.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2fd329bf0e901ff3f60425691410c69094dc2a1f34b331f37bfc4e9ac1565a1"
|
||||
checksum = "d79fb68e3d7fe5d4833ea34dc87d2e97d26d3086cb3da660bb6b1f76d98680b6"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-smithy-async",
|
||||
@@ -625,13 +632,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum-extra"
|
||||
version = "0.10.3"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96"
|
||||
checksum = "5136e6c5e7e7978fe23e9876fb924af2c0f84c72127ac6ac17e7c46f457d362c"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http 1.3.1",
|
||||
@@ -639,8 +647,6 @@ dependencies = [
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde_core",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -671,7 +677,7 @@ dependencies = [
|
||||
"hyper 1.7.0",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
@@ -806,9 +812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bollard"
|
||||
version = "0.19.3"
|
||||
version = "0.19.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7646ee90964aa59e9f832a67182791396a19a5b1d76eb17599a8310a7e2e09"
|
||||
checksum = "87a52479c9237eb04047ddb94788c41ca0d26eaff8b697ecfbb4c32f7fdc3b1b"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bollard-stubs",
|
||||
@@ -902,7 +908,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cache"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"tokio",
|
||||
@@ -1019,9 +1025,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.50"
|
||||
version = "4.5.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623"
|
||||
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -1029,9 +1035,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.50"
|
||||
version = "4.5.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0"
|
||||
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1094,7 +1100,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "command"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"komodo_client",
|
||||
"shlex",
|
||||
@@ -1104,9 +1110,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compression-codecs"
|
||||
version = "0.4.31"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23"
|
||||
checksum = "680dc087785c5230f8e8843e2e57ac7c1c90488b6a91b88caa265410568f441b"
|
||||
dependencies = [
|
||||
"compression-core",
|
||||
"flate2",
|
||||
@@ -1115,13 +1121,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compression-core"
|
||||
version = "0.4.29"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb"
|
||||
checksum = "3a9b614a5787ef0c8802a55766480563cb3a93b435898c422ed2a359cf811582"
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"indexmap 2.12.0",
|
||||
@@ -1227,9 +1233,9 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "croner"
|
||||
version = "3.0.0"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c007081651a19b42931f86f7d4f74ee1c2a7d0cd2c6636a81695b5ffd4e9990"
|
||||
checksum = "4aa42bcd3d846ebf66e15bd528d1087f75d1c6c1c66ebff626178a106353c576"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"derive_builder",
|
||||
@@ -1443,7 +1449,7 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
|
||||
|
||||
[[package]]
|
||||
name = "database"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-compression",
|
||||
@@ -1466,7 +1472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
"pem-rfc7468 0.7.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -1732,7 +1738,7 @@ dependencies = [
|
||||
"generic-array",
|
||||
"group",
|
||||
"hkdf",
|
||||
"pem-rfc7468",
|
||||
"pem-rfc7468 0.7.0",
|
||||
"pkcs8",
|
||||
"rand_core 0.6.4",
|
||||
"sec1",
|
||||
@@ -1742,7 +1748,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "encoding"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -1784,7 +1790,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "environment"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"formatting",
|
||||
@@ -1794,7 +1800,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "environment_file"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
@@ -1879,6 +1885,12 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.2"
|
||||
@@ -1890,7 +1902,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "formatting"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"serror",
|
||||
]
|
||||
@@ -2056,7 +2068,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cache",
|
||||
@@ -2127,21 +2139,23 @@ version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.0"
|
||||
@@ -2454,7 +2468,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"hyper 1.7.0",
|
||||
"hyper-util",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
@@ -2688,7 +2702,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "interpolate"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -2793,9 +2807,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jsonwebtoken"
|
||||
version = "10.1.0"
|
||||
version = "10.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d119c6924272d16f0ab9ce41f7aa0bfef9340c00b0bb7ca3dd3b263d4a9150b"
|
||||
checksum = "c76e1c7d7df3e34443b3621b459b066a7b79644f059fc8b2db7070c825fd417e"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"base64 0.22.1",
|
||||
@@ -2810,7 +2824,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_cli"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -2838,7 +2852,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_client"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2874,7 +2888,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_core"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -2921,7 +2935,7 @@ dependencies = [
|
||||
"reqwest",
|
||||
"resolver_api",
|
||||
"response",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"secret_file",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2948,7 +2962,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_periphery"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -2979,7 +2993,7 @@ dependencies = [
|
||||
"periphery_client",
|
||||
"portable-pty",
|
||||
"resolver_api",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"secret_file",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -3069,7 +3083,7 @@ checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
|
||||
[[package]]
|
||||
name = "logger"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -3300,7 +3314,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"rand 0.8.5",
|
||||
"rustc_version_runtime",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
@@ -3361,7 +3375,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "noise"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -3369,7 +3383,7 @@ dependencies = [
|
||||
"colored",
|
||||
"der",
|
||||
"komodo_client",
|
||||
"pem-rfc7468",
|
||||
"pem-rfc7468 1.0.0",
|
||||
"pkcs8",
|
||||
"secret_file",
|
||||
"serde_json",
|
||||
@@ -3659,11 +3673,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ordered_hash_map"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab0e5f22bf6dd04abd854a8874247813a8fa2c8c1260eba6fbb150270ce7c176"
|
||||
checksum = "a6c699f8a30f345785be969deed7eee4c73a5de58c7faf61d6a3251ef798ff61"
|
||||
dependencies = [
|
||||
"hashbrown 0.13.2",
|
||||
"hashbrown 0.15.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -3768,6 +3782,15 @@ dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
@@ -3776,7 +3799,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "periphery_client"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"derive_variants",
|
||||
@@ -3996,7 +4019,7 @@ dependencies = [
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"socket2 0.6.1",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
@@ -4016,7 +4039,7 @@ dependencies = [
|
||||
"rand 0.9.2",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.17",
|
||||
@@ -4208,7 +4231,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
@@ -4257,7 +4280,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "response"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -4362,9 +4385,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.34"
|
||||
version = "0.23.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7"
|
||||
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"log",
|
||||
@@ -4527,7 +4550,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "secret_file"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
@@ -5273,7 +5296,7 @@ version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
||||
dependencies = [
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -5297,7 +5320,7 @@ checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
@@ -5307,9 +5330,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.16"
|
||||
version = "0.7.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
|
||||
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -5354,9 +5377,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_pretty"
|
||||
version = "1.2.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dd195be7600b4b26e951a25b382b67a976d2d44bb967a1a5b573a3e63d18c29"
|
||||
checksum = "abc44e8fe3b5ec4cce2db87a3c11e0ebc396d4c2d59da64d6f0c00e78f9b9296"
|
||||
dependencies = [
|
||||
"ordered_hash_map",
|
||||
"serde",
|
||||
@@ -5560,7 +5583,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "transport"
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -5573,7 +5596,7 @@ dependencies = [
|
||||
"periphery_client",
|
||||
"pin-project-lite",
|
||||
"rand 0.9.2",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"serde",
|
||||
"serror",
|
||||
"sha1",
|
||||
@@ -5604,7 +5627,7 @@ dependencies = [
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.9.2",
|
||||
"rustls 0.23.34",
|
||||
"rustls 0.23.35",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
"thiserror 2.0.17",
|
||||
|
||||
28
Cargo.toml
28
Cargo.toml
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "2.0.0-dev-86"
|
||||
version = "2.0.0-dev-90"
|
||||
edition = "2024"
|
||||
authors = ["mbecker20 <becker.maxh@gmail.com>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
@@ -48,14 +48,14 @@ partial_derive2 = "0.4.3"
|
||||
derive_variants = "1.0.0"
|
||||
mongo_indexed = "2.0.2"
|
||||
resolver_api = "3.0.0"
|
||||
toml_pretty = "1.2.0"
|
||||
toml_pretty = "2.0.0"
|
||||
mungos = "3.2.2"
|
||||
svi = "1.2.0"
|
||||
|
||||
# ASYNC
|
||||
reqwest = { version = "0.12.24", default-features = false, features = ["json", "stream", "rustls-tls-native-roots"] }
|
||||
tokio = { version = "1.48.0", features = ["full"] }
|
||||
tokio-util = { version = "0.7.16", features = ["io", "codec"] }
|
||||
tokio-util = { version = "0.7.17", features = ["io", "codec"] }
|
||||
tokio-stream = { version = "0.1.17", features = ["sync"] }
|
||||
pin-project-lite = "0.2.16"
|
||||
futures-util = "0.3.31"
|
||||
@@ -63,7 +63,7 @@ arc-swap = "1.7.1"
|
||||
|
||||
# SERVER
|
||||
tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-native-roots"] }
|
||||
axum-extra = { version = "0.10.3", features = ["typed-header"] }
|
||||
axum-extra = { version = "0.12.1", features = ["typed-header"] }
|
||||
tower-http = { version = "0.6.6", features = ["fs", "cors"] }
|
||||
axum-server = { version = "0.7.2", features = ["tls-rustls"] }
|
||||
axum = { version = "0.8.6", features = ["ws", "json", "macros"] }
|
||||
@@ -94,15 +94,15 @@ opentelemetry = "0.31.0"
|
||||
tracing = "0.1.41"
|
||||
|
||||
# CONFIG
|
||||
clap = { version = "4.5.50", features = ["derive"] }
|
||||
clap = { version = "4.5.51", features = ["derive"] }
|
||||
dotenvy = "0.15.7"
|
||||
envy = "0.4.2"
|
||||
|
||||
# CRYPTO / AUTH
|
||||
uuid = { version = "1.18.1", features = ["v4", "fast-rng", "serde"] }
|
||||
jsonwebtoken = { version = "10.1.0", features = ["aws_lc_rs"] } # locked back with octorust
|
||||
rustls = { version = "0.23.34", features = ["aws-lc-rs"] }
|
||||
pem-rfc7468 = { version = "0.7.0", features = ["alloc"] }
|
||||
jsonwebtoken = { version = "10.2.0", features = ["aws_lc_rs"] } # locked back with octorust
|
||||
rustls = { version = "0.23.35", features = ["aws-lc-rs"] }
|
||||
pem-rfc7468 = { version = "1.0.0", features = ["alloc"] }
|
||||
openidconnect = "4.0.1"
|
||||
urlencoding = "2.1.3"
|
||||
bcrypt = "0.17.1"
|
||||
@@ -122,23 +122,23 @@ hickory-resolver = "0.25.2"
|
||||
portable-pty = "0.9.0"
|
||||
shell-escape = "0.1.5"
|
||||
crossterm = "0.29.0"
|
||||
bollard = "0.19.3"
|
||||
bollard = "0.19.4"
|
||||
sysinfo = "0.37.1"
|
||||
shlex = "1.3.0"
|
||||
|
||||
# CLOUD
|
||||
aws-config = "1.8.8"
|
||||
aws-sdk-ec2 = "1.176.0"
|
||||
aws-credential-types = "1.2.8"
|
||||
aws-config = "1.8.10"
|
||||
aws-sdk-ec2 = "1.184.0"
|
||||
aws-credential-types = "1.2.9"
|
||||
|
||||
## CRON
|
||||
english-to-cron = "0.1.6"
|
||||
chrono-tz = "0.10.4"
|
||||
chrono = "0.4.42"
|
||||
croner = "3.0.0"
|
||||
croner = "3.0.1"
|
||||
|
||||
# MISC
|
||||
async-compression = { version = "0.4.32", features = ["tokio", "gzip"] }
|
||||
async-compression = { version = "0.4.33", features = ["tokio", "gzip"] }
|
||||
derive_builder = "0.20.2"
|
||||
comfy-table = "7.2.1"
|
||||
typeshare = "1.0.4"
|
||||
|
||||
@@ -17,9 +17,12 @@ use formatting::format_serror;
|
||||
use futures_util::future::join_all;
|
||||
use interpolate::Interpolator;
|
||||
use komodo_client::{
|
||||
api::execute::{
|
||||
BatchExecutionResponse, BatchRunBuild, CancelBuild, Deploy,
|
||||
RunBuild,
|
||||
api::{
|
||||
execute::{
|
||||
BatchExecutionResponse, BatchRunBuild, CancelBuild, Deploy,
|
||||
RunBuild,
|
||||
},
|
||||
write::RefreshBuildCache,
|
||||
},
|
||||
entities::{
|
||||
alert::{Alert, AlertData, SeverityLevel},
|
||||
@@ -41,6 +44,7 @@ use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
alert::send_alerts,
|
||||
api::write::WriteArgs,
|
||||
helpers::{
|
||||
build_git_token,
|
||||
builder::{cleanup_builder_instance, connect_builder_periphery},
|
||||
@@ -186,7 +190,7 @@ impl Resolve<ExecuteArgs> for RunBuild {
|
||||
update.finalize();
|
||||
let id = update.id.clone();
|
||||
if let Err(e) = update_update(update).await {
|
||||
warn!("failed to modify Update {id} on db | {e:#}");
|
||||
warn!("Failed to modify Update {id} on db | {e:#}");
|
||||
}
|
||||
if !is_server_builder {
|
||||
cancel_clone.cancel();
|
||||
@@ -215,12 +219,12 @@ impl Resolve<ExecuteArgs> for RunBuild {
|
||||
Ok(builder) => builder,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"failed to get builder for build {} | {e:#}",
|
||||
"Failed to get Builder for Build {} | {e:#}",
|
||||
build.name
|
||||
);
|
||||
update.logs.push(Log::error(
|
||||
"get builder",
|
||||
format_serror(&e.context("failed to get builder").into()),
|
||||
"Get Builder",
|
||||
format_serror(&e.context("Failed to get Builder").into()),
|
||||
));
|
||||
return handle_early_return(
|
||||
update, build.id, build.name, false,
|
||||
@@ -276,7 +280,7 @@ impl Resolve<ExecuteArgs> for RunBuild {
|
||||
|
||||
let commit_message = match res {
|
||||
Ok(res) => {
|
||||
debug!("finished repo clone");
|
||||
debug!("Finished repo clone");
|
||||
update.logs.extend(res.res.logs);
|
||||
update.commit_hash =
|
||||
res.res.commit_hash.unwrap_or_default().to_string();
|
||||
@@ -312,10 +316,10 @@ impl Resolve<ExecuteArgs> for RunBuild {
|
||||
commit_hash: optional_string(&update.commit_hash),
|
||||
// Unused for now
|
||||
additional_tags: Default::default(),
|
||||
}) => res.context("failed at call to periphery to build"),
|
||||
}) => res.context("Failed at call to Periphery to build"),
|
||||
_ = cancel.cancelled() => {
|
||||
info!("Build cancelled during build, cleaning up builder");
|
||||
update.push_error_log("Build cancelled", String::from("user cancelled build during docker build"));
|
||||
update.push_error_log("Build cancelled", String::from("User cancelled build during docker build"));
|
||||
cleanup_builder_instance(periphery, cleanup_data, &mut update)
|
||||
.await;
|
||||
return handle_early_return(update, build.id, build.name, true).await
|
||||
@@ -328,10 +332,10 @@ impl Resolve<ExecuteArgs> for RunBuild {
|
||||
update.logs.extend(logs);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("error in build | {e:#}");
|
||||
warn!("Error in build | {e:#}");
|
||||
update.push_error_log(
|
||||
"Build Error",
|
||||
format_serror(&e.context("failed to build").into()),
|
||||
format_serror(&e.context("Failed to build").into()),
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -382,12 +386,15 @@ impl Resolve<ExecuteArgs> for RunBuild {
|
||||
|
||||
update_update(update.clone()).await?;
|
||||
|
||||
let Build { id, name, .. } = build;
|
||||
|
||||
if update.success {
|
||||
// don't hold response up for user
|
||||
tokio::spawn(async move {
|
||||
handle_post_build_redeploy(&build.id).await;
|
||||
handle_post_build_redeploy(&id).await;
|
||||
});
|
||||
} else {
|
||||
let name = name.clone();
|
||||
let target = update.target.clone();
|
||||
let version = update.version;
|
||||
tokio::spawn(async move {
|
||||
@@ -398,16 +405,22 @@ impl Resolve<ExecuteArgs> for RunBuild {
|
||||
resolved_ts: Some(komodo_timestamp()),
|
||||
resolved: true,
|
||||
level: SeverityLevel::Warning,
|
||||
data: AlertData::BuildFailed {
|
||||
id: build.id,
|
||||
name: build.name,
|
||||
version,
|
||||
},
|
||||
data: AlertData::BuildFailed { id, name, version },
|
||||
};
|
||||
send_alerts(&[alert]).await
|
||||
});
|
||||
}
|
||||
|
||||
if let Err(e) = (RefreshBuildCache { build: name })
|
||||
.resolve(&WriteArgs { user: user.clone() })
|
||||
.await
|
||||
{
|
||||
update.push_error_log(
|
||||
"Refresh build cache",
|
||||
format_serror(&e.error.into()),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(update.clone())
|
||||
}
|
||||
}
|
||||
@@ -565,7 +578,7 @@ impl Resolve<ExecuteArgs> for CancelBuild {
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
"failed to set CancelBuild Update status Complete after timeout | {e:#}"
|
||||
"Failed to set CancelBuild Update status Complete after timeout | {e:#}"
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ use formatting::format_serror;
|
||||
use komodo_client::entities::{
|
||||
FileContents, RepoExecutionArgs,
|
||||
repo::Repo,
|
||||
stack::{Stack, StackRemoteFileContents},
|
||||
stack::{AdditionalEnvFile, Stack, StackRemoteFileContents},
|
||||
to_path_compatible_name,
|
||||
update::Log,
|
||||
};
|
||||
@@ -60,24 +60,22 @@ pub async fn maybe_login_registry(
|
||||
|
||||
pub fn env_file_args(
|
||||
env_file_path: Option<&str>,
|
||||
additional_env_files: &[String],
|
||||
additional_env_files: &[AdditionalEnvFile],
|
||||
) -> anyhow::Result<String> {
|
||||
let mut res = String::new();
|
||||
|
||||
for file in additional_env_files.iter().filter(|&path| {
|
||||
let Some(komodo_path) = env_file_path else {
|
||||
return true;
|
||||
};
|
||||
// Filter komodo env out of additional env file if its also in there.
|
||||
// It will be always be added last / have highest priority.
|
||||
path != komodo_path
|
||||
}) {
|
||||
write!(res, " --env-file {file}").with_context(|| {
|
||||
format!("Failed to write --env-file arg for {file}")
|
||||
// Add additional env files (except komodo's own, which comes last)
|
||||
for file in additional_env_files
|
||||
.iter()
|
||||
.filter(|f| env_file_path != Some(f.path.as_str()))
|
||||
{
|
||||
let path = &file.path;
|
||||
write!(res, " --env-file {path}").with_context(|| {
|
||||
format!("Failed to write --env-file arg for {path}")
|
||||
})?;
|
||||
}
|
||||
|
||||
// Add this last, so it is applied on top
|
||||
// Add komodo's env file last for highest priority
|
||||
if let Some(file) = env_file_path {
|
||||
write!(res, " --env-file {file}").with_context(|| {
|
||||
format!("Failed to write --env-file arg for {file}")
|
||||
|
||||
@@ -8,14 +8,18 @@ use command::{
|
||||
use formatting::format_serror;
|
||||
use git::write_commit_file;
|
||||
use interpolate::Interpolator;
|
||||
use komodo_client::entities::{
|
||||
FileContents, RepoExecutionResponse, all_logs_success,
|
||||
stack::{
|
||||
ComposeFile, ComposeProject, ComposeService,
|
||||
ComposeServiceDeploy, StackRemoteFileContents, StackServiceNames,
|
||||
use komodo_client::{
|
||||
entities::{
|
||||
FileContents, RepoExecutionResponse, all_logs_success,
|
||||
stack::{
|
||||
ComposeFile, ComposeProject, ComposeService,
|
||||
ComposeServiceDeploy, StackRemoteFileContents,
|
||||
StackServiceNames,
|
||||
},
|
||||
to_path_compatible_name,
|
||||
update::Log,
|
||||
},
|
||||
to_path_compatible_name,
|
||||
update::Log,
|
||||
parsers::parse_multiline_command,
|
||||
};
|
||||
use periphery_client::api::compose::*;
|
||||
use resolver_api::Resolve;
|
||||
@@ -361,7 +365,7 @@ impl Resolve<super::Args> for ComposePull {
|
||||
)?;
|
||||
|
||||
let file_paths = stack
|
||||
.all_file_paths()
|
||||
.all_tracked_file_paths()
|
||||
.into_iter()
|
||||
.map(|path| {
|
||||
(
|
||||
@@ -658,10 +662,18 @@ impl Resolve<super::Args> for ComposeUp {
|
||||
|
||||
// Run compose up
|
||||
let extra_args = format_extra_args(&stack.config.extra_args);
|
||||
let command = format!(
|
||||
let mut command = format!(
|
||||
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} up -d{extra_args}{service_args}",
|
||||
);
|
||||
|
||||
// Apply compose cmd wrapper if configured
|
||||
let compose_cmd_wrapper =
|
||||
parse_multiline_command(&stack.config.compose_cmd_wrapper);
|
||||
if !compose_cmd_wrapper.is_empty() {
|
||||
command =
|
||||
compose_cmd_wrapper.replace("[[COMPOSE_COMMAND]]", &command);
|
||||
}
|
||||
|
||||
let span = info_span!("RunComposeUp");
|
||||
let Some(log) = run_komodo_command_with_sanitization(
|
||||
"Compose Up",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::{
|
||||
net::IpAddr, path::PathBuf, str::FromStr as _, sync::OnceLock,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
@@ -221,12 +222,10 @@ fn opendns_resolver() -> &'static OpenDNSResolver {
|
||||
static OPENDNS_RESOLVER: OnceLock<OpenDNSResolver> =
|
||||
OnceLock::new();
|
||||
OPENDNS_RESOLVER.get_or_init(|| {
|
||||
// OpenDNS resolver ips
|
||||
// OpenDNS resolver ipv4s
|
||||
let ips = [
|
||||
IpAddr::from_str("208.67.222.222").unwrap(),
|
||||
IpAddr::from_str("208.67.220.220").unwrap(),
|
||||
IpAddr::from_str("2620:119:35::35").unwrap(),
|
||||
IpAddr::from_str("2620:119:53::53").unwrap(),
|
||||
IpAddr::from_str("208.67.222.222").unwrap(),
|
||||
];
|
||||
|
||||
// trust_negative_responses=true means NXDOMAIN/empty NOERROR from an
|
||||
@@ -249,15 +248,23 @@ fn opendns_resolver() -> &'static OpenDNSResolver {
|
||||
})
|
||||
}
|
||||
|
||||
/// Includes 1s timeout
|
||||
pub async fn resolve_host_public_ip() -> anyhow::Result<String> {
|
||||
opendns_resolver()
|
||||
.lookup_ip("myip.opendns.com.")
|
||||
.await
|
||||
.context("Failed to query OpenDNS resolvers for host public IP")?
|
||||
.into_iter()
|
||||
.map(|ip| ip.to_string())
|
||||
.next()
|
||||
.context("OpenDNS call for public IP didn't return anything")
|
||||
tokio::time::timeout(Duration::from_secs(1), async {
|
||||
opendns_resolver()
|
||||
.lookup_ip("myip.opendns.com.")
|
||||
.await
|
||||
.context(
|
||||
"Failed to query OpenDNS resolvers for host public IP",
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|ip| ip.to_string())
|
||||
.next()
|
||||
.context("OpenDNS call for public IP didn't return anything")
|
||||
})
|
||||
.await
|
||||
.context("OpenDNS call for public IP timed out")
|
||||
.flatten()
|
||||
}
|
||||
|
||||
// =====
|
||||
|
||||
@@ -327,7 +327,7 @@ pub struct UrlBuilderConfig {
|
||||
/// The address of the Periphery agent
|
||||
#[serde(default = "default_address")]
|
||||
#[builder(default = default_address())]
|
||||
#[partial(default(default_address()))]
|
||||
#[partial_default(default_address())]
|
||||
pub address: String,
|
||||
/// An expected public key associated with Periphery private key.
|
||||
/// If empty, doesn't validate Periphery public key.
|
||||
@@ -337,7 +337,7 @@ pub struct UrlBuilderConfig {
|
||||
/// Whether to validate the Periphery tls certificates.
|
||||
#[serde(default = "default_insecure_tls")]
|
||||
#[builder(default = default_insecure_tls())]
|
||||
#[partial(default(default_insecure_tls()))]
|
||||
#[partial_default(default_insecure_tls())]
|
||||
pub insecure_tls: bool,
|
||||
/// Deprecated. Use private / public keys instead.
|
||||
/// An optional override passkey to use
|
||||
@@ -423,18 +423,6 @@ pub struct AwsBuilderConfig {
|
||||
#[partial_default(aws_default_volume_gb())]
|
||||
pub volume_gb: i32,
|
||||
|
||||
/// The port periphery will be running on.
|
||||
/// Default: `8120`
|
||||
#[serde(default = "default_port")]
|
||||
#[builder(default = "default_port()")]
|
||||
#[partial_default(default_port())]
|
||||
pub port: i32,
|
||||
|
||||
#[serde(default = "default_use_https")]
|
||||
#[builder(default = "default_use_https()")]
|
||||
#[partial_default(default_use_https())]
|
||||
pub use_https: bool,
|
||||
|
||||
/// The EC2 ami id to create.
|
||||
/// The ami should have the periphery client configured to start on startup,
|
||||
/// and should have the necessary github / dockerhub accounts configured.
|
||||
@@ -473,14 +461,27 @@ pub struct AwsBuilderConfig {
|
||||
#[builder(default)]
|
||||
pub user_data: String,
|
||||
|
||||
/// The port periphery will be running on.
|
||||
/// Default: `8120`
|
||||
#[serde(default = "default_port")]
|
||||
#[builder(default = "default_port()")]
|
||||
#[partial_default(default_port())]
|
||||
pub port: i32,
|
||||
|
||||
#[serde(default = "default_use_https")]
|
||||
#[builder(default = "default_use_https()")]
|
||||
#[partial_default(default_use_https())]
|
||||
pub use_https: bool,
|
||||
|
||||
/// An expected public key associated with Periphery private key.
|
||||
/// If empty, doesn't validate Periphery public key.
|
||||
#[serde(default)]
|
||||
pub periphery_public_key: String,
|
||||
|
||||
/// Whether to validate the Periphery tls certificates.
|
||||
#[serde(default = "default_insecure_tls")]
|
||||
#[builder(default = default_insecure_tls())]
|
||||
#[partial(default(default_insecure_tls()))]
|
||||
#[partial_default(default_insecure_tls())]
|
||||
pub insecure_tls: bool,
|
||||
|
||||
/// Which git providers are available on the AMI
|
||||
|
||||
@@ -79,14 +79,24 @@ impl Stack {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn all_file_paths(&self) -> Vec<String> {
|
||||
/// Get tracked additional env files (those that Komodo should manage)
|
||||
fn tracked_env_files(&self) -> impl Iterator<Item = &str> {
|
||||
self
|
||||
.config
|
||||
.additional_env_files
|
||||
.iter()
|
||||
.filter(|f| f.track)
|
||||
.map(|f| f.path.as_str())
|
||||
}
|
||||
|
||||
pub fn all_tracked_file_paths(&self) -> Vec<String> {
|
||||
let mut res = self
|
||||
.compose_file_paths()
|
||||
.iter()
|
||||
.cloned()
|
||||
// Makes sure to dedup them, while maintaining ordering
|
||||
.collect::<IndexSet<_>>();
|
||||
res.extend(self.config.additional_env_files.clone());
|
||||
res.extend(self.tracked_env_files().map(str::to_string));
|
||||
res.extend(
|
||||
self.config.config_files.iter().map(|f| f.path.clone()),
|
||||
);
|
||||
@@ -103,11 +113,8 @@ impl Stack {
|
||||
.collect::<IndexSet<_>>();
|
||||
res.extend(
|
||||
self
|
||||
.config
|
||||
.additional_env_files
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(StackFileDependency::full_redeploy),
|
||||
.tracked_env_files()
|
||||
.map(|p| StackFileDependency::full_redeploy(p.to_string())),
|
||||
);
|
||||
res.extend(self.config.config_files.clone());
|
||||
res.into_iter().collect()
|
||||
@@ -450,13 +457,10 @@ pub struct StackConfig {
|
||||
///
|
||||
/// Note. It is already included as an `additional_file`.
|
||||
/// Don't add it again there.
|
||||
#[serde(default, deserialize_with = "string_list_deserializer")]
|
||||
#[partial_attr(serde(
|
||||
default,
|
||||
deserialize_with = "option_string_list_deserializer"
|
||||
))]
|
||||
#[serde(default)]
|
||||
#[partial_attr(serde(default))]
|
||||
#[builder(default)]
|
||||
pub additional_env_files: Vec<String>,
|
||||
pub additional_env_files: Vec<AdditionalEnvFile>,
|
||||
|
||||
/// Add additional config files either in repo or on host to track.
|
||||
/// Can add any files associated with the stack to enable editing them in the UI.
|
||||
@@ -517,6 +521,17 @@ pub struct StackConfig {
|
||||
#[builder(default)]
|
||||
pub build_extra_args: Vec<String>,
|
||||
|
||||
/// Optional command wrapper for secrets management tools.
|
||||
/// Wraps the docker compose up command with a prefix command.
|
||||
/// Use [[COMPOSE_COMMAND]] as placeholder for the full compose command.
|
||||
///
|
||||
/// Examples:
|
||||
/// - "op run -- [[COMPOSE_COMMAND]]" (1password CLI)
|
||||
/// - "sops exec-file --no-fifo /path/to/secret.env '[[COMPOSE_COMMAND]]'" (sops)
|
||||
#[serde(default)]
|
||||
#[builder(default)]
|
||||
pub compose_cmd_wrapper: String,
|
||||
|
||||
/// Ignore certain services declared in the compose file when checking
|
||||
/// the stack status. For example, an init service might be exited, but the
|
||||
/// stack should be healthy. This init service should be in `ignore_services`
|
||||
@@ -619,6 +634,7 @@ impl Default for StackConfig {
|
||||
run_build: Default::default(),
|
||||
destroy_before_deploy: Default::default(),
|
||||
build_extra_args: Default::default(),
|
||||
compose_cmd_wrapper: Default::default(),
|
||||
skip_secret_interp: Default::default(),
|
||||
linked_repo: Default::default(),
|
||||
git_provider: default_git_provider(),
|
||||
@@ -818,6 +834,86 @@ pub enum StackFileRequires {
|
||||
None,
|
||||
}
|
||||
|
||||
/// Additional env file configuration for Stack.
|
||||
/// Supports backward compatibility with string-only format.
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
|
||||
pub struct AdditionalEnvFile {
|
||||
/// File path relative to run directory
|
||||
pub path: String,
|
||||
/// Whether Komodo should track this file's contents.
|
||||
/// If true (default), Komodo will read, display, diff, and validate.
|
||||
/// If false, only passed to docker compose via --env-file.
|
||||
/// Useful for externally managed files (e.g., sops decrypted files).
|
||||
#[serde(default = "default_true")]
|
||||
pub track: bool,
|
||||
}
|
||||
|
||||
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Used with custom de/serializer for [AdditionalEnvFile]
|
||||
#[derive(Deserialize)]
|
||||
struct __AdditionalEnvFile {
|
||||
path: String,
|
||||
#[serde(default = "default_true")]
|
||||
track: bool,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for AdditionalEnvFile {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct AdditionalEnvFileVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for AdditionalEnvFileVisitor {
|
||||
type Value = AdditionalEnvFile;
|
||||
|
||||
fn expecting(
|
||||
&self,
|
||||
formatter: &mut std::fmt::Formatter,
|
||||
) -> std::fmt::Result {
|
||||
write!(formatter, "string or AdditionalEnvFile (object)")
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, path: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(AdditionalEnvFile {
|
||||
path,
|
||||
track: default_true(),
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Self::visit_string(self, v.to_string())
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
__AdditionalEnvFile::deserialize(
|
||||
MapAccessDeserializer::new(map).into_deserializer(),
|
||||
)
|
||||
.map(|v| AdditionalEnvFile {
|
||||
path: v.path,
|
||||
track: v.track,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(AdditionalEnvFileVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure additional file dependencies of the Stack.
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
|
||||
|
||||
@@ -2205,6 +2205,22 @@ export type GetStackActionStateResponse = StackActionState;
|
||||
|
||||
export type GetStackLogResponse = Log;
|
||||
|
||||
/**
|
||||
* Additional env file configuration for Stack.
|
||||
* Supports backward compatibility with string-only format.
|
||||
*/
|
||||
export interface AdditionalEnvFile {
|
||||
/** File path relative to run directory */
|
||||
path: string;
|
||||
/**
|
||||
* Whether Komodo should track this file's contents.
|
||||
* If true (default), Komodo will read, display, diff, and validate.
|
||||
* If false, only passed to docker compose via --env-file.
|
||||
* Useful for externally managed files (e.g., sops decrypted files).
|
||||
*/
|
||||
track: boolean;
|
||||
}
|
||||
|
||||
export enum StackFileRequires {
|
||||
/** Diff requires service redeploy. */
|
||||
Redeploy = "Redeploy",
|
||||
@@ -2342,7 +2358,7 @@ export interface StackConfig {
|
||||
* Note. It is already included as an `additional_file`.
|
||||
* Don't add it again there.
|
||||
*/
|
||||
additional_env_files?: string[];
|
||||
additional_env_files?: AdditionalEnvFile[];
|
||||
/**
|
||||
* Add additional config files either in repo or on host to track.
|
||||
* Can add any files associated with the stack to enable editing them in the UI.
|
||||
@@ -2374,6 +2390,16 @@ export interface StackConfig {
|
||||
* Only used if `run_build: true`
|
||||
*/
|
||||
build_extra_args?: string[];
|
||||
/**
|
||||
* Optional command wrapper for secrets management tools.
|
||||
* Wraps the docker compose up command with a prefix command.
|
||||
* Use [[COMPOSE_COMMAND]] as placeholder for the full compose command.
|
||||
*
|
||||
* Examples:
|
||||
* - "op run -- [[COMPOSE_COMMAND]]" (1password CLI)
|
||||
* - "sops exec-file --no-fifo /path/to/secret.env '[[COMPOSE_COMMAND]]'" (sops)
|
||||
*/
|
||||
compose_cmd_wrapper?: string;
|
||||
/**
|
||||
* Ignore certain services declared in the compose file when checking
|
||||
* the stack status. For example, an init service might be exited, but the
|
||||
@@ -4283,12 +4309,6 @@ export interface AwsBuilderConfig {
|
||||
instance_type: string;
|
||||
/** The size of the builder volume in gb */
|
||||
volume_gb: number;
|
||||
/**
|
||||
* The port periphery will be running on.
|
||||
* Default: `8120`
|
||||
*/
|
||||
port: number;
|
||||
use_https: boolean;
|
||||
/**
|
||||
* The EC2 ami id to create.
|
||||
* The ami should have the periphery client configured to start on startup,
|
||||
@@ -4316,6 +4336,12 @@ export interface AwsBuilderConfig {
|
||||
security_group_ids?: string[];
|
||||
/** The user data to deploy the instance with. */
|
||||
user_data?: string;
|
||||
/**
|
||||
* The port periphery will be running on.
|
||||
* Default: `8120`
|
||||
*/
|
||||
port: number;
|
||||
use_https: boolean;
|
||||
/**
|
||||
* An expected public key associated with Periphery private key.
|
||||
* If empty, doesn't validate Periphery public key.
|
||||
|
||||
@@ -49,9 +49,9 @@
|
||||
"react-router-dom": "7.6.1",
|
||||
"react-xtermjs": "1.0.10",
|
||||
"sanitize-html": "2.17.0",
|
||||
"shell-quote": "1.8.1",
|
||||
"tailwind-merge": "2.6.0",
|
||||
"tailwindcss-animate": "1.0.7",
|
||||
"shell-quote": "1.8.1"
|
||||
"tailwindcss-animate": "1.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "19.1.6",
|
||||
|
||||
39
frontend/public/client/types.d.ts
vendored
39
frontend/public/client/types.d.ts
vendored
@@ -2339,6 +2339,21 @@ export interface StackActionState {
|
||||
}
|
||||
export type GetStackActionStateResponse = StackActionState;
|
||||
export type GetStackLogResponse = Log;
|
||||
/**
|
||||
* Additional env file configuration for Stack.
|
||||
* Supports backward compatibility with string-only format.
|
||||
*/
|
||||
export interface AdditionalEnvFile {
|
||||
/** File path relative to run directory */
|
||||
path: string;
|
||||
/**
|
||||
* Whether Komodo should track this file's contents.
|
||||
* If true (default), Komodo will read, display, diff, and validate.
|
||||
* If false, only passed to docker compose via --env-file.
|
||||
* Useful for externally managed files (e.g., sops decrypted files).
|
||||
*/
|
||||
track: boolean;
|
||||
}
|
||||
export declare enum StackFileRequires {
|
||||
/** Diff requires service redeploy. */
|
||||
Redeploy = "Redeploy",
|
||||
@@ -2474,7 +2489,7 @@ export interface StackConfig {
|
||||
* Note. It is already included as an `additional_file`.
|
||||
* Don't add it again there.
|
||||
*/
|
||||
additional_env_files?: string[];
|
||||
additional_env_files?: AdditionalEnvFile[];
|
||||
/**
|
||||
* Add additional config files either in repo or on host to track.
|
||||
* Can add any files associated with the stack to enable editing them in the UI.
|
||||
@@ -2506,6 +2521,16 @@ export interface StackConfig {
|
||||
* Only used if `run_build: true`
|
||||
*/
|
||||
build_extra_args?: string[];
|
||||
/**
|
||||
* Optional command wrapper for secrets management tools.
|
||||
* Wraps the docker compose up command with a prefix command.
|
||||
* Use [[COMPOSE_COMMAND]] as placeholder for the full compose command.
|
||||
*
|
||||
* Examples:
|
||||
* - "op run -- [[COMPOSE_COMMAND]]" (1password CLI)
|
||||
* - "sops exec-file --no-fifo /path/to/secret.env '[[COMPOSE_COMMAND]]'" (sops)
|
||||
*/
|
||||
compose_cmd_wrapper?: string;
|
||||
/**
|
||||
* Ignore certain services declared in the compose file when checking
|
||||
* the stack status. For example, an init service might be exited, but the
|
||||
@@ -4204,12 +4229,6 @@ export interface AwsBuilderConfig {
|
||||
instance_type: string;
|
||||
/** The size of the builder volume in gb */
|
||||
volume_gb: number;
|
||||
/**
|
||||
* The port periphery will be running on.
|
||||
* Default: `8120`
|
||||
*/
|
||||
port: number;
|
||||
use_https: boolean;
|
||||
/**
|
||||
* The EC2 ami id to create.
|
||||
* The ami should have the periphery client configured to start on startup,
|
||||
@@ -4237,6 +4256,12 @@ export interface AwsBuilderConfig {
|
||||
security_group_ids?: string[];
|
||||
/** The user data to deploy the instance with. */
|
||||
user_data?: string;
|
||||
/**
|
||||
* The port periphery will be running on.
|
||||
* Default: `8120`
|
||||
*/
|
||||
port: number;
|
||||
use_https: boolean;
|
||||
/**
|
||||
* An expected public key associated with Periphery private key.
|
||||
* If empty, doesn't validate Periphery public key.
|
||||
|
||||
@@ -18,7 +18,12 @@ import {
|
||||
import { Box, CalendarDays, Home, Search, Terminal, User } from "lucide-react";
|
||||
import { Fragment, ReactNode, useMemo, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { cn, RESOURCE_TARGETS, usableResourcePath } from "@lib/utils";
|
||||
import {
|
||||
cn,
|
||||
RESOURCE_TARGETS,
|
||||
terminalLink,
|
||||
usableResourcePath,
|
||||
} from "@lib/utils";
|
||||
import { Badge } from "@ui/badge";
|
||||
import { ResourceComponents } from "./resources";
|
||||
import { Switch } from "@ui/switch";
|
||||
@@ -121,6 +126,8 @@ export const OmniDialog = ({
|
||||
{showContainers && (
|
||||
<OmniContainers search={search} closeSearch={() => setOpen(false)} />
|
||||
)}
|
||||
|
||||
<OmniTerminals search={search} closeSearch={() => setOpen(false)} />
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
);
|
||||
@@ -265,25 +272,77 @@ const OmniContainers = ({
|
||||
<>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Containers">
|
||||
{containers?.map((container) => (
|
||||
<CommandItem
|
||||
key={container.id}
|
||||
value={container.name}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onSelect={() => {
|
||||
closeSearch();
|
||||
navigate(
|
||||
`/servers/${container.server_id!}/container/${container.name}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
<DOCKER_LINK_ICONS.container
|
||||
server_id={container.server_id!}
|
||||
name={container.name}
|
||||
/>
|
||||
{container.name}
|
||||
</CommandItem>
|
||||
))}
|
||||
{containers?.map((container) => {
|
||||
const key = container.server_id + container.name;
|
||||
return (
|
||||
<CommandItem
|
||||
key={key}
|
||||
value={key}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onSelect={() => {
|
||||
closeSearch();
|
||||
navigate(
|
||||
`/servers/${container.server_id!}/container/${container.name}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
<DOCKER_LINK_ICONS.container
|
||||
server_id={container.server_id!}
|
||||
name={container.name}
|
||||
/>
|
||||
{container.name}
|
||||
</CommandItem>
|
||||
);
|
||||
})}
|
||||
</CommandGroup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const OmniTerminals = ({
|
||||
search,
|
||||
closeSearch,
|
||||
}: {
|
||||
search: string;
|
||||
closeSearch: () => void;
|
||||
}) => {
|
||||
const _terminals = useRead("ListTerminals", {}).data;
|
||||
const terminals = useMemo(() => {
|
||||
return _terminals?.filter((c) => {
|
||||
const searchTerms = search
|
||||
.toLowerCase()
|
||||
.split(" ")
|
||||
.filter((term) => term);
|
||||
if (searchTerms.length === 0) return true;
|
||||
const lower = c.name.toLowerCase();
|
||||
return searchTerms.every(
|
||||
(term) => lower.includes(term) || "terminals".includes(term)
|
||||
);
|
||||
});
|
||||
}, [_terminals, search]);
|
||||
const navigate = useNavigate();
|
||||
if ((terminals?.length ?? 0) < 1) return null;
|
||||
return (
|
||||
<>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Terminals">
|
||||
{terminals?.map((terminal) => {
|
||||
const key = JSON.stringify(terminal.target) + terminal.name;
|
||||
return (
|
||||
<CommandItem
|
||||
key={key}
|
||||
value={key}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
onSelect={() => {
|
||||
closeSearch();
|
||||
navigate(terminalLink(terminal));
|
||||
}}
|
||||
>
|
||||
<Terminal className="w-4 h-4" />
|
||||
{terminal.name}
|
||||
</CommandItem>
|
||||
);
|
||||
})}
|
||||
</CommandGroup>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from "@lib/color";
|
||||
import { cn, updateLogToHtml } from "@lib/utils";
|
||||
import { Types } from "komodo_client";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import { GroupActions } from "@components/group-actions";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@ui/tooltip";
|
||||
import { Card } from "@ui/card";
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from "@lib/color";
|
||||
import { cn } from "@lib/utils";
|
||||
import { Types } from "komodo_client";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import { StatusBadge } from "@components/util";
|
||||
import { Card } from "@ui/card";
|
||||
import { Badge } from "@ui/badge";
|
||||
|
||||
@@ -104,13 +104,6 @@ const AwsBuilderConfig = ({ id }: { id: string }) => {
|
||||
description:
|
||||
"Whether to connect to the instance over the public IP. Otherwise, will use the internal IP.",
|
||||
},
|
||||
port: {
|
||||
description: "Configure the port to connect to Periphery on.",
|
||||
placeholder: "Input port",
|
||||
},
|
||||
use_https: {
|
||||
description: "Whether to connect to Periphery using HTTPS.",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -132,17 +125,24 @@ const AwsBuilderConfig = ({ id }: { id: string }) => {
|
||||
],
|
||||
additional: [
|
||||
{
|
||||
label: "Auth",
|
||||
label: "Connection",
|
||||
labelHidden: true,
|
||||
components: {
|
||||
periphery_public_key: {
|
||||
label: "Periphery Public Key",
|
||||
description:
|
||||
"If provided, the associated private key must be set as Periphery 'private_key'. For Periphery -> Core connection, either this or using 'periphery_public_key' in Core config is required for Periphery to be able to connect.",
|
||||
"If provided, the associated private key must be set as Periphery 'private_key'.",
|
||||
placeholder: "custom-public-key",
|
||||
},
|
||||
port: {
|
||||
description: "Configure the port to connect to Periphery on.",
|
||||
placeholder: "Input port",
|
||||
},
|
||||
use_https: {
|
||||
description: "Whether to connect to Periphery using HTTPS.",
|
||||
},
|
||||
insecure_tls: {
|
||||
description: "Skip Periphery TLS certificate validation.",
|
||||
description: "Skip Periphery TLS certificate validation when HTTPS is enabled.",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -352,7 +352,7 @@ const UrlBuilderConfig = ({ id }: { id: string }) => {
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Auth",
|
||||
label: "Connection",
|
||||
labelHidden: true,
|
||||
components: {
|
||||
periphery_public_key: {
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
ResourcePageHeader,
|
||||
} from "../common";
|
||||
import { RunBuild } from "../build/actions";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import {
|
||||
ContainerPortsTableView,
|
||||
DockerResourceLink,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useDeployment } from ".";
|
||||
import { useLocalStorage, usePermissions } from "@lib/hooks";
|
||||
import { useServer } from "../server";
|
||||
import { useMemo } from "react";
|
||||
import { MobileFriendlyTabsSelector } from "@ui/mobile-friendly-tabs";
|
||||
import { MobileFriendlyTabsSelector, TabNoContent } from "@ui/mobile-friendly-tabs";
|
||||
import { DeploymentConfig } from "./config";
|
||||
import { DeploymentLogs } from "./log";
|
||||
import { DeploymentInspect } from "./inspect";
|
||||
@@ -34,16 +34,12 @@ const DeploymentTabsInner = ({
|
||||
useServer(deployment.info.server_id)?.info.container_terminals_disabled ??
|
||||
true;
|
||||
const state = deployment.info.state;
|
||||
const logsDisabled =
|
||||
!specificLogs ||
|
||||
state === undefined ||
|
||||
state === Types.DeploymentState.Unknown ||
|
||||
state === Types.DeploymentState.NotDeployed;
|
||||
const inspectDisabled =
|
||||
!specificInspect ||
|
||||
const downOrUnknown =
|
||||
state === undefined ||
|
||||
state === Types.DeploymentState.Unknown ||
|
||||
state === Types.DeploymentState.NotDeployed;
|
||||
const logsDisabled = !specificLogs || downOrUnknown;
|
||||
const inspectDisabled = !specificInspect || downOrUnknown;
|
||||
const terminalDisabled =
|
||||
!specificTerminal ||
|
||||
container_terminals_disabled ||
|
||||
@@ -55,34 +51,36 @@ const DeploymentTabsInner = ({
|
||||
? "Config"
|
||||
: _view;
|
||||
|
||||
const Selector = useMemo(
|
||||
() => (
|
||||
<MobileFriendlyTabsSelector
|
||||
tabs={[
|
||||
{
|
||||
value: "Config",
|
||||
},
|
||||
{
|
||||
value: "Log",
|
||||
disabled: logsDisabled,
|
||||
},
|
||||
{
|
||||
value: "Inspect",
|
||||
disabled: inspectDisabled,
|
||||
},
|
||||
{
|
||||
value: "Terminals",
|
||||
disabled: terminalDisabled,
|
||||
},
|
||||
]}
|
||||
value={view}
|
||||
onValueChange={setView as any}
|
||||
tabsTriggerClassname="w-[110px]"
|
||||
/>
|
||||
),
|
||||
const tabs = useMemo<TabNoContent<DeploymentTabsView>[]>(
|
||||
() => [
|
||||
{
|
||||
value: "Config",
|
||||
},
|
||||
{
|
||||
value: "Log",
|
||||
disabled: logsDisabled,
|
||||
},
|
||||
{
|
||||
value: "Inspect",
|
||||
disabled: inspectDisabled,
|
||||
},
|
||||
{
|
||||
value: "Terminals",
|
||||
disabled: terminalDisabled,
|
||||
},
|
||||
],
|
||||
[logsDisabled, inspectDisabled, terminalDisabled]
|
||||
);
|
||||
|
||||
const Selector = (
|
||||
<MobileFriendlyTabsSelector
|
||||
tabs={tabs}
|
||||
value={view}
|
||||
onValueChange={setView as any}
|
||||
tabsTriggerClassname="w-[110px]"
|
||||
/>
|
||||
);
|
||||
|
||||
const target: Types.TerminalTarget = useMemo(
|
||||
() => ({
|
||||
type: "Deployment",
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from "@lib/color";
|
||||
import { cn, updateLogToHtml } from "@lib/utils";
|
||||
import { Types } from "komodo_client";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import { GroupActions } from "@components/group-actions";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@ui/tooltip";
|
||||
import { Card } from "@ui/card";
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { cn } from "@lib/utils";
|
||||
import { useServer } from "../server";
|
||||
import { Types } from "komodo_client";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import { RepoLink, StatusBadge } from "@components/util";
|
||||
import { Badge } from "@ui/badge";
|
||||
import { useToast } from "@ui/use-toast";
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
import { ServerTable } from "./table";
|
||||
import { DeleteResource, NewResource, ResourcePageHeader } from "../common";
|
||||
import { ActionWithDialog, ConfirmButton, StatusBadge } from "@components/util";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import { ServerStatsMini } from "./stats-mini";
|
||||
import { GroupActions } from "@components/group-actions";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@ui/tooltip";
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { useLocalStorage, usePermissions, useRead, useUser } from "@lib/hooks";
|
||||
import { useServer } from ".";
|
||||
import { ReactNode, useMemo } from "react";
|
||||
import { MobileFriendlyTabsSelector } from "@ui/mobile-friendly-tabs";
|
||||
import {
|
||||
MobileFriendlyTabsSelector,
|
||||
TabNoContent,
|
||||
} from "@ui/mobile-friendly-tabs";
|
||||
import { ServerStats } from "./stats";
|
||||
import { ServerInfo } from "./info";
|
||||
import { ServerConfig } from "./config";
|
||||
@@ -14,10 +17,10 @@ import { ServerTerminals } from "@components/terminal/server";
|
||||
import { Card, CardHeader, CardTitle } from "@ui/card";
|
||||
import { Types } from "komodo_client";
|
||||
|
||||
type ServerTabView = "Config" | "Stats" | "Docker" | "Resources" | "Terminals";
|
||||
type ServerTabsView = "Config" | "Stats" | "Docker" | "Resources" | "Terminals";
|
||||
|
||||
export const ServerTabs = ({ id }: { id: string }) => {
|
||||
const [view, setView] = useLocalStorage<ServerTabView>(
|
||||
const [view, setView] = useLocalStorage<ServerTabsView>(
|
||||
`server-${id}-tab`,
|
||||
"Config"
|
||||
);
|
||||
@@ -45,36 +48,38 @@ export const ServerTabs = ({ id }: { id: string }) => {
|
||||
|
||||
const noResources = noDeployments && noRepos && noStacks;
|
||||
|
||||
const Selector = useMemo(
|
||||
() => (
|
||||
<MobileFriendlyTabsSelector
|
||||
tabs={[
|
||||
{
|
||||
value: "Config",
|
||||
},
|
||||
{
|
||||
value: "Stats",
|
||||
},
|
||||
{
|
||||
value: "Docker",
|
||||
},
|
||||
{
|
||||
value: "Resources",
|
||||
disabled: noResources,
|
||||
},
|
||||
{
|
||||
value: "Terminals",
|
||||
disabled: terminalDisabled,
|
||||
},
|
||||
]}
|
||||
value={view}
|
||||
onValueChange={setView as any}
|
||||
tabsTriggerClassname="w-[110px]"
|
||||
/>
|
||||
),
|
||||
const tabs = useMemo<TabNoContent<ServerTabsView>[]>(
|
||||
() => [
|
||||
{
|
||||
value: "Config",
|
||||
},
|
||||
{
|
||||
value: "Stats",
|
||||
},
|
||||
{
|
||||
value: "Docker",
|
||||
},
|
||||
{
|
||||
value: "Resources",
|
||||
disabled: noResources,
|
||||
},
|
||||
{
|
||||
value: "Terminals",
|
||||
disabled: terminalDisabled,
|
||||
},
|
||||
],
|
||||
[noResources, terminalDisabled]
|
||||
);
|
||||
|
||||
const Selector = (
|
||||
<MobileFriendlyTabsSelector
|
||||
tabs={tabs}
|
||||
value={view}
|
||||
onValueChange={setView as any}
|
||||
tabsTriggerClassname="w-[110px]"
|
||||
/>
|
||||
);
|
||||
|
||||
switch (view) {
|
||||
case "Config":
|
||||
return <ServerConfig id={id} titleOther={Selector} />;
|
||||
|
||||
@@ -42,6 +42,8 @@ import {
|
||||
import { LinkedRepoConfig } from "@components/config/linked_repo";
|
||||
import { Button } from "@ui/button";
|
||||
import { Input } from "@ui/input";
|
||||
import { Label } from "@ui/label";
|
||||
import { Switch } from "@ui/switch";
|
||||
import { useStack } from ".";
|
||||
import { filterBySplit } from "@lib/utils";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@ui/popover";
|
||||
@@ -244,19 +246,86 @@ export const StackConfig = ({
|
||||
},
|
||||
additional_env_files:
|
||||
(mode === "Files On Server" || mode === "Git Repo") &&
|
||||
((values, set) => (
|
||||
<ConfigList
|
||||
label="Additional Env Files"
|
||||
boldLabel
|
||||
addLabel="Add Env File"
|
||||
description="Add additional env files to pass with '--env-file'. Relative to the 'Run Directory'."
|
||||
field="additional_env_files"
|
||||
values={values ?? []}
|
||||
set={set}
|
||||
disabled={disabled}
|
||||
placeholder=".env"
|
||||
/>
|
||||
)),
|
||||
((values, set) => {
|
||||
const files = (values ?? []).map((v: any) =>
|
||||
typeof v === "string" ? { path: v, track: true } : v
|
||||
);
|
||||
return (
|
||||
<ConfigItem label="Additional Env Files" boldLabel>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
{files.map((file: any, i: number) => (
|
||||
<div key={i} className="flex items-center gap-4 w-full">
|
||||
<Input
|
||||
value={file.path || ""}
|
||||
onChange={(e) => {
|
||||
const newFiles = [...files];
|
||||
newFiles[i] = {
|
||||
path: e.target.value,
|
||||
track: file.track ?? true,
|
||||
};
|
||||
set({ additional_env_files: newFiles });
|
||||
}}
|
||||
placeholder=".env"
|
||||
disabled={disabled}
|
||||
className="w-[400px] max-w-full"
|
||||
/>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Switch
|
||||
checked={file.track ?? true}
|
||||
onCheckedChange={(track) => {
|
||||
const newFiles = [...files];
|
||||
newFiles[i] = { ...newFiles[i], track };
|
||||
set({ additional_env_files: newFiles });
|
||||
}}
|
||||
disabled={disabled}
|
||||
id={`track-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`track-${i}`} className="text-sm">
|
||||
Track
|
||||
</Label>
|
||||
</div>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
set({
|
||||
additional_env_files: files.filter(
|
||||
(_: any, idx: number) => idx !== i
|
||||
),
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
set({
|
||||
additional_env_files: [
|
||||
...files,
|
||||
{ path: "", track: true },
|
||||
],
|
||||
});
|
||||
}}
|
||||
className="w-fit"
|
||||
>
|
||||
<PlusCircle className="w-4 h-4 mr-2" />
|
||||
Add Env File
|
||||
</Button>
|
||||
)}
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Add additional env files to pass with '--env-file'. Relative
|
||||
to the 'Run Directory'. Uncheck 'Track' for externally managed
|
||||
files (e.g., sops decrypted).
|
||||
</div>
|
||||
</div>
|
||||
</ConfigItem>
|
||||
);
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -368,6 +437,26 @@ export const StackConfig = ({
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Command Wrapper",
|
||||
description:
|
||||
"Optional wrapper to execute 'docker compose up -d' as a subcommand of tools like secrets management.",
|
||||
components: {
|
||||
compose_cmd_wrapper: (value, set) => (
|
||||
<MonacoEditor
|
||||
value={
|
||||
value ??
|
||||
"# sops exec-env .encrypted.env '[[COMPOSE_COMMAND]]'\n"
|
||||
}
|
||||
language="shell"
|
||||
onValueChange={(compose_cmd_wrapper) =>
|
||||
set({ compose_cmd_wrapper })
|
||||
}
|
||||
readOnly={disabled}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Extra Args",
|
||||
labelHidden: true,
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
import { Badge } from "@ui/badge";
|
||||
import { Button } from "@ui/button";
|
||||
import { useToast } from "@ui/use-toast";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import { StatusBadge } from "@components/util";
|
||||
import { GroupActions } from "@components/group-actions";
|
||||
import { Tooltip, TooltipTrigger, TooltipContent } from "@ui/tooltip";
|
||||
|
||||
@@ -36,7 +36,7 @@ export const StackTabs = ({ id }: { id: string }) => {
|
||||
? "Config"
|
||||
: _view;
|
||||
|
||||
const tabsNoContent = useMemo<TabNoContent<StackTabsView>[]>(
|
||||
const tabs = useMemo<TabNoContent<StackTabsView>[]>(
|
||||
() => [
|
||||
{
|
||||
value: "Config",
|
||||
@@ -59,7 +59,7 @@ export const StackTabs = ({ id }: { id: string }) => {
|
||||
|
||||
const Selector = (
|
||||
<MobileFriendlyTabsSelector
|
||||
tabs={tabsNoContent}
|
||||
tabs={tabs}
|
||||
value={view}
|
||||
onValueChange={setView as any}
|
||||
tabsTriggerClassname="w-[110px]"
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from "@lib/color";
|
||||
import { cn } from "@lib/utils";
|
||||
import { fmt_date } from "@lib/formatting";
|
||||
import { DashboardPieChart } from "@pages/dashboard";
|
||||
import { DashboardPieChart } from "@components/util";
|
||||
import { StatusBadge } from "@components/util";
|
||||
import { Badge } from "@ui/badge";
|
||||
import { GroupActions } from "@components/group-actions";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useRead } from "@lib/hooks";
|
||||
import { useAllResources, useRead } from "@lib/hooks";
|
||||
import { Types } from "komodo_client";
|
||||
import { UsableResource } from "@types";
|
||||
|
||||
@@ -6,25 +6,17 @@ export const useUserTargetPermissions = (user_target: Types.UserTarget) => {
|
||||
const permissions = useRead("ListUserTargetPermissions", {
|
||||
user_target,
|
||||
}).data;
|
||||
const servers = useRead("ListServers", {}).data;
|
||||
const stacks = useRead("ListStacks", {}).data;
|
||||
const deployments = useRead("ListDeployments", {}).data;
|
||||
const builds = useRead("ListBuilds", {}).data;
|
||||
const repos = useRead("ListRepos", {}).data;
|
||||
const procedures = useRead("ListProcedures", {}).data;
|
||||
const builders = useRead("ListBuilders", {}).data;
|
||||
const alerters = useRead("ListAlerters", {}).data;
|
||||
const syncs = useRead("ListResourceSyncs", {}).data;
|
||||
const allResources = useAllResources();
|
||||
const perms: (Types.Permission & { name: string })[] = [];
|
||||
addPerms(user_target, permissions, "Server", servers, perms);
|
||||
addPerms(user_target, permissions, "Stack", stacks, perms);
|
||||
addPerms(user_target, permissions, "Deployment", deployments, perms);
|
||||
addPerms(user_target, permissions, "Build", builds, perms);
|
||||
addPerms(user_target, permissions, "Repo", repos, perms);
|
||||
addPerms(user_target, permissions, "Procedure", procedures, perms);
|
||||
addPerms(user_target, permissions, "Builder", builders, perms);
|
||||
addPerms(user_target, permissions, "Alerter", alerters, perms);
|
||||
addPerms(user_target, permissions, "ResourceSync", syncs, perms);
|
||||
for (const [resource_type, resources] of Object.entries(allResources)) {
|
||||
addPerms(
|
||||
user_target,
|
||||
permissions,
|
||||
resource_type as UsableResource,
|
||||
resources,
|
||||
perms
|
||||
);
|
||||
}
|
||||
return perms;
|
||||
};
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ import {
|
||||
SelectValue,
|
||||
} from "@ui/select";
|
||||
import { useServer } from "./resources/server";
|
||||
import { PieChart } from "react-minimal-pie-chart";
|
||||
|
||||
export const ActionButton = forwardRef<
|
||||
HTMLButtonElement,
|
||||
@@ -1634,3 +1635,46 @@ export const ContainerTerminalModeSelector = ({
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export type DashboardPieChartItem = {
|
||||
title: string;
|
||||
intention: ColorIntention;
|
||||
value: number;
|
||||
};
|
||||
|
||||
export const DashboardPieChart = ({
|
||||
data: _data,
|
||||
}: {
|
||||
data: Array<DashboardPieChartItem | false | undefined>;
|
||||
}) => {
|
||||
const data = _data.filter((d) => d) as Array<DashboardPieChartItem>;
|
||||
return (
|
||||
<div className="flex items-center gap-8">
|
||||
<div className="flex flex-col gap-2 w-28">
|
||||
{data.map(({ title, value, intention }) => (
|
||||
<p key={title} className="flex gap-2 text-xs text-muted-foreground">
|
||||
<span
|
||||
className={cn(
|
||||
"font-bold",
|
||||
text_color_class_by_intention(intention)
|
||||
)}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
{title}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<PieChart
|
||||
className="w-32 h-32"
|
||||
radius={42}
|
||||
lineWidth={30}
|
||||
data={data.map(({ title, value, intention }) => ({
|
||||
title,
|
||||
value,
|
||||
color: hex_color_by_intention(intention),
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -284,3 +284,22 @@ export const resourceTargetFromTerminalTarget = (
|
||||
return { type: "Deployment", id: target.params.deployment };
|
||||
}
|
||||
};
|
||||
|
||||
export const terminalLink = ({
|
||||
target,
|
||||
name,
|
||||
}: {
|
||||
target: Types.TerminalTarget;
|
||||
name: string;
|
||||
}) => {
|
||||
switch (target.type) {
|
||||
case "Server":
|
||||
return `/servers/${target.params.server}/terminal/${name}`;
|
||||
case "Container":
|
||||
return `/servers/${target.params.server}/container/${target.params.container}/terminal/${name}`;
|
||||
case "Stack":
|
||||
return `/stacks/${target.params.stack}/service/${target.params.service}/terminal/${name}`;
|
||||
case "Deployment":
|
||||
return `/deployments/${target.params.deployment}/terminal/${name}`;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,16 +11,14 @@ import { Eye, EyeOff, Settings, Table } from "lucide-react";
|
||||
import {
|
||||
action_state_intention,
|
||||
build_state_intention,
|
||||
ColorIntention,
|
||||
hex_color_by_intention,
|
||||
procedure_state_intention,
|
||||
repo_state_intention,
|
||||
text_color_class_by_intention,
|
||||
} from "@lib/color";
|
||||
import {
|
||||
useFilterResources,
|
||||
useNoResources,
|
||||
useRead,
|
||||
useSetTitle,
|
||||
useUser,
|
||||
} from "@lib/hooks";
|
||||
import { cn, usableResourcePath } from "@lib/utils";
|
||||
@@ -28,7 +26,6 @@ import { Types } from "komodo_client";
|
||||
import { RequiredResourceComponents, UsableResource } from "@types";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { AlertTriangle, Box, Circle, History } from "lucide-react";
|
||||
import { PieChart } from "react-minimal-pie-chart";
|
||||
import { Link } from "react-router-dom";
|
||||
import { UpdateAvailable as StackUpdateAvailable } from "@components/resources/stack";
|
||||
import { UpdateAvailable as DeploymentUpdateAvailable } from "@components/resources/deployment";
|
||||
@@ -37,6 +34,7 @@ import { Input } from "@ui/input";
|
||||
|
||||
export default function Dashboard() {
|
||||
const { preferences } = useDashboardPreferences();
|
||||
useSetTitle(undefined);
|
||||
return (
|
||||
<>
|
||||
<ActiveResources />
|
||||
@@ -272,49 +270,6 @@ const RecentCard = ({
|
||||
);
|
||||
};
|
||||
|
||||
export type DashboardPieChartItem = {
|
||||
title: string;
|
||||
intention: ColorIntention;
|
||||
value: number;
|
||||
};
|
||||
|
||||
export const DashboardPieChart = ({
|
||||
data: _data,
|
||||
}: {
|
||||
data: Array<DashboardPieChartItem | false | undefined>;
|
||||
}) => {
|
||||
const data = _data.filter((d) => d) as Array<DashboardPieChartItem>;
|
||||
return (
|
||||
<div className="flex items-center gap-8">
|
||||
<div className="flex flex-col gap-2 w-28">
|
||||
{data.map(({ title, value, intention }) => (
|
||||
<p key={title} className="flex gap-2 text-xs text-muted-foreground">
|
||||
<span
|
||||
className={cn(
|
||||
"font-bold",
|
||||
text_color_class_by_intention(intention)
|
||||
)}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
{title}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<PieChart
|
||||
className="w-32 h-32"
|
||||
radius={42}
|
||||
lineWidth={30}
|
||||
data={data.map(({ title, value, intention }) => ({
|
||||
title,
|
||||
value,
|
||||
color: hex_color_by_intention(intention),
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ActiveResources = () => {
|
||||
const builds =
|
||||
useRead("ListBuilds", {}).data?.filter(
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
useInvalidate,
|
||||
useRead,
|
||||
useSetTitle,
|
||||
useShiftKeyListener,
|
||||
useUser,
|
||||
useWrite,
|
||||
} from "@lib/hooks";
|
||||
@@ -237,6 +238,7 @@ const CreateVariable = () => {
|
||||
const user = useUser().data;
|
||||
const disabled = !user?.admin;
|
||||
const submit = () => mutate({ name });
|
||||
useShiftKeyListener("N", () => !open && setOpen(true));
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
@@ -261,6 +263,11 @@ const CreateVariable = () => {
|
||||
onChange={(e) =>
|
||||
setName(e.target.value.toUpperCase().replaceAll(" ", "_"))
|
||||
}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && name) {
|
||||
submit();
|
||||
}
|
||||
}}
|
||||
placeholder="Input variable name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -43,31 +43,33 @@ export const StackServiceTabs = ({
|
||||
? "Log"
|
||||
: _view;
|
||||
|
||||
const Selector = useMemo(
|
||||
() => (
|
||||
<MobileFriendlyTabsSelector
|
||||
tabs={[
|
||||
{
|
||||
value: "Log",
|
||||
disabled: logDisabled,
|
||||
},
|
||||
{
|
||||
value: "Inspect",
|
||||
disabled: inspectDisabled,
|
||||
},
|
||||
{
|
||||
value: "Terminals",
|
||||
disabled: terminalDisabled,
|
||||
},
|
||||
]}
|
||||
value={view}
|
||||
onValueChange={setView as any}
|
||||
tabsTriggerClassname="w-[110px]"
|
||||
/>
|
||||
),
|
||||
const tabs = useMemo(
|
||||
() => [
|
||||
{
|
||||
value: "Log",
|
||||
disabled: logDisabled,
|
||||
},
|
||||
{
|
||||
value: "Inspect",
|
||||
disabled: inspectDisabled,
|
||||
},
|
||||
{
|
||||
value: "Terminals",
|
||||
disabled: terminalDisabled,
|
||||
},
|
||||
],
|
||||
[logDisabled, inspectDisabled, terminalDisabled]
|
||||
);
|
||||
|
||||
const Selector = (
|
||||
<MobileFriendlyTabsSelector
|
||||
tabs={tabs}
|
||||
value={view}
|
||||
onValueChange={setView as any}
|
||||
tabsTriggerClassname="w-[110px]"
|
||||
/>
|
||||
);
|
||||
|
||||
const target: Types.TerminalTarget = useMemo(
|
||||
() => ({
|
||||
type: "Stack",
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
useTerminalTargetPermissions,
|
||||
useWrite,
|
||||
} from "@lib/hooks";
|
||||
import { filterBySplit } from "@lib/utils";
|
||||
import { filterBySplit, terminalLink } from "@lib/utils";
|
||||
import { Button } from "@ui/button";
|
||||
import { DataTable, SortableHeader } from "@ui/data-table";
|
||||
import { Input } from "@ui/input";
|
||||
@@ -86,7 +86,7 @@ export default function TerminalsPage() {
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<Link
|
||||
to={terminal_link(row.original.name, row.original.target)}
|
||||
to={terminalLink(row.original)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
@@ -162,19 +162,6 @@ export default function TerminalsPage() {
|
||||
);
|
||||
}
|
||||
|
||||
const terminal_link = (name: string, target: Types.TerminalTarget) => {
|
||||
switch (target.type) {
|
||||
case "Server":
|
||||
return `/servers/${target.params.server}/terminal/${name}`;
|
||||
case "Container":
|
||||
return `/servers/${target.params.server}/container/${target.params.container}/terminal/${name}`;
|
||||
case "Stack":
|
||||
return `/stacks/${target.params.stack}/service/${target.params.service}/terminal/${name}`;
|
||||
case "Deployment":
|
||||
return `/deployments/${target.params.deployment}/terminal/${name}`;
|
||||
}
|
||||
};
|
||||
|
||||
const TerminalTargetResourceLink = ({
|
||||
target,
|
||||
}: {
|
||||
|
||||
@@ -1464,9 +1464,9 @@ camelcase-css@^2.0.1:
|
||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||
|
||||
caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718:
|
||||
version "1.0.30001721"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz"
|
||||
integrity sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==
|
||||
version "1.0.30001754"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz"
|
||||
integrity sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==
|
||||
|
||||
chalk@^4.0.0:
|
||||
version "4.1.2"
|
||||
|
||||
@@ -232,7 +232,7 @@ def main():
|
||||
write_service_file(args, home_dir, bin_dir, config_dir, service_dir)
|
||||
|
||||
user = ""
|
||||
if user_install:
|
||||
if args.user:
|
||||
user = " --user"
|
||||
|
||||
print("Starting Periphery...")
|
||||
@@ -241,5 +241,7 @@ def main():
|
||||
print("Finished Periphery setup.\n")
|
||||
print(f'Note. Use "systemctl{user} status periphery" to make sure Periphery is running')
|
||||
print(f'Note. Use "systemctl{user} enable periphery" to have Periphery start on system boot')
|
||||
if args.user:
|
||||
print(f'Note. Use "sudo loginctl enable-linger $USER" to make sure Periphery keeps runnning after user logs out')
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user