270 Commits

Author SHA1 Message Date
954d9caf34 Update dependency eslint to ^9.29.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-06-19 00:28:47 +00:00
39873cfa40 Update dependency @typescript-eslint/eslint-plugin to ^8.34.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-18 00:25:02 +00:00
e3df9e63e6 Update dependency @typescript-eslint/parser to ^8.34.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-17 00:30:49 +00:00
6eb54e8653 Update dependency @fluentui/react-components to ^9.66.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-16 00:25:16 +00:00
b10caff599 Update dependency @eslint/js to ^9.29.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-15 00:25:10 +00:00
80921b12fa Update dependency @fluentui/react-icons to ^2.0.303
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-14 00:30:47 +00:00
5bdf6d03a4 Update Rust crate rust-embed to 8.7.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-13 00:30:53 +00:00
73e02cd6b8 Update Rust crate reqwest to 0.12.20
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-12 00:26:20 +00:00
f6ed37458e Update Rust crate futures-util to 0.3.31
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-11 00:26:27 +00:00
082bfc5cb9 Update Rust crate clap to 4.5.40
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-10 00:26:16 +00:00
c2227c9129 Update dependency @types/react to ^18.3.23
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-09 00:25:33 +00:00
eb33e93b08 Update dependency @fluentui/react-icons to ^2.0.302
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-07 00:31:37 +00:00
2e393b8777 Update dependency vite to ^6.3.5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-06-06 00:31:13 +00:00
7daafdc1aa Fix cargo clippy issues
All checks were successful
continuous-integration/drone/push Build is passing
2025-06-05 08:54:53 +00:00
f3e14df55f Update dependency typescript-eslint to ^8.32.1
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
2025-05-15 00:19:30 +00:00
4caa2c416b Update dependency @typescript-eslint/parser to ^8.32.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-14 00:20:15 +00:00
b4913054f0 Update dependency @typescript-eslint/eslint-plugin to ^8.32.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-13 00:21:11 +00:00
8f2337c325 Update Rust crate clap to 4.5.38
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-12 00:20:13 +00:00
4ccdea317b Update dependency typescript-eslint to ^8.32.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-11 00:18:37 +00:00
d8ac0d1f0f Update dependency @fluentui/react-icons to ^2.0.300
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-10 00:19:30 +00:00
652fab1511 Update dependency globals to ^16.1.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-09 00:18:59 +00:00
e687f94daa Update dependency @typescript-eslint/parser to ^8.32.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-08 00:28:02 +00:00
ee6991c240 Update dependency @types/react to ^18.3.21
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-07 00:27:55 +00:00
1efaeb9264 Update dependency @typescript-eslint/eslint-plugin to ^8.32.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-06 00:27:28 +00:00
60f96bbc45 Update dependency eslint to ^9.26.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-04 00:27:34 +00:00
a3752ee654 Update dependency @eslint/js to ^9.26.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-03 00:27:24 +00:00
dd39e3d7ba Update dependency typescript-eslint to ^8.31.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-02 00:22:34 +00:00
dc07e055f8 Update dependency @types/react-dom to ^18.3.7
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-05-01 00:22:41 +00:00
5ee8c7fce3 Update dependency @typescript-eslint/parser to ^8.31.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-30 00:22:36 +00:00
5a796fecca Update dependency @typescript-eslint/eslint-plugin to ^8.31.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-29 00:22:26 +00:00
48fc0a03a5 Update dependency eslint to ^9.25.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-28 00:22:12 +00:00
8e679210ea Update dependency @typescript-eslint/parser to ^8.31.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-27 00:21:37 +00:00
aa1f8e12eb Update dependency @fluentui/react-icons to ^2.0.298
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-26 00:26:13 +00:00
d33700f9ae Update dependency @fluentui/react-components to ^9.63.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-25 00:22:55 +00:00
46e689045e Update dependency @typescript-eslint/eslint-plugin to ^8.31.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-24 00:22:45 +00:00
18c9eb7f23 Update dependency eslint-plugin-react-refresh to ^0.4.20
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-23 00:22:17 +00:00
9110c66f05 Update dependency @eslint/js to ^9.25.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-22 00:30:49 +00:00
77c0869f74 Update dependency @vitejs/plugin-react to ^4.4.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-21 00:31:01 +00:00
3726f8ba2d Update dependency @eslint/js to ^9.25.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-20 00:30:36 +00:00
89ca5493e1 Update Rust crate clap to 4.5.37
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-19 00:31:32 +00:00
b06926e3a5 Update dependency @typescript-eslint/eslint-plugin to ^8.30.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-18 00:34:38 +00:00
5b7709f50a Update dependency @fluentui/react-components to ^9.62.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-17 00:29:52 +00:00
79ef24e414 Update dependency @eslint/js to ^9.24.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-16 00:30:06 +00:00
d575feac81 Update Rust crate anyhow to 1.0.98
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-15 00:29:57 +00:00
00343abdb0 Update dependency vite to ^6.2.6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-14 00:29:57 +00:00
3ee3f0119b Update dependency @fluentui/react-icons to ^2.0.297
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-13 00:30:19 +00:00
b18f18a986 Update Rust crate clap to 4.5.36
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-12 00:30:50 +00:00
e7ad0ffd4f Update dependency typescript to ^5.8.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-11 00:30:22 +00:00
670ceab69e Update dependency eslint-plugin-react-refresh to ^0.4.19
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-10 00:30:29 +00:00
9c2eedc7d1 Update dependency @types/react-dom to ^18.3.6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-09 00:30:31 +00:00
f44d318b16 Update dependency @fluentui/react-icons to ^2.0.294
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-08 00:34:39 +00:00
85b33a32c4 Update dependency @fluentui/react-components to ^9.61.6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-07 00:36:40 +00:00
36478bd61e Update Rust crate env_logger to 0.11.8
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-06 00:38:04 +00:00
6f2c00b2a4 Update Rust crate clap to 4.5.35
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-05 00:37:21 +00:00
4c61610ff2 Update Rust crate thiserror to 2.0.12
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-04 00:38:53 +00:00
52b749c9a9 Update Rust crate serde to 1.0.219
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-03 00:39:07 +00:00
8eccffb176 Merge pull request 'Update react' (#279) from renovate/react into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #279
2025-04-02 07:11:51 +00:00
35fc98e653 Update react
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-04-02 00:40:01 +00:00
1f21bc5ba0 Update Rust crate rust-embed to 8.6.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-04-01 02:09:39 +00:00
7b43701b1c Update Rust crate mime_guess to 2.0.5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-03-31 20:54:43 +00:00
5c62dd0c27 Update Rust crate lazy_static to 1.5.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-03-31 00:38:57 +00:00
6b6ea9ea83 Update Rust crate lazy-regex to 3.4.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-03-30 02:25:05 +00:00
1d5b132e7e Update Rust crate anyhow to 1.0.97
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-03-29 23:01:36 +00:00
97f65931c8 Update Rust crate actix-cors to 0.7.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-03-29 18:17:24 +00:00
ccb0c6cd6e Update renovate.json
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-29 17:32:11 +00:00
4ee52e83fd Update dependency globals to v16
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-03-29 12:55:23 +00:00
296d168995 Update renovate.json
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-29 09:03:26 +00:00
8f3ff52dda Merge pull request 'Update dependency @types/react to v18.3.20' (#257) from renovate/react-18.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #257
2025-03-29 08:56:59 +00:00
0e0af55a85 Merge pull request 'Update Rust crate basic-jwt to 0.3.0' (#258) from renovate/basic-jwt-0.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #258
2025-03-29 08:56:49 +00:00
2518d202da Update Rust crate basic-jwt to 0.3.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-29 00:34:41 +00:00
aa7c217b6c Update dependency @types/react to v18.3.20
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-29 00:34:38 +00:00
6b699994cf Rollback to React 18 (waiting for fluentui to upgrade)
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-28 16:52:06 +01:00
e13ae9f062 Updated frontend dependencies
Some checks failed
continuous-integration/drone/push Build is failing
2025-03-28 16:44:52 +01:00
77b1117fa1 Update VirteWebRemote backend dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-28 16:32:24 +01:00
daa0a9f391 Merge pull request 'Update Rust crate actix-cors to v0.7.1' (#250) from renovate/actix-cors-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #250
2025-03-28 15:22:54 +00:00
f94d1b1c6b Merge pull request 'Update Rust crate reqwest to v0.12.14' (#254) from renovate/reqwest-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #254
2025-03-28 15:22:48 +00:00
b3b1592d93 Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.26.1' (#255) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #255
2025-03-28 15:22:43 +00:00
8bf7129ee1 Merge pull request 'Update dependency @typescript-eslint/parser to v8.26.1' (#256) from renovate/typescript-eslint-parser-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #256
2025-03-28 15:22:37 +00:00
5c841e6a85 Update dependency @typescript-eslint/parser to v8.26.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-15 00:09:20 +00:00
369efd442f Update dependency @typescript-eslint/eslint-plugin to v8.26.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-14 00:09:56 +00:00
01c0f20cf4 Update Rust crate reqwest to v0.12.14
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-14 00:09:51 +00:00
c96ca68f7e Merge pull request 'Update Rust crate reqwest to v0.12.13' (#251) from renovate/reqwest-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #251
2025-03-13 15:41:16 +00:00
8121212723 Merge pull request 'Update dependency @fluentui/react-components to v9.60.1' (#253) from renovate/fluentui-react-components-9.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #253
2025-03-13 15:31:15 +00:00
cd9867c5b0 Update dependency @fluentui/react-components to v9.60.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-13 00:09:48 +00:00
cbc432a304 Update Rust crate reqwest to v0.12.13
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-12 00:24:15 +00:00
25d4d3e0f3 Update Rust crate actix-cors to v0.7.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-12 00:24:10 +00:00
855ec54e83 Merge pull request 'Update Rust crate clap to v4.5.32' (#248) from renovate/clap-4.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #248
2025-03-11 13:07:09 +00:00
10ab40fcd5 Merge pull request 'Update Rust crate serde to v1.0.219' (#249) from renovate/serde-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #249
2025-03-11 13:07:02 +00:00
92d53430af Update Rust crate serde to v1.0.219
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-11 00:23:27 +00:00
4d8387a854 Update Rust crate clap to v4.5.32
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-11 00:23:23 +00:00
68b2bb8e0c Merge pull request 'Update dependency @fluentui/react-icons to v2.0.279' (#243) from renovate/fluentui-react-icons-2.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #243
2025-03-10 17:58:41 +00:00
02a120c220 Merge pull request 'Update Rust crate rust-embed to v8.6.0' (#244) from renovate/rust-embed-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #244
2025-03-10 17:58:31 +00:00
e16167991b Merge pull request 'Update Rust crate uuid to v1.15.1' (#245) from renovate/uuid-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #245
2025-03-10 17:58:19 +00:00
5101d43c05 Merge pull request 'Update dependency @fluentui/react-components to v9.60.0' (#246) from renovate/fluentui-react-components-9.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #246
2025-03-10 17:58:10 +00:00
c32536f260 Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.26.0' (#247) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #247
2025-03-10 17:58:00 +00:00
e89818cc35 Update dependency @typescript-eslint/eslint-plugin to v8.26.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-09 00:22:01 +00:00
c7e0a6ddce Update dependency @fluentui/react-components to v9.60.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-08 00:22:42 +00:00
4ef2f69d92 Update Rust crate uuid to v1.15.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-08 00:22:32 +00:00
6427593fa8 Update Rust crate rust-embed to v8.6.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-07 00:22:20 +00:00
3336c9e8bf Update dependency @fluentui/react-icons to v2.0.279
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-07 00:22:14 +00:00
97f8e85268 Merge pull request 'Update Rust crate light-openid to v1.0.3' (#241) from renovate/light-openid-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #241
2025-03-06 20:28:29 +00:00
144d10164d Merge pull request 'Update Rust crate log to v0.4.26' (#242) from renovate/log-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #242
2025-03-06 20:28:00 +00:00
8cd5e61a6a Update Rust crate log to v0.4.26
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-06 00:22:17 +00:00
3a3110114b Update Rust crate light-openid to v1.0.3
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-06 00:22:15 +00:00
1b83c8fa07 Merge pull request 'Update dependency @typescript-eslint/parser to v8.26.0' (#228) from renovate/typescript-eslint-parser-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #228
2025-03-05 19:19:57 +00:00
9037842c0c Merge pull request 'Update Rust crate anyhow to v1.0.97' (#239) from renovate/anyhow-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #239
2025-03-05 19:19:45 +00:00
df3724a17d Merge pull request 'Update Rust crate clap to v4.5.31' (#240) from renovate/clap-4.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #240
2025-03-05 19:19:38 +00:00
31eb1977c3 Update dependency @typescript-eslint/parser to v8.26.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-05 00:22:26 +00:00
61ec9f6d91 Update Rust crate clap to v4.5.31
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-05 00:22:18 +00:00
aa6d45a5e8 Update Rust crate anyhow to v1.0.97
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-05 00:22:14 +00:00
cb0eba7fca Add new info on README
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-04 18:43:30 +00:00
3e4face5c9 Merge pull request 'Update dependency @fluentui/react-components to v9.58.3' (#231) from renovate/fluentui-react-components-9.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #231
2025-03-04 18:41:51 +00:00
217e476811 Merge pull request 'Update dependency @fluentui/react-icons to v2.0.274' (#225) from renovate/fluentui-react-icons-2.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #225
2025-03-04 18:41:38 +00:00
76a81e0ff9 Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.24.0' (#233) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #233
2025-03-04 18:41:32 +00:00
52ca4674d7 Merge pull request 'Update Rust crate uuid to v1.13.1' (#229) from renovate/uuid-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #229
2025-03-04 18:40:48 +00:00
5417e70bff Merge pull request 'Update Rust crate anyhow to v1.0.96' (#236) from renovate/anyhow-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #236
2025-03-04 18:40:42 +00:00
ba45b119a0 Merge pull request 'Update Rust crate thiserror to v2.0.12' (#238) from renovate/thiserror-2.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #238
2025-03-04 18:40:18 +00:00
947aa258f8 Update Rust crate thiserror to v2.0.12
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-03-04 00:22:32 +00:00
964e01cc8d Update Rust crate anyhow to v1.0.96
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-22 00:11:11 +00:00
f84f8aefc1 Merge pull request 'Update Rust crate clap to v4.5.29' (#234) from renovate/clap-4.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #234
2025-02-21 14:48:55 +00:00
1db549e2ee Merge pull request 'Update Rust crate serde to v1.0.218' (#235) from renovate/serde-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #235
2025-02-21 14:44:32 +00:00
fe00953be3 Update Rust crate serde to v1.0.218
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-21 00:11:10 +00:00
a223335cee Update Rust crate clap to v4.5.29
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-12 00:09:51 +00:00
417ea655ab Update dependency @typescript-eslint/eslint-plugin to v8.24.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-11 00:09:08 +00:00
2c7f5c9751 Merge pull request 'Update dependency eslint-plugin-react-refresh to v0.4.19' (#232) from renovate/eslint-plugin-react-refresh-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #232
2025-02-10 18:37:20 +00:00
04fa264e1c Update dependency eslint-plugin-react-refresh to v0.4.19
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-10 00:13:11 +00:00
8716b32739 Update dependency @fluentui/react-components to v9.58.3
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-08 00:13:19 +00:00
39357529e8 Merge pull request 'Update dependency vite to v6.1.0' (#230) from renovate/vite-6.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #230
2025-02-06 22:30:29 +00:00
d7d1211ee6 Update dependency vite to v6.1.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-06 00:13:48 +00:00
19b2854f56 Update Rust crate uuid to v1.13.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-06 00:13:35 +00:00
aa2498d1ef Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.23.0' (#227) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #227
2025-02-04 21:27:36 +00:00
a8aba27c87 Merge pull request 'Update Rust crate clap to v4.5.28' (#226) from renovate/clap-4.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #226
2025-02-04 07:02:57 +00:00
ca73e7b6fa Update dependency @typescript-eslint/eslint-plugin to v8.23.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-04 00:13:20 +00:00
6c59c4ae7b Update Rust crate clap to v4.5.28
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-04 00:13:16 +00:00
bb631188ae Update dependency @fluentui/react-icons to v2.0.274
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-01 00:26:43 +00:00
869ef03a9f Merge pull request 'Update dependency @fluentui/react-components to v9.58.2' (#223) from renovate/fluentui-react-components-9.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #223
2025-01-31 07:09:47 +00:00
bd16ab08c2 Merge pull request 'Update dependency @typescript-eslint/parser to v8.22.0' (#224) from renovate/typescript-eslint-parser-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #224
2025-01-30 07:22:57 +00:00
ad8c41ea58 Update dependency @typescript-eslint/parser to v8.22.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-30 00:31:12 +00:00
b051476f9d Update dependency @fluentui/react-components to v9.58.2
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-30 00:27:11 +00:00
bd22186c0f Merge pull request 'Update dependency @fluentui/react-components to v9.58.1' (#221) from renovate/fluentui-react-components-9.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #221
2025-01-28 22:18:28 +00:00
78046a9b3a Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.22.0' (#222) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #222
2025-01-28 06:58:27 +00:00
f5de43a67a Update dependency @typescript-eslint/eslint-plugin to v8.22.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-28 00:31:54 +00:00
2861038d71 Update dependency @fluentui/react-components to v9.58.1
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-28 00:27:53 +00:00
fe2b6d5dd6 Update README.md
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-24 07:31:01 +00:00
f7aebd7d6a Update dependency @typescript-eslint/parser to v8.21.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-24 00:27:46 +00:00
84ad543948 Update dependency @typescript-eslint/eslint-plugin to v8.21.0
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-23 01:11:06 +00:00
5a7d9e178d Update dependency @fluentui/react-components to v9.58.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-23 00:28:03 +00:00
9020389714 Update dependency vite to v6.0.11
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-22 01:13:21 +00:00
4f0e2cb722 Update Rust crate uuid to v1.12.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-22 00:27:49 +00:00
316b9efef8 Merge pull request 'Update Rust crate clap to v4.5.27' (#214) from renovate/clap-4.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #214
2025-01-21 07:05:22 +00:00
3e67d0bdb3 Update dependency vite to v6.0.10
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-21 00:28:01 +00:00
3281bf4b36 Update Rust crate clap to v4.5.27
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-21 00:27:57 +00:00
b4c4920e48 Merge pull request 'Update dependency @typescript-eslint/parser to v8.20.0' (#210) from renovate/typescript-eslint-parser-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #210
2025-01-19 22:09:37 +00:00
cc14077a82 Merge pull request 'Update Rust crate log to v0.4.25' (#211) from renovate/log-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #211
2025-01-19 22:09:30 +00:00
f1301f7eb0 Merge pull request 'Update Rust crate uuid to v1.12.0' (#212) from renovate/uuid-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #212
2025-01-19 22:09:22 +00:00
94ae206bbf Update dependency @fluentui/react-icons to v2.0.271
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-18 00:27:27 +00:00
e1d2bd7f4f Update Rust crate uuid to v1.12.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-15 00:52:14 +00:00
fc698ea66e Update Rust crate log to v0.4.25
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-15 00:52:06 +00:00
9211b43e50 Update dependency @typescript-eslint/parser to v8.20.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-14 00:52:26 +00:00
026aa1ecfd Update dependency @typescript-eslint/eslint-plugin to v8.20.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-14 00:52:11 +00:00
de3c18c658 Update dependency eslint-plugin-react-refresh to v0.4.18
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-12 01:19:00 +00:00
d74831aa9f Update Rust crate uuid to v1.11.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-12 00:50:44 +00:00
7da20d879b Update Rust crate thiserror to v2.0.11
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-11 01:21:18 +00:00
987c95221f Update Rust crate log to v0.4.24
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-11 00:24:55 +00:00
9c64f9a2a7 Update dependency @fluentui/react-components to v9.57.0
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-10 01:23:48 +00:00
6d2a2683bc Update Rust crate clap to v4.5.26
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-10 00:24:46 +00:00
80fd39dd24 Update dependency typescript to v5.7.3
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-09 01:52:32 +00:00
85b6ca9176 Update Rust crate thiserror to v2.0.10
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-09 00:24:45 +00:00
0b71315321 Update Rust crate clap to v4.5.24
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-08 00:30:17 +00:00
9246ced2e1 Update dependency @typescript-eslint/parser to v8.19.1
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-07 01:27:47 +00:00
b0c97052f5 Update dependency @typescript-eslint/eslint-plugin to v8.19.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-07 00:29:06 +00:00
70b1c290d0 Update Rust crate thiserror to v2.0.9
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-04 00:25:58 +00:00
50df3e92fd Merge pull request 'Update Rust crate thiserror to v2.0.8' (#178) from renovate/thiserror-2.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #178
2025-01-03 08:22:45 +00:00
14e4ff41a9 Merge pull request 'Update Rust crate env_logger to v0.11.6' (#182) from renovate/env_logger-0.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #182
2025-01-03 08:22:38 +00:00
744537a906 Update dependency vite to v6.0.7
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-03 00:25:07 +00:00
146a4e0885 Update Rust crate reqwest to v0.12.12
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-01 00:25:31 +00:00
74e1ed9ca1 Update dependency @typescript-eslint/parser to v8.19.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-31 00:59:09 +00:00
ca3d2010ef Update dependency @typescript-eslint/eslint-plugin to v8.19.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-31 00:24:55 +00:00
a7df69cd6f Update Rust crate lazy-regex to v3.4.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-29 00:56:53 +00:00
446001d9ff Update Rust crate serde to v1.0.217
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-28 01:51:22 +00:00
1a7aa5dab0 Update Rust crate reqwest to v0.12.11
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-28 00:26:50 +00:00
8f6892e498 Update dependency vite to v6.0.6
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-27 01:18:21 +00:00
5c8df481ac Update Rust crate reqwest to v0.12.10
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-27 00:25:19 +00:00
d8e1ce7fbe Update dependency @typescript-eslint/parser to v8.18.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-24 00:49:34 +00:00
5ae6f8f1bf Update dependency @typescript-eslint/eslint-plugin to v8.18.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-24 00:25:05 +00:00
807c2c310a Update Rust crate anyhow to v1.0.95
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-23 00:25:03 +00:00
ea5b072511 Update dependency vite to v6.0.5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-22 00:25:42 +00:00
1f5c22828d Update dependency @types/react to v18.3.18
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-21 00:25:57 +00:00
ba1073a8bd Update Rust crate env_logger to v0.11.6
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-21 00:25:54 +00:00
da1c962223 Update dependency @fluentui/react-icons to v2.0.270
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-20 01:22:22 +00:00
dab3034206 Update dependency @fluentui/react-components to v9.56.8
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-20 00:25:52 +00:00
75b97fb3e2 Update dependency @fluentui/react-components to v9.56.7
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-19 00:25:36 +00:00
e9c4a4d1b4 Update Rust crate thiserror to v2.0.8
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-19 00:25:30 +00:00
5c4e1c5425 Update dependency @typescript-eslint/parser to v8.18.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-18 01:35:39 +00:00
bcff61f1f6 Update dependency @typescript-eslint/eslint-plugin to v8.18.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-18 00:07:58 +00:00
9a970ce347 Update dependency @types/react to v18.3.17
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-17 01:36:43 +00:00
9e1287509a Update dependency @fluentui/react-components to v9.56.6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-17 00:08:13 +00:00
09f9a364ae Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.18.0' (#172) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #172
2024-12-16 09:59:48 +00:00
30589a6e6a Update dependency @typescript-eslint/parser to v8.18.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-15 00:08:21 +00:00
a87b275796 Update dependency @typescript-eslint/eslint-plugin to v8.18.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-15 00:08:17 +00:00
4454f4a10d Update dependency @fluentui/react-icons to v2.0.269
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-14 01:26:08 +00:00
0a85dc65f2 Update Rust crate thiserror to v2.0.7
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-14 00:09:22 +00:00
77a9c954de Merge pull request 'Update dependency @types/react-dom to v18.3.5' (#169) from renovate/react-dom-18.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #169
2024-12-13 19:31:28 +00:00
bf13e3ac8a Merge pull request 'Update dependency @types/react to v18.3.16' (#168) from renovate/react-18.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #168
2024-12-13 19:31:21 +00:00
7fbdd9c3d3 Update dependency @types/react-dom to v18.3.5
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-13 00:08:28 +00:00
8c3d6240eb Update dependency @types/react to v18.3.16
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-13 00:08:25 +00:00
d344b16a8c Update dependency @fluentui/react-icons to v2.0.267
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-12 01:33:08 +00:00
aa6b20b202 Update Rust crate serde to v1.0.216
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-12 00:08:35 +00:00
3dfa2250ce Merge pull request 'Update dependency @types/react to v18.3.15' (#164) from renovate/react-18.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #164
2024-12-11 18:50:53 +00:00
386a4af108 Update dependency @types/react-dom to v18.3.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-11 00:24:50 +00:00
76b234febb Update dependency @types/react to v18.3.15
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-11 00:24:47 +00:00
45880e212d Update dependency @types/react-dom to v18.3.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-10 01:31:43 +00:00
023ab429fe Update dependency @fluentui/react-components to v9.56.5
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2024-12-10 00:25:00 +00:00
0f9ad94368 Update dependency @typescript-eslint/eslint-plugin to v8.17.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-09 01:43:00 +00:00
d75b0287ad Update Rust crate thiserror to v2.0.6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-09 00:24:52 +00:00
0f24e6dc3e Update dependency vite to v6.0.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-08 01:39:21 +00:00
94ad0398de Update Rust crate thiserror to v2.0.5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-08 00:25:07 +00:00
5305083eca Update dependency @types/react-dom to v18.3.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-07 02:08:46 +00:00
eef867ad19 Update dependency @fluentui/react-components to v9.56.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-07 00:29:26 +00:00
10569459c3 Fix Dockerfile entrypoint specification
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-06 19:09:17 +01:00
4c6608bf55 Add groups support (#146)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #146
2024-12-06 18:06:01 +00:00
aa9222bd22 Update dependency @types/react to v18.3.14
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-06 02:30:38 +00:00
191b041993 Update Rust crate clap to v4.5.23
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-06 00:26:21 +00:00
00b9bd4ab4 Merge pull request 'Update dependency eslint to v9' (#147) from renovate/eslint-9.x into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #147
2024-12-05 22:07:48 +00:00
1c76b51a02 Merge pull request 'Update Rust crate anyhow to v1.0.94' (#150) from renovate/anyhow-1.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #150
2024-12-05 22:07:41 +00:00
533b8d68b9 Merge pull request 'Update dependency @types/react to v18.3.13' (#153) from renovate/react-18.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #153
2024-12-05 22:07:35 +00:00
8678ecdb32 Update dependency @types/react to v18.3.13
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-05 00:26:03 +00:00
f817472485 Update Rust crate thiserror to v2.0.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-05 00:26:01 +00:00
46db385215 Update Rust crate clap to v4.5.22
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-04 00:26:50 +00:00
31c45adbc3 Update Rust crate anyhow to v1.0.94
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-04 00:26:47 +00:00
45b8c1f012 Update dependency vite to v6.0.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-03 01:04:53 +00:00
1ef5bf8848 Update dependency eslint-plugin-react-refresh to v0.4.16
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-12-03 00:24:40 +00:00
ade396460a Update dependency eslint to v9
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-12-01 00:24:55 +00:00
184a106542 Centralize rights management
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-30 10:26:14 +01:00
74ab902180 Updated project dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-30 09:28:09 +01:00
017ce989c0 Update node Docker tag to v23
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-19 02:01:00 +00:00
e8f1b66670 Update Rust crate anyhow to v1.0.90
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-19 00:30:34 +00:00
d0b34f038d Update dependency @typescript-eslint/eslint-plugin to v8.10.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-18 00:30:25 +00:00
9465a5b04f Update Rust crate uuid to v1.11.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-17 00:29:39 +00:00
a09ca8805c Update dependency @fluentui/react-components to v9.55.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-16 00:29:43 +00:00
5dbd41ab19 Update dependency @typescript-eslint/eslint-plugin to v8.9.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-15 00:29:17 +00:00
b8b3b48f6b Update dependency eslint-plugin-react-hooks to v5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-12 00:29:04 +00:00
08c9eee0f2 Update dependency @fluentui/react-components to v9.55.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-10 00:28:22 +00:00
9b467bf907 Update dependency typescript to v5.6.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-09 00:28:49 +00:00
e0a97d8604 Update dependency @typescript-eslint/eslint-plugin to v8.8.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-08 00:28:07 +00:00
b3be9a519a Update Rust crate futures-util to v0.3.31
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-06 00:29:10 +00:00
e8dc523264 Update dependency @types/react to v18.3.11
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-03 00:29:10 +00:00
0053dec503 Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.8.0' (#124) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #124
2024-10-02 20:13:49 +00:00
84feab23c6 Update dependency @typescript-eslint/parser to v8.8.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-02 01:23:54 +00:00
e14e525954 Update Rust crate clap to v4.5.19
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-02 00:32:29 +00:00
57d98e3848 Update dependency @typescript-eslint/eslint-plugin to v8.8.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-01 00:32:41 +00:00
e92aff4570 Update Rust crate reqwest to v0.12.8
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-10-01 00:32:38 +00:00
682036986d Update dependency @vitejs/plugin-react to v4.3.2
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-30 00:32:57 +00:00
c7cfb71935 Update dependency @typescript-eslint/parser to v8.7.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-29 00:31:51 +00:00
4f19bd9b6c Update dependency vite to v5.4.8
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-28 01:22:39 +00:00
329254a432 Update dependency @types/react to v18.3.10
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-28 00:32:00 +00:00
b11a265e56 Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v8.7.0' (#117) from renovate/typescript-eslint-eslint-plugin-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #117
2024-09-27 05:28:32 +00:00
d20c910cd6 Merge pull request 'Update dependency @typescript-eslint/parser to v8.6.0' (#112) from renovate/typescript-eslint-parser-8.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #112
2024-09-27 05:28:19 +00:00
4f3380b029 Merge pull request 'Update dependency @types/react to v18.3.7' (#109) from renovate/react-18.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #109
2024-09-27 05:26:29 +00:00
18dda6ef87 Merge pull request 'Update dependency vite to v5.4.7' (#114) from renovate/vite-5.x-lockfile into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #114
2024-09-27 05:26:09 +00:00
dbd7f119ac Update dependency @fluentui/react-components to v9.54.17
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-27 00:34:06 +00:00
bcc80c8c06 Update dependency @typescript-eslint/eslint-plugin to v8.7.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-09-24 00:17:00 +00:00
4c0fe6214b Update dependency @fluentui/react-components to v9.54.16
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-24 00:13:28 +00:00
2f688b8123 Update Rust crate thiserror to v1.0.64
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-23 00:13:29 +00:00
c96b9677ec Update dependency vite to v5.4.7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-09-21 00:34:57 +00:00
ea4c687e50 Update Rust crate clap to v4.5.18
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-21 00:34:54 +00:00
e90fd1032b Update dependency @typescript-eslint/parser to v8.6.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-09-20 00:35:07 +00:00
1a24598537 Update dependency @typescript-eslint/eslint-plugin to v8.6.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-19 01:13:32 +00:00
f1cdd75e6a Update dependency vite to v5.4.6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-09-19 00:34:54 +00:00
7f863b91dc Update dependency @types/react to v18.3.7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-09-18 00:34:11 +00:00
37 changed files with 4554 additions and 2940 deletions

View File

@ -5,7 +5,7 @@ name: default
steps:
- name: frontend_build
image: node:22
image: node:23
volumes:
- name: frontend_app
path: /tmp/frontend_build

View File

@ -1,4 +1,11 @@
# VirtWeb Remote
WIP project
Web UI that allows to start and stop VMs managed by VirtWEB without having to expose the VirtWEB directly on the Internet.
This project aims to use the VirtWeb API to start and stop VM without directly exposing the VirtWEB API to the Internet.
VirtWebRemote rely on OpenID to authenticate users.
VirtWebRemote authenticates against VirtWEB API using an API token. Both the token ID and private key are required to be able to authenticate against the VirtWEB API.
## Docker image options
```bash
docker run --rm -it pierre42100/virtweb_remote --help
```

1554
remote_backend/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,28 @@
[package]
name = "remote_backend"
version = "0.1.0"
edition = "2021"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4.21"
env_logger = "0.11.3"
clap = { version = "4.5.4", features = ["derive", "env"] }
serde = { version = "1.0.200", features = ["derive"] }
light-openid = { version = "1.0.2", features = ["crypto-wrapper"] }
basic-jwt = "0.2.0"
actix-web = "4.5.1"
log = "0.4.27"
env_logger = "0.11.8"
clap = { version = "4.5.40", features = ["derive", "env"] }
serde = { version = "1.0.219", features = ["derive"] }
light-openid = { version = "1.0.4", features = ["crypto-wrapper"] }
basic-jwt = "0.3.0"
actix-web = "4.10.2"
actix-remote-ip = "0.1.0"
actix-session = { version = "0.10.0", features = ["cookie-session"] }
actix-identity = "0.7.1"
actix-cors = "0.7.0"
lazy_static = "1.4.0"
anyhow = "1.0.83"
reqwest = { version = "0.12.4", features = ["json"] }
thiserror = "1.0.59"
uuid = { version = "1.8.0", features = ["v4", "serde"] }
futures-util = "0.3.30"
lazy-regex = "3.1.0"
mime_guess = "2.0.4"
rust-embed = { version = "8.3.0" }
actix-session = { version = "0.10.1", features = ["cookie-session"] }
actix-identity = "0.8.0"
actix-cors = "0.7.1"
lazy_static = "1.5.0"
anyhow = "1.0.98"
reqwest = { version = "0.12.20", features = ["json"] }
thiserror = "2.0.12"
uuid = { version = "1.16.0", features = ["v4", "serde"] }
futures-util = "0.3.31"
lazy-regex = "3.4.1"
mime_guess = "2.0.5"
rust-embed = { version = "8.7.2" }

View File

@ -6,4 +6,4 @@ RUN apt-get update \
COPY remote_backend /usr/local/bin/remote_backend
ENTRYPOINT /usr/local/bin/remote_backend
ENTRYPOINT ["/usr/local/bin/remote_backend"]

View File

@ -29,7 +29,7 @@ pub struct AppConfig {
#[arg(
long,
env,
default_value = "http://localhost:9001/.well-known/openid-configuration"
default_value = "http://localhost:9001/dex/.well-known/openid-configuration"
)]
pub oidc_configuration_url: String,

View File

@ -1,6 +1,6 @@
use actix_remote_ip::RemoteIP;
use actix_web::web::Data;
use actix_web::{web, HttpResponse, Responder};
use actix_web::{HttpResponse, Responder, web};
use light_openid::basic_state_manager::BasicStateManager;
use crate::app_config::AppConfig;

View File

@ -0,0 +1,79 @@
use crate::controllers::HttpResult;
use crate::virtweb_client;
use crate::virtweb_client::{GroupID, VMUuid};
use actix_web::{HttpResponse, web};
#[derive(serde::Deserialize)]
pub struct GroupIDInPath {
gid: GroupID,
}
#[derive(serde::Deserialize)]
pub struct VMIDInQuery {
vm_id: Option<VMUuid>,
}
/// Get the state of one or all VM
pub async fn vm_state(
path: web::Path<GroupIDInPath>,
query: web::Query<VMIDInQuery>,
) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::group_vm_state(&path.gid, query.vm_id).await?))
}
/// Start one or all VM
pub async fn vm_start(
path: web::Path<GroupIDInPath>,
query: web::Query<VMIDInQuery>,
) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::group_vm_start(&path.gid, query.vm_id).await?))
}
/// Shutdown one or all VM
pub async fn vm_shutdown(
path: web::Path<GroupIDInPath>,
query: web::Query<VMIDInQuery>,
) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::group_vm_shutdown(&path.gid, query.vm_id).await?))
}
/// Kill one or all VM
pub async fn vm_kill(path: web::Path<GroupIDInPath>, query: web::Query<VMIDInQuery>) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::group_vm_kill(&path.gid, query.vm_id).await?))
}
/// Reset one or all VM
pub async fn vm_reset(
path: web::Path<GroupIDInPath>,
query: web::Query<VMIDInQuery>,
) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::group_vm_reset(&path.gid, query.vm_id).await?))
}
/// Suspend one or all VM
pub async fn vm_suspend(
path: web::Path<GroupIDInPath>,
query: web::Query<VMIDInQuery>,
) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::group_vm_suspend(&path.gid, query.vm_id).await?))
}
/// Resume one or all VM
pub async fn vm_resume(
path: web::Path<GroupIDInPath>,
query: web::Query<VMIDInQuery>,
) -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::group_vm_resume(&path.gid, query.vm_id).await?))
}
/// Screenshot one or all VM
pub async fn vm_screenshot(
path: web::Path<GroupIDInPath>,
query: web::Query<VMIDInQuery>,
) -> HttpResult {
let screenshot = virtweb_client::group_vm_screenshot(&path.gid, query.vm_id).await?;
Ok(HttpResponse::Ok()
.insert_header(("content-type", "image/png"))
.body(screenshot))
}

View File

@ -1,11 +1,11 @@
use actix_web::HttpResponse;
use actix_web::body::BoxBody;
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::io::ErrorKind;
pub mod auth_controller;
pub mod group_controller;
pub mod server_controller;
pub mod static_controller;
pub mod sys_info_controller;
@ -51,7 +51,7 @@ impl From<anyhow::Error> for HttpErr {
impl From<Box<dyn Error>> for HttpErr {
fn from(value: Box<dyn Error>) -> Self {
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
HttpErr::Err(std::io::Error::other(value.to_string()).into())
}
}
@ -81,7 +81,7 @@ impl From<reqwest::header::ToStrError> for HttpErr {
impl From<actix_web::Error> for HttpErr {
fn from(value: actix_web::Error) -> Self {
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
HttpErr::Err(std::io::Error::other(value.to_string()).into())
}
}

View File

@ -1,6 +1,8 @@
use crate::app_config::AppConfig;
use crate::controllers::HttpResult;
use crate::extractors::auth_extractor::AuthExtractor;
use crate::virtweb_client;
use crate::virtweb_client::{GroupID, VMCaps, VMInfo};
use actix_web::HttpResponse;
#[derive(serde::Serialize)]
@ -15,3 +17,75 @@ pub async fn config(auth: AuthExtractor) -> HttpResult {
disable_auth: AppConfig::get().unsecure_disable_login,
}))
}
#[derive(Default, Debug, serde::Serialize)]
pub struct Rights {
groups: Vec<GroupInfo>,
vms: Vec<VMInfoAndCaps>,
sys_info: bool,
}
#[derive(Debug, serde::Serialize)]
pub struct GroupInfo {
id: GroupID,
vms: Vec<VMInfo>,
#[serde(flatten)]
caps: VMCaps,
}
#[derive(Debug, serde::Serialize)]
pub struct VMInfoAndCaps {
#[serde(flatten)]
info: VMInfo,
#[serde(flatten)]
caps: VMCaps,
}
pub async fn rights() -> HttpResult {
let rights = virtweb_client::get_token_info().await?;
let mut res = Rights {
groups: vec![],
vms: vec![],
sys_info: rights.can_retrieve_system_info(),
};
for g in rights.list_groups() {
let group_vms = virtweb_client::group_vm_info(&g).await?;
res.groups.push(GroupInfo {
id: g.clone(),
vms: group_vms,
caps: VMCaps {
can_get_state: rights.is_route_allowed("GET", &g.route_vm_state(None)),
can_start: rights.is_route_allowed("GET", &g.route_vm_start(None)),
can_shutdown: rights.is_route_allowed("GET", &g.route_vm_shutdown(None)),
can_kill: rights.is_route_allowed("GET", &g.route_vm_kill(None)),
can_reset: rights.is_route_allowed("GET", &g.route_vm_reset(None)),
can_suspend: rights.is_route_allowed("GET", &g.route_vm_suspend(None)),
can_resume: rights.is_route_allowed("GET", &g.route_vm_resume(None)),
can_screenshot: rights.is_route_allowed("GET", &g.route_vm_screenshot(None)),
},
})
}
for v in rights.list_vm() {
let vm_info = virtweb_client::vm_info(v).await?;
res.vms.push(VMInfoAndCaps {
info: vm_info,
caps: VMCaps {
can_get_state: rights.is_route_allowed("GET", &v.route_state()),
can_start: rights.is_route_allowed("GET", &v.route_start()),
can_shutdown: rights.is_route_allowed("GET", &v.route_shutdown()),
can_kill: rights.is_route_allowed("GET", &v.route_kill()),
can_reset: rights.is_route_allowed("GET", &v.route_reset()),
can_suspend: rights.is_route_allowed("GET", &v.route_suspend()),
can_resume: rights.is_route_allowed("GET", &v.route_resume()),
can_screenshot: rights.is_route_allowed("GET", &v.route_screenshot()),
},
})
}
Ok(HttpResponse::Ok().json(res))
}

View File

@ -18,7 +18,7 @@ mod serve_static_debug {
#[cfg(not(debug_assertions))]
mod serve_static_release {
use actix_web::{web, HttpResponse, Responder};
use actix_web::{HttpResponse, Responder, web};
use rust_embed::RustEmbed;
#[derive(RustEmbed)]

View File

@ -2,20 +2,6 @@ use crate::controllers::HttpResult;
use crate::virtweb_client;
use actix_web::HttpResponse;
#[derive(serde::Serialize)]
struct SysInfoStatus {
allowed: bool,
}
/// Check if system info can be retrieved
pub async fn config() -> HttpResult {
let info = virtweb_client::get_token_info().await?;
Ok(HttpResponse::Ok().json(SysInfoStatus {
allowed: info.can_retrieve_system_info(),
}))
}
/// Get current system status
pub async fn status() -> HttpResult {
Ok(HttpResponse::Ok().json(virtweb_client::get_server_info().await?))

View File

@ -3,55 +3,7 @@
use crate::controllers::HttpResult;
use crate::virtweb_client;
use crate::virtweb_client::VMUuid;
use actix_web::{web, HttpResponse};
#[derive(Debug, serde::Serialize)]
pub struct VMInfoAndCaps {
uiid: VMUuid,
name: String,
description: Option<String>,
architecture: String,
memory: usize,
number_vcpu: usize,
can_get_state: bool,
can_start: bool,
can_shutdown: bool,
can_kill: bool,
can_reset: bool,
can_suspend: bool,
can_resume: bool,
can_screenshot: bool,
}
/// Get the list of VMs that can be controlled by VirtWeb remote
pub async fn list() -> HttpResult {
let rights = virtweb_client::get_token_info().await?;
let mut res = vec![];
for v in rights.list_vm() {
let vm_info = virtweb_client::vm_info(v).await?;
res.push(VMInfoAndCaps {
uiid: vm_info.uuid,
name: vm_info.name,
description: vm_info.description.clone(),
architecture: vm_info.architecture.to_string(),
memory: vm_info.memory,
number_vcpu: vm_info.number_vcpu,
can_get_state: rights.is_route_allowed("GET", &v.route_state()),
can_start: rights.is_route_allowed("GET", &v.route_start()),
can_shutdown: rights.is_route_allowed("GET", &v.route_shutdown()),
can_kill: rights.is_route_allowed("GET", &v.route_kill()),
can_reset: rights.is_route_allowed("GET", &v.route_reset()),
can_suspend: rights.is_route_allowed("GET", &v.route_suspend()),
can_resume: rights.is_route_allowed("GET", &v.route_resume()),
can_screenshot: rights.is_route_allowed("GET", &v.route_screenshot()),
})
}
Ok(HttpResponse::Ok().json(res))
}
use actix_web::{HttpResponse, web};
#[derive(serde::Deserialize)]
pub struct ReqPath {

View File

@ -1,7 +1,7 @@
use actix_identity::Identity;
use actix_web::dev::Payload;
use actix_web::{Error, FromRequest, HttpMessage, HttpRequest};
use futures_util::future::{ready, Ready};
use futures_util::future::{Ready, ready};
use std::fmt::Display;
pub struct AuthExtractor {

View File

@ -1,18 +1,19 @@
use actix_cors::Cors;
use actix_identity::config::LogoutBehaviour;
use actix_identity::IdentityMiddleware;
use actix_identity::config::LogoutBehaviour;
use actix_remote_ip::RemoteIPConfig;
use actix_session::storage::CookieSessionStore;
use actix_session::SessionMiddleware;
use actix_session::storage::CookieSessionStore;
use actix_web::cookie::{Key, SameSite};
use actix_web::middleware::Logger;
use actix_web::web::Data;
use actix_web::{web, App, HttpServer};
use actix_web::{App, HttpServer, web};
use light_openid::basic_state_manager::BasicStateManager;
use remote_backend::app_config::AppConfig;
use remote_backend::constants;
use remote_backend::controllers::{
auth_controller, server_controller, static_controller, sys_info_controller, vm_controller,
auth_controller, group_controller, server_controller, static_controller, sys_info_controller,
vm_controller,
};
use remote_backend::middlewares::auth_middleware::AuthChecker;
use std::time::Duration;
@ -82,8 +83,44 @@ async fn main() -> std::io::Result<()> {
"/api/auth/sign_out",
web::get().to(auth_controller::sign_out),
)
.route(
"/api/server/rights",
web::get().to(server_controller::rights),
)
// Groups routes
.route(
"/api/group/{gid}/vm/state",
web::get().to(group_controller::vm_state),
)
.route(
"/api/group/{gid}/vm/start",
web::get().to(group_controller::vm_start),
)
.route(
"/api/group/{gid}/vm/shutdown",
web::get().to(group_controller::vm_shutdown),
)
.route(
"/api/group/{gid}/vm/kill",
web::get().to(group_controller::vm_kill),
)
.route(
"/api/group/{gid}/vm/reset",
web::get().to(group_controller::vm_reset),
)
.route(
"/api/group/{gid}/vm/suspend",
web::get().to(group_controller::vm_suspend),
)
.route(
"/api/group/{gid}/vm/resume",
web::get().to(group_controller::vm_resume),
)
.route(
"/api/group/{gid}/vm/screenshot",
web::get().to(group_controller::vm_screenshot),
)
// VM routes
.route("/api/vm/list", web::get().to(vm_controller::list))
.route("/api/vm/{uid}/state", web::get().to(vm_controller::state))
.route("/api/vm/{uid}/start", web::get().to(vm_controller::start))
.route(
@ -102,10 +139,6 @@ async fn main() -> std::io::Result<()> {
web::get().to(vm_controller::screenshot),
)
// Sys info routes
.route(
"/api/sysinfo/config",
web::get().to(sys_info_controller::config),
)
.route(
"/api/sysinfo/status",
web::get().to(sys_info_controller::status),

View File

@ -1,4 +1,4 @@
use std::future::{ready, Ready};
use std::future::{Ready, ready};
use std::rc::Rc;
use crate::app_config::AppConfig;
@ -7,8 +7,8 @@ use crate::extractors::auth_extractor::AuthExtractor;
use actix_web::body::EitherBody;
use actix_web::dev::Payload;
use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
Error, FromRequest, HttpResponse,
dev::{Service, ServiceRequest, ServiceResponse, Transform, forward_ready},
};
use futures_util::future::LocalBoxFuture;

View File

@ -1,6 +1,7 @@
use crate::app_config::AppConfig;
use crate::utils::time;
use lazy_regex::regex;
use std::collections::HashMap;
use std::fmt::Display;
use std::str::FromStr;
use thiserror::Error;
@ -12,9 +13,105 @@ pub enum VirtWebClientError {
InvalidStatusCode(u16),
}
#[derive(Eq, PartialEq, Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Eq, PartialEq, Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GroupID(String);
impl GroupID {
pub fn route_vm_info(&self) -> String {
format!("/api/group/{}/vm/info", self.0)
}
pub fn route_vm_state(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/state{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
pub fn route_vm_start(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/start{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
pub fn route_vm_shutdown(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/shutdown{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
pub fn route_vm_suspend(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/suspend{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
pub fn route_vm_resume(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/resume{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
pub fn route_vm_kill(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/kill{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
pub fn route_vm_reset(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/reset{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
pub fn route_vm_screenshot(&self, vm: Option<VMUuid>) -> String {
format!(
"/api/group/{}/vm/screenshot{}",
self.0,
match vm {
None => "".to_string(),
Some(id) => format!("?vm_id={}", id.0),
}
)
}
}
#[derive(Eq, PartialEq, Debug, Copy, Clone, serde::Serialize, serde::Deserialize, Hash)]
pub struct VMUuid(Uuid);
#[derive(Default, serde::Deserialize, serde::Serialize)]
pub struct TreatmentResult {
ok: usize,
failed: usize,
}
impl VMUuid {
pub fn route_info(&self) -> String {
format!("/api/vm/{}", self.0)
@ -69,7 +166,7 @@ pub struct TokenClaims {
pub nonce: String,
}
#[derive(serde::Deserialize, Debug)]
#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct VMInfo {
pub uuid: VMUuid,
pub name: String,
@ -79,6 +176,18 @@ pub struct VMInfo {
pub number_vcpu: usize,
}
#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct VMCaps {
pub can_get_state: bool,
pub can_start: bool,
pub can_shutdown: bool,
pub can_kill: bool,
pub can_reset: bool,
pub can_suspend: bool,
pub can_resume: bool,
pub can_screenshot: bool,
}
#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct VMState {
pub state: String,
@ -147,6 +256,16 @@ impl TokenInfo {
false
}
/// List the groups with access
pub fn list_groups(&self) -> Vec<GroupID> {
self.rights
.iter()
.filter(|r| r.verb == "GET")
.filter(|r| regex!("^/api/group/[^/]+/vm/info$").is_match(&r.path))
.map(|r| GroupID(r.path.split("/").nth(3).unwrap().to_string()))
.collect::<Vec<_>>()
}
/// List the virtual machines with access
pub fn list_vm(&self) -> Vec<VMUuid> {
self.rights
@ -168,12 +287,13 @@ async fn request<D: Display>(uri: D) -> anyhow::Result<reqwest::Response> {
let url = format!("{}{}", AppConfig::get().virtweb_base_url, uri);
log::debug!("Will query {uri}...");
let uri = uri.to_string();
let jwt = TokenClaims {
sub: AppConfig::get().virtweb_token_id.to_string(),
iat: time() - 60 * 2,
exp: time() + 60 * 3,
verb: "GET".to_string(),
path: uri.to_string(),
path: uri.split_once('?').map(|s| s.0).unwrap_or(&uri).to_string(),
nonce: Uuid::new_v4().to_string(),
};
let jwt = AppConfig::get().token_private_key().sign_jwt(&jwt)?;
@ -260,6 +380,73 @@ pub async fn vm_screenshot(id: VMUuid) -> anyhow::Result<Vec<u8>> {
.to_vec())
}
/// Get the VM of a group
pub async fn group_vm_info(id: &GroupID) -> anyhow::Result<Vec<VMInfo>> {
json_request(id.route_vm_info()).await
}
/// Get the state of one or all VMs of a group
pub async fn group_vm_state(
id: &GroupID,
vm_id: Option<VMUuid>,
) -> anyhow::Result<HashMap<VMUuid, String>> {
json_request(id.route_vm_state(vm_id)).await
}
/// Start one or all VMs of a group
pub async fn group_vm_start(
id: &GroupID,
vm_id: Option<VMUuid>,
) -> anyhow::Result<TreatmentResult> {
json_request(id.route_vm_start(vm_id)).await
}
/// Shutdown one or all VMs of a group
pub async fn group_vm_shutdown(
id: &GroupID,
vm_id: Option<VMUuid>,
) -> anyhow::Result<TreatmentResult> {
json_request(id.route_vm_shutdown(vm_id)).await
}
/// Kill one or all VMs of a group
pub async fn group_vm_kill(id: &GroupID, vm_id: Option<VMUuid>) -> anyhow::Result<TreatmentResult> {
json_request(id.route_vm_kill(vm_id)).await
}
/// Reset one or all VMs of a group
pub async fn group_vm_reset(
id: &GroupID,
vm_id: Option<VMUuid>,
) -> anyhow::Result<TreatmentResult> {
json_request(id.route_vm_reset(vm_id)).await
}
/// Suspend one or all VMs of a group
pub async fn group_vm_suspend(
id: &GroupID,
vm_id: Option<VMUuid>,
) -> anyhow::Result<TreatmentResult> {
json_request(id.route_vm_suspend(vm_id)).await
}
/// Resume one or all VMs of a group
pub async fn group_vm_resume(
id: &GroupID,
vm_id: Option<VMUuid>,
) -> anyhow::Result<TreatmentResult> {
json_request(id.route_vm_resume(vm_id)).await
}
/// Get the screenshot of one or all VMs of a group
pub async fn group_vm_screenshot(id: &GroupID, vm_id: Option<VMUuid>) -> anyhow::Result<Vec<u8>> {
Ok(request(id.route_vm_screenshot(vm_id))
.await?
.bytes()
.await?
.to_vec())
}
/// Get current server information
pub async fn get_server_info() -> anyhow::Result<SystemInfo> {
json_request("/api/server/info").await

View File

@ -1,18 +0,0 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}

View File

@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)

File diff suppressed because it is too large Load Diff

View File

@ -10,22 +10,25 @@
"preview": "vite preview"
},
"dependencies": {
"@fluentui/react-components": "^9.49.2",
"@fluentui/react-icons": "^2.0.239",
"filesize": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"@fluentui/react-components": "^9.66.1",
"@fluentui/react-icons": "^2.0.303",
"filesize": "^10.1.6",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.2.0",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"typescript": "^5.2.2",
"vite": "^5.2.11"
"@eslint/js": "^9.29.0",
"@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7",
"@typescript-eslint/eslint-plugin": "^8.34.1",
"@typescript-eslint/parser": "^8.34.1",
"@vitejs/plugin-react": "^4.4.1",
"eslint": "^9.29.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.1.0",
"typescript": "^5.8.3",
"typescript-eslint": "^8.32.1",
"vite": "^6.3.5"
}
}

View File

@ -5,6 +5,8 @@ import {
typographyStyles,
} from "@fluentui/react-components";
import {
AppsListDetailFilled,
AppsListDetailRegular,
DesktopFilled,
DesktopRegular,
InfoFilled,
@ -12,12 +14,13 @@ import {
bundleIcon,
} from "@fluentui/react-icons";
import React from "react";
import { ServerApi } from "./api/ServerApi";
import { Rights, ServerApi } from "./api/ServerApi";
import { AuthRouteWidget } from "./routes/AuthRouteWidget";
import { AsyncWidget } from "./widgets/AsyncWidget";
import { MainMenu } from "./widgets/MainMenu";
import { SystemInfoWidget } from "./widgets/SystemInfoWidget";
import { VirtualMachinesWidget } from "./widgets/VirtualMachinesWidget";
import { GroupsWidget } from "./widgets/GroupsWidget";
const useStyles = makeStyles({
title: typographyStyles.title2,
@ -27,6 +30,8 @@ const InfoIcon = bundleIcon(InfoFilled, InfoRegular);
const DesktopIcon = bundleIcon(DesktopFilled, DesktopRegular);
const AppListIcon = bundleIcon(AppsListDetailFilled, AppsListDetailRegular);
export function App() {
return (
<AsyncWidget
@ -40,45 +45,79 @@ export function App() {
}
function AppInner(): React.ReactElement {
const styles = useStyles();
const [tab, setTab] = React.useState<"vm" | "info">("vm");
if (!ServerApi.Config.authenticated && !ServerApi.Config.disable_auth)
return <AuthRouteWidget />;
return <AuthenticatedApp />;
}
function AuthenticatedApp(): React.ReactElement {
const styles = useStyles();
const [tab, setTab] = React.useState<"group" | "vm" | "info">("group");
const [rights, setRights] = React.useState<Rights | undefined>();
const load = async () => {
const rights = await ServerApi.GetRights();
setRights(rights);
if (rights!.groups.length > 0) setTab("group");
else if (rights!.vms.length > 0) setTab("vm");
else setTab("info");
};
return (
<div
style={{
width: "95%",
maxWidth: "1000px",
margin: "50px auto",
<AsyncWidget
loadKey={1}
load={load}
errMsg="Failed to retrieve application rights!"
build={() => {
return (
<div
style={{
width: "95%",
maxWidth: "1000px",
margin: "50px auto",
}}
>
<span className={styles.title}>VirtWebRemote</span>
<div
style={{
display: "flex",
justifyContent: "space-between",
marginTop: "30px",
}}
>
<TabList
selectedValue={tab}
onTabSelect={(_, d) => setTab(d.value as any)}
>
{rights!.groups.length > 0 && (
<Tab value="group" icon={<AppListIcon />}>
Groups
</Tab>
)}
{rights!.vms.length > 0 && (
<Tab value="vm" icon={<DesktopIcon />}>
Virtual machines
</Tab>
)}
{rights!.sys_info && (
<Tab value="info" icon={<InfoIcon />}>
System info
</Tab>
)}
</TabList>
<div>
<MainMenu />
</div>
</div>
{tab === "group" && <GroupsWidget rights={rights!} />}
{tab === "vm" && <VirtualMachinesWidget rights={rights!} />}
{tab === "info" && <SystemInfoWidget />}
</div>
);
}}
>
<span className={styles.title}>VirtWebRemote</span>
<div
style={{
display: "flex",
justifyContent: "space-between",
marginTop: "30px",
}}
>
<TabList
selectedValue={tab}
onTabSelect={(_, d) => setTab(d.value as any)}
>
<Tab value="vm" icon={<DesktopIcon />}>
Virtual machines
</Tab>
<Tab value="info" icon={<InfoIcon />}>
System info
</Tab>
</TabList>
<div>
<MainMenu />
</div>
</div>
{tab === "vm" && <VirtualMachinesWidget />}
{tab === "info" && <SystemInfoWidget />}
</div>
/>
);
}

View File

@ -0,0 +1,107 @@
import { APIClient } from "./ApiClient";
import { VMGroup } from "./ServerApi";
import { VMInfo, VMState } from "./VMApi";
export interface GroupVMState {
[key: string]: VMState;
}
export interface TreatmentResult {
ok: number;
failed: number;
}
export class GroupApi {
/**
* Get the state of the VMs of a group
*/
static async State(g: VMGroup): Promise<GroupVMState> {
return (
await APIClient.exec({ method: "GET", uri: `/group/${g.id}/vm/state` })
).data;
}
/**
* Request to start the VM of a group
*/
static async StartVM(g: VMGroup, vm?: VMInfo): Promise<TreatmentResult> {
return (
await APIClient.exec({
method: "GET",
uri: `/group/${g.id}/vm/start` + (vm ? `?vm_id=${vm.uuid}` : ""),
})
).data;
}
/**
* Request to suspend the VM of a group
*/
static async SuspendVM(g: VMGroup, vm?: VMInfo): Promise<TreatmentResult> {
return (
await APIClient.exec({
method: "GET",
uri: `/group/${g.id}/vm/suspend` + (vm ? `?vm_id=${vm.uuid}` : ""),
})
).data;
}
/**
* Request to resume the VM of a group
*/
static async ResumeVM(g: VMGroup, vm?: VMInfo): Promise<TreatmentResult> {
return (
await APIClient.exec({
method: "GET",
uri: `/group/${g.id}/vm/resume` + (vm ? `?vm_id=${vm.uuid}` : ""),
})
).data;
}
/**
* Request to shutdown the VM of a group
*/
static async ShutdownVM(g: VMGroup, vm?: VMInfo): Promise<TreatmentResult> {
return (
await APIClient.exec({
method: "GET",
uri: `/group/${g.id}/vm/shutdown` + (vm ? `?vm_id=${vm.uuid}` : ""),
})
).data;
}
/**
* Request to kill the VM of a group
*/
static async KillVM(g: VMGroup, vm?: VMInfo): Promise<TreatmentResult> {
return (
await APIClient.exec({
method: "GET",
uri: `/group/${g.id}/vm/kill` + (vm ? `?vm_id=${vm.uuid}` : ""),
})
).data;
}
/**
* Request to reset the VM of a group
*/
static async ResetVM(g: VMGroup, vm?: VMInfo): Promise<TreatmentResult> {
return (
await APIClient.exec({
method: "GET",
uri: `/group/${g.id}/vm/reset` + (vm ? `?vm_id=${vm.uuid}` : ""),
})
).data;
}
/**
* Request a screenshot of the VM of group
*/
static async ScreenshotVM(g: VMGroup, vm?: VMInfo): Promise<Blob> {
return (
await APIClient.exec({
method: "GET",
uri: `/group/${g.id}/vm/screenshot` + (vm ? `?vm_id=${vm.uuid}` : ""),
})
).data;
}
}

View File

@ -1,10 +1,24 @@
import { APIClient } from "./ApiClient";
import { VMCaps, VMInfo, VMInfoAndCaps } from "./VMApi";
export interface ServerConfig {
authenticated: boolean;
disable_auth: boolean;
}
export interface Rights {
groups: VMGroup[];
vms: VMInfoAndCaps[];
sys_info: boolean;
}
export type VMGroup = VMGroupInfo & VMCaps;
export interface VMGroupInfo {
id: string;
vms: VMInfo[];
}
let config: ServerConfig | null = null;
export class ServerApi {
@ -27,4 +41,16 @@ export class ServerApi {
if (config === null) throw new Error("Missing configuration!");
return config;
}
/**
* Get application rights
*/
static async GetRights(): Promise<Rights> {
return (
await APIClient.exec({
uri: "/server/rights",
method: "GET",
})
).data;
}
}

View File

@ -1,9 +1,5 @@
import { APIClient } from "./ApiClient";
export interface SysInfoConfig {
allowed: boolean;
}
export interface LoadAverage {
one: number;
five: number;
@ -24,14 +20,6 @@ export interface SysInfoStatus {
}
export class SysInfoApi {
/**
* Get system info configuration (ie. check if it allowed)
*/
static async GetConfig(): Promise<SysInfoConfig> {
return (await APIClient.exec({ method: "GET", uri: "/sysinfo/config" }))
.data;
}
/**
* Get system status
*/

View File

@ -1,12 +1,15 @@
import { APIClient } from "./ApiClient";
export interface VMInfo {
uiid: string;
uuid: string;
name: string;
description?: string;
architecture: string;
memory: number;
number_vcpu: number;
}
export interface VMCaps {
can_get_state: boolean;
can_start: boolean;
can_shutdown: boolean;
@ -17,6 +20,8 @@ export interface VMInfo {
can_screenshot: boolean;
}
export type VMInfoAndCaps = VMInfo & VMCaps;
export type VMState =
| "NoState"
| "Running"
@ -29,19 +34,12 @@ export type VMState =
| "Other";
export class VMApi {
/**
* Get the list of VM that can be managed by this console
*/
static async GetList(): Promise<VMInfo[]> {
return (await APIClient.exec({ method: "GET", uri: "/vm/list" })).data;
}
/**
* Get the state of a VM
*/
static async State(vm: VMInfo): Promise<VMState> {
return (
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uiid}/state` })
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uuid}/state` })
).data.state;
}
@ -49,42 +47,42 @@ export class VMApi {
* Request to start VM
*/
static async StartVM(vm: VMInfo): Promise<void> {
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uiid}/start` });
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uuid}/start` });
}
/**
* Request to suspend VM
*/
static async SuspendVM(vm: VMInfo): Promise<void> {
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uiid}/suspend` });
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uuid}/suspend` });
}
/**
* Request to resume VM
*/
static async ResumeVM(vm: VMInfo): Promise<void> {
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uiid}/resume` });
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uuid}/resume` });
}
/**
* Request to shutdown VM
*/
static async ShutdownVM(vm: VMInfo): Promise<void> {
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uiid}/shutdown` });
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uuid}/shutdown` });
}
/**
* Request to kill VM
*/
static async KillVM(vm: VMInfo): Promise<void> {
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uiid}/kill` });
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uuid}/kill` });
}
/**
* Request to reset VM
*/
static async ResetVM(vm: VMInfo): Promise<void> {
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uiid}/reset` });
await APIClient.exec({ method: "GET", uri: `/vm/${vm.uuid}/reset` });
}
/**
@ -93,7 +91,7 @@ export class VMApi {
static async Screenshot(vm: VMInfo): Promise<Blob> {
return (
await APIClient.exec({
uri: `/vm/${vm.uiid}/screenshot`,
uri: `/vm/${vm.uuid}/screenshot`,
method: "GET",
})
).data;

View File

@ -20,7 +20,7 @@ type ThemeContext = { theme: Theme; set: (theme: Theme) => void };
const ThemeContextK = React.createContext<ThemeContext | null>(null);
export function ThemeProvider(p: React.PropsWithChildren): React.ReactElement {
const [theme, setTheme] = React.useState<Theme>("highcontrast");
const [theme, setTheme] = React.useState<Theme>("teamsdark");
let fluentTheme = teamsHighContrastTheme;
switch (theme) {

View File

@ -0,0 +1,177 @@
import { Button, Spinner, Toolbar, Tooltip } from "@fluentui/react-components";
import {
ArrowResetRegular,
PauseRegular,
PlayCircleRegular,
PlayFilled,
PowerRegular,
StopRegular,
} from "@fluentui/react-icons";
import React from "react";
import { GroupApi, TreatmentResult } from "../api/GroupApi";
import { VMGroup } from "../api/ServerApi";
import { VMInfo, VMState } from "../api/VMApi";
import { useAlert } from "../hooks/providers/AlertDialogProvider";
import { useConfirm } from "../hooks/providers/ConfirmDialogProvider";
import { useToast } from "../hooks/providers/ToastProvider";
export function GroupVMAction(p: {
group: VMGroup;
state?: VMState;
vm?: VMInfo;
}): React.ReactElement {
return (
<Toolbar>
<GroupVMButton
enabled={p.group.can_start}
icon={<PlayFilled />}
tooltip="Start"
group={p.group}
vm={p.vm}
allowedStates={["Shutdown", "Shutoff", "Crashed"]}
currState={p.state}
needConfirm={false}
action={GroupApi.StartVM}
/>
<GroupVMButton
enabled={p.group.can_suspend}
icon={<PauseRegular />}
tooltip="Suspend"
group={p.group}
vm={p.vm}
allowedStates={["Running"]}
currState={p.state}
needConfirm={true}
action={GroupApi.SuspendVM}
/>
<GroupVMButton
enabled={p.group.can_resume}
icon={<PlayCircleRegular />}
tooltip="Resume"
group={p.group}
vm={p.vm}
allowedStates={["Paused", "PowerManagementSuspended"]}
currState={p.state}
needConfirm={false}
action={GroupApi.ResumeVM}
/>
<GroupVMButton
enabled={p.group.can_shutdown}
icon={<PowerRegular />}
tooltip="Shutdown"
group={p.group}
vm={p.vm}
allowedStates={["Running"]}
currState={p.state}
needConfirm={true}
action={GroupApi.ShutdownVM}
/>
<GroupVMButton
enabled={p.group.can_kill}
icon={<StopRegular />}
tooltip="Kill"
group={p.group}
vm={p.vm}
allowedStates={[
"Running",
"Paused",
"PowerManagementSuspended",
"Blocked",
]}
currState={p.state}
needConfirm={true}
action={GroupApi.KillVM}
/>
<GroupVMButton
enabled={p.group.can_reset}
icon={<ArrowResetRegular />}
tooltip="Reset"
group={p.group}
vm={p.vm}
allowedStates={[
"Running",
"Paused",
"PowerManagementSuspended",
"Blocked",
]}
currState={p.state}
needConfirm={true}
action={GroupApi.ResetVM}
/>
</Toolbar>
);
}
function GroupVMButton(p: {
enabled: boolean;
icon: React.ReactElement;
action: (group: VMGroup, vm?: VMInfo) => Promise<TreatmentResult>;
tooltip: string;
currState?: VMState;
allowedStates: VMState[];
group: VMGroup;
vm?: VMInfo;
needConfirm: boolean;
}): React.ReactElement {
const toast = useToast();
const confirm = useConfirm();
const alert = useAlert();
const [running, setRunning] = React.useState(false);
const target = p.vm
? `the VM ${p.vm.name}`
: `all the VM of the group ${p.group.id}`;
const allowed =
!p.vm || (p.currState && p.allowedStates.includes(p.currState));
const perform = async () => {
if (running || !allowed) return;
try {
if (
(!p.vm || p.needConfirm) &&
!(await confirm(
`Do you want to perform ${p.tooltip} action on ${target}?`,
`Confirmation`,
p.tooltip
))
) {
return;
}
setRunning(true);
const result = await p.action(p.group, p.vm);
toast(
p.tooltip,
`${p.tooltip} action on ${target}: ${result.ok} OK / ${result.failed} Failed`,
"success"
);
} catch (e) {
console.error("Failed to perform group action!", e);
alert(`Failed to perform ${p.tooltip} action on ${target}: ${e}`);
} finally {
setRunning(false);
}
};
if (!p.enabled) return <></>;
return (
<Tooltip
content={`${p.tooltip} ${target}`}
relationship="description"
withArrow
>
<Button
icon={running ? <Spinner size="tiny" /> : p.icon}
onClick={allowed ? perform : undefined}
disabled={!allowed}
appearance="subtle"
/>
</Tooltip>
);
}

View File

@ -0,0 +1,171 @@
import {
Button,
Card,
Dialog,
DialogActions,
DialogBody,
DialogContent,
DialogSurface,
DialogTitle,
DialogTrigger,
Table,
TableBody,
TableCell,
TableCellActions,
TableCellLayout,
TableHeader,
TableHeaderCell,
TableRow,
Title3,
Tooltip,
} from "@fluentui/react-components";
import { Desktop24Regular, ScreenshotRegular } from "@fluentui/react-icons";
import { filesize } from "filesize";
import React from "react";
import { GroupApi, GroupVMState } from "../api/GroupApi";
import { Rights, VMGroup } from "../api/ServerApi";
import { VMInfo } from "../api/VMApi";
import { useToast } from "../hooks/providers/ToastProvider";
import { GroupVMAction } from "./GroupVMAction";
import { VMLiveScreenshot } from "./VMLiveScreenshot";
export function GroupsWidget(p: { rights: Rights }): React.ReactElement {
return (
<>
{p.rights.groups.map((g) => (
<GroupInfo group={g} />
))}
</>
);
}
function GroupInfo(p: { group: VMGroup }): React.ReactElement {
const toast = useToast();
const [state, setState] = React.useState<GroupVMState | undefined>();
const [screenshotVM, setScreenshotVM] = React.useState<VMInfo | undefined>();
const load = async () => {
const newState = await GroupApi.State(p.group);
if (state !== newState) setState(newState);
};
const screenshot = (vm: VMInfo) => {
setScreenshotVM(vm);
};
React.useEffect(() => {
const interval = setInterval(async () => {
try {
if (p.group.can_get_state) await load();
} catch (e) {
console.error(e);
toast(
"Error",
`Failed to refresh group ${p.group.id} VMs status!`,
"error"
);
}
}, 1000);
return () => clearInterval(interval);
});
return (
<>
<Card
style={{
margin: "50px 10px",
display: "flex",
flexDirection: "column",
}}
>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<Title3 style={{ marginLeft: "10px" }}>{p.group.id}</Title3>
<GroupVMAction group={p.group} />
</div>
<Table sortable>
<TableHeader>
<TableRow>
<TableHeaderCell>VM</TableHeaderCell>
<TableHeaderCell>Resources</TableHeaderCell>
<TableHeaderCell>State</TableHeaderCell>
<TableHeaderCell>Actions</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
{p.group.vms.map((item) => (
<TableRow key={item.uuid}>
<TableCell>
<TableCellLayout
media={<Desktop24Regular />}
appearance="primary"
description={item.description}
>
{item.name}
</TableCellLayout>
<TableCellActions>
{state?.[item.uuid] === "Running" && (
<Tooltip
relationship="description"
content={"Take a screenshot of the VM screen"}
withArrow
>
<Button
icon={<ScreenshotRegular />}
appearance="subtle"
aria-label="Edit"
disabled={!p.group.can_screenshot}
onClick={() => screenshot(item)}
/>
</Tooltip>
)}
</TableCellActions>
</TableCell>
<TableCell>
{item.architecture} &bull; RAM :{" "}
{filesize(item.memory * 1000 * 1000)} &bull;{" "}
{item.number_vcpu} vCPU
</TableCell>
<TableCell>{state?.[item.uuid] ?? ""}</TableCell>
<TableCell>
<GroupVMAction
group={p.group}
state={state?.[item.uuid]}
vm={item}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Card>
<Dialog
open={!!screenshotVM}
onOpenChange={(_event, _data) => {
if (!screenshotVM) setScreenshotVM(undefined);
}}
>
<DialogSurface>
<DialogBody>
<DialogTitle>
<em>{screenshotVM?.name}</em> screen
</DialogTitle>
<DialogContent>
<VMLiveScreenshot vm={screenshotVM!} group={p.group} />
</DialogContent>
<DialogActions>
<DialogTrigger disableButtonEnhancement>
<Button
appearance="secondary"
onClick={() => setScreenshotVM(undefined)}
>
Close
</Button>
</DialogTrigger>
</DialogActions>
</DialogBody>
</DialogSurface>
</Dialog>
</>
);
}

View File

@ -1,47 +1,13 @@
import React from "react";
import { SysInfoApi, SysInfoConfig, SysInfoStatus } from "../api/SysInfoApi";
import { AsyncWidget } from "./AsyncWidget";
import { SectionContainer } from "./SectionContainer";
import { Field, ProgressBar } from "@fluentui/react-components";
import { filesize } from "filesize";
import { format_duration } from "../utils/time_utils";
import React from "react";
import { SysInfoApi, SysInfoStatus } from "../api/SysInfoApi";
import { useToast } from "../hooks/providers/ToastProvider";
import { format_duration } from "../utils/time_utils";
import { AsyncWidget } from "./AsyncWidget";
import { SectionContainer } from "./SectionContainer";
export function SystemInfoWidget(): React.ReactElement {
const [config, setConfig] = React.useState<SysInfoConfig | undefined>();
const load = async () => {
setConfig(await SysInfoApi.GetConfig());
};
return (
<SectionContainer>
<AsyncWidget
loadKey={1}
load={load}
errMsg="Failed to check system configuration!"
loadingMessage="Checking server configuration..."
build={() =>
config?.allowed ? (
<SystemInfoWidgetInner />
) : (
<SystemInfoWidgetUnavailable />
)
}
/>
</SectionContainer>
);
}
function SystemInfoWidgetUnavailable(): React.ReactElement {
return (
<p style={{ textAlign: "center" }}>
Unfortunatley, system information is available. (not enough privileges)
</p>
);
}
function SystemInfoWidgetInner(): React.ReactElement {
const toast = useToast();
const [status, setStatus] = React.useState<SysInfoStatus | undefined>();
@ -63,49 +29,51 @@ function SystemInfoWidgetInner(): React.ReactElement {
});
return (
<AsyncWidget
loadKey={1}
load={load}
loadingMessage="Loading system status..."
errMsg="Failed to load system status!"
build={() => (
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
}}
>
<Field
validationMessage={`${filesize(
status!.system.used_memory
)} of memory used out of ${filesize(
status!.system.available_memory + status!.system.used_memory
)}`}
validationState="none"
style={{ flex: 2 }}
<SectionContainer>
<AsyncWidget
loadKey={1}
load={load}
loadingMessage="Loading system status..."
errMsg="Failed to load system status!"
build={() => (
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
}}
>
<ProgressBar
value={
status!.system.used_memory /
(status!.system.available_memory + status!.system.used_memory)
}
/>
</Field>
<div style={{ width: "20px" }}></div>
<div style={{ flex: 1 }}>
<p>
Load average: {status!.system.load_average.one}{" "}
{status!.system.load_average.five}{" "}
{status!.system.load_average.fifteen}
</p>
<UptimeWidget uptime={status!.system.uptime} />
Number physical cores: {status!.system.physical_core_count}
<Field
validationMessage={`${filesize(
status!.system.used_memory
)} of memory used out of ${filesize(
status!.system.available_memory + status!.system.used_memory
)}`}
validationState="none"
style={{ flex: 2 }}
>
<ProgressBar
value={
status!.system.used_memory /
(status!.system.available_memory + status!.system.used_memory)
}
/>
</Field>
<div style={{ width: "20px" }}></div>
<div style={{ flex: 1 }}>
<p>
Load average: {status!.system.load_average.one}{" "}
{status!.system.load_average.five}{" "}
{status!.system.load_average.fifteen}
</p>
<UptimeWidget uptime={status!.system.uptime} />
Number physical cores: {status!.system.physical_core_count}
</div>
</div>
</div>
)}
/>
)}
/>
</SectionContainer>
);
}

View File

@ -1,8 +1,13 @@
import React from "react";
import { GroupApi } from "../api/GroupApi";
import { VMGroup } from "../api/ServerApi";
import { VMApi, VMInfo } from "../api/VMApi";
import { useToast } from "../hooks/providers/ToastProvider";
export function VMLiveScreenshot(p: { vm: VMInfo }): React.ReactElement {
export function VMLiveScreenshot(p: {
vm: VMInfo;
group?: VMGroup;
}): React.ReactElement {
const toast = useToast();
const [screenshotURL, setScreenshotURL] = React.useState<
@ -14,7 +19,9 @@ export function VMLiveScreenshot(p: { vm: VMInfo }): React.ReactElement {
React.useEffect(() => {
const refresh = async () => {
try {
const screenshot = await VMApi.Screenshot(p.vm);
const screenshot = p.group
? await GroupApi.ScreenshotVM(p.group, p.vm)
: await VMApi.Screenshot(p.vm);
const u = URL.createObjectURL(screenshot);
setScreenshotURL(u);
} catch (e) {

View File

@ -21,10 +21,10 @@ import {
} from "@fluentui/react-icons";
import { filesize } from "filesize";
import React from "react";
import { VMApi, VMInfo, VMState } from "../api/VMApi";
import { Rights } from "../api/ServerApi";
import { VMApi, VMInfo, VMInfoAndCaps, VMState } from "../api/VMApi";
import { useConfirm } from "../hooks/providers/ConfirmDialogProvider";
import { useToast } from "../hooks/providers/ToastProvider";
import { AsyncWidget } from "./AsyncWidget";
import { SectionContainer } from "./SectionContainer";
import { VMLiveScreenshot } from "./VMLiveScreenshot";
@ -33,43 +33,28 @@ const useStyles = makeStyles({
caption1: typographyStyles.caption1,
});
export function VirtualMachinesWidget(): React.ReactElement {
const [list, setList] = React.useState<VMInfo[] | undefined>();
const load = async () => {
setList(await VMApi.GetList());
};
export function VirtualMachinesWidget(p: {
rights: Rights;
}): React.ReactElement {
return (
<SectionContainer>
<AsyncWidget
loadKey={1}
load={load}
loadingMessage="Loading the list virtual machines..."
errMsg="Failed to load the list of virtual machines!"
build={() => <VirtualMachinesWidgetInner list={list!} />}
/>
<div
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "center",
}}
>
{p.rights.vms.map((v, n) => (
<VMWidget key={n} vm={v} />
))}
</div>
</SectionContainer>
);
}
function VirtualMachinesWidgetInner(p: { list: VMInfo[] }): React.ReactElement {
return (
<div
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "center",
}}
>
{p.list.map((v, n) => (
<VMWidget key={n} vm={v} />
))}{" "}
</div>
);
}
function VMWidget(p: { vm: VMInfo }): React.ReactElement {
function VMWidget(p: { vm: VMInfoAndCaps }): React.ReactElement {
const toast = useToast();
const [state, setState] = React.useState<VMState | undefined>();
@ -204,7 +189,10 @@ function VMWidget(p: { vm: VMInfo }): React.ReactElement {
);
}
function VMPreview(p: { vm: VMInfo; state?: VMState }): React.ReactElement {
function VMPreview(p: {
vm: VMInfoAndCaps;
state?: VMState;
}): React.ReactElement {
const styles = useStyles();
if (!p.vm.can_screenshot || p.state !== "Running") {
return (

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}

View File

@ -1,25 +1,7 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

View File

@ -1,11 +1,24 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -1,7 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})

View File

@ -1,9 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"matchUpdateTypes": ["major", "minor", "patch"],
"automerge": true
}
]
"extends": ["local>renovate/presets"]
}