[Add] Main UI with LogCard

This commit is contained in:
Alex Emmet 2026-02-18 20:31:44 +01:00
commit 9416a9744f
17 changed files with 214 additions and 712 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
target target
logs

View file

@ -1,13 +0,0 @@
1771405721036 IOTA ID: 0
1771405721036 User IDS:
1771405721046 Community IDS:
1771405721047 TLS certificate 'certs/cert.pem' not found.
1771405721047 HTTP Server running on 0.0.0.0:1984
1771405721048 Communities active on ws://10.209.226.34:1984/community/...
1771405721048 Downloading ZIP file...
1771405721507 Failed to download file: Status 404 Not Found
1771405721507 Error downloading file: Failed to download file: Status 404 Not Found
1771405721507 IOTA_REGISTER_NEW
1771405721512 OMIKRON_CONNECTING
1771405721987 OMIKRON_CONNECTION_SUCCESS
1771405731879 Web Server shutdown complete.

View file

@ -1,16 +0,0 @@
1771421284869 IOTA ID: 0
1771421284869 User IDS:
1771421284885 Community IDS:
1771421284886 TLS certificate 'certs/cert.pem' not found.
1771421284886 HTTP Server running on 0.0.0.0:1984
1771421284887 Communities active on ws://10.209.226.34:1984/community/...
1771421284887 Downloading ZIP file...
1771421285166 Failed to download file: Status 404 Not Found
1771421285167 Error downloading file: Failed to download file: Status 404 Not Found
1771421285167 IOTA_REGISTER_NEW
1771421285173 OMIKRON_CONNECTING
1771421285459 OMIKRON_CONNECTION_SUCCESS
1771421297984 Shutdown signal received.
1771421297985 Web Server shutdown complete.
1771421305461 Request timed out after 20 seconds.
1771421305461 Launched

View file

@ -1,42 +0,0 @@
1771421408357 IOTA ID: 0
1771421408357 User IDS:
1771421408369 Community IDS:
1771421408369 TLS certificate 'certs/cert.pem' not found.
1771421408369 HTTP Server running on 0.0.0.0:1984
1771421408370 Communities active on ws://10.209.226.34:1984/community/...
1771421408370 Downloading ZIP file...
1771421408574 Failed to download file: Status 404 Not Found
1771421408574 Error downloading file: Failed to download file: Status 404 Not Found
1771421408574 IOTA_REGISTER_NEW
1771421408581 OMIKRON_CONNECTING
1771421408791 OMIKRON_CONNECTION_SUCCESS
1771421428793 Request timed out after 20 seconds.
1771421428793 Launched
1771421428824 error_internal
1771421428911 Connection closed.
1771421429796 IOTA_REGISTER_NEW
1771421429800 OMIKRON_CONNECTING
1771421430102 OMIKRON_CONNECTION_SUCCESS
1771421450104 Request timed out after 20 seconds.
1771421450106 Launched
1771421450135 error_internal
1771421450205 Connection closed.
1771421451108 IOTA_REGISTER_NEW
1771421451113 OMIKRON_CONNECTING
1771421451310 OMIKRON_CONNECTION_SUCCESS
1771421471312 Request timed out after 20 seconds.
1771421471314 Launched
1771421471354 error_internal
1771421471428 Connection closed.
1771421472315 IOTA_REGISTER_NEW
1771421472319 OMIKRON_CONNECTING
1771421472543 OMIKRON_CONNECTION_SUCCESS
1771421492544 Request timed out after 20 seconds.
1771421492546 Launched
1771421492568 error_internal
1771421492597 Connection closed.
1771421493548 IOTA_REGISTER_NEW
1771421493554 OMIKRON_CONNECTING
1771421493769 OMIKRON_CONNECTION_SUCCESS
1771421493828 Shutdown signal received.
1771421493830 Web Server shutdown complete.

View file

@ -1,15 +0,0 @@
1771421600740 IOTA ID: 0
1771421600740 User IDS:
1771421600755 Community IDS:
1771421600756 TLS certificate 'certs/cert.pem' not found.
1771421600756 HTTP Server running on 0.0.0.0:1984
1771421600756 Communities active on ws://10.209.226.34:1984/community/...
1771421600756 Downloading ZIP file...
1771421600982 Failed to download file: Status 404 Not Found
1771421600982 Error downloading file: Failed to download file: Status 404 Not Found
1771421600983 IOTA_REGISTER_NEW
1771421600988 OMIKRON_CONNECTING
1771421601270 OMIKRON_CONNECTION_SUCCESS
1771421606464 Shutdown signal received.
1771421621272 Request timed out after 20 seconds.
1771421621272 Launched

View file

@ -1,184 +0,0 @@
1771423051538 IOTA ID: 0
1771423051538 User IDS:
1771423051551 Community IDS:
1771423051551 TLS certificate 'certs/cert.pem' not found.
1771423051551 HTTP Server running on 0.0.0.0:1984
1771423051552 Communities active on ws://10.209.226.34:1984/community/...
1771423051552 Downloading ZIP file...
1771423051790 Failed to download file: Status 404 Not Found
1771423051790 Error downloading file: Failed to download file: Status 404 Not Found
1771423051790 IOTA_REGISTER_NEW
1771423051793 OMIKRON_CONNECTING
1771423052032 OMIKRON_CONNECTION_SUCCESS
1771423072035 Request timed out after 20 seconds.
1771423072035 Launched
1771423072067 error_internal
1771423072105 Connection closed.
1771423073036 IOTA_REGISTER_NEW
1771423073040 OMIKRON_CONNECTING
1771423073256 OMIKRON_CONNECTION_SUCCESS
1771423093258 Request timed out after 20 seconds.
1771423093262 Launched
1771423093286 error_internal
1771423093322 Connection closed.
1771423094264 IOTA_REGISTER_NEW
1771423094267 OMIKRON_CONNECTING
1771423094484 OMIKRON_CONNECTION_SUCCESS
1771423114491 Request timed out after 20 seconds.
1771423114492 Launched
1771423114520 error_internal
1771423114558 Connection closed.
1771423115495 IOTA_REGISTER_NEW
1771423115501 OMIKRON_CONNECTING
1771423115724 OMIKRON_CONNECTION_SUCCESS
1771423135725 Request timed out after 20 seconds.
1771423135728 Launched
1771423135759 error_internal
1771423135794 Connection closed.
1771423136730 IOTA_REGISTER_NEW
1771423136738 OMIKRON_CONNECTING
1771423136959 OMIKRON_CONNECTION_SUCCESS
1771423156960 Request timed out after 20 seconds.
1771423156963 Launched
1771423156999 error_internal
1771423157078 Connection closed.
1771423157965 IOTA_REGISTER_NEW
1771423157970 OMIKRON_CONNECTING
1771423158169 OMIKRON_CONNECTION_SUCCESS
1771423178171 Request timed out after 20 seconds.
1771423178173 Launched
1771423178200 error_internal
1771423178270 Connection closed.
1771423179174 IOTA_REGISTER_NEW
1771423179178 OMIKRON_CONNECTING
1771423179404 OMIKRON_CONNECTION_SUCCESS
1771423199406 Request timed out after 20 seconds.
1771423199409 Launched
1771423199437 error_internal
1771423199485 Connection closed.
1771423200413 IOTA_REGISTER_NEW
1771423200418 OMIKRON_CONNECTING
1771423200855 OMIKRON_CONNECTION_SUCCESS
1771423220858 Request timed out after 20 seconds.
1771423220861 Launched
1771423220884 error_internal
1771423220913 Connection closed.
1771423221864 IOTA_REGISTER_NEW
1771423221870 OMIKRON_CONNECTING
1771423222087 OMIKRON_CONNECTION_SUCCESS
1771423242092 Request timed out after 20 seconds.
1771423242095 Launched
1771423242115 error_internal
1771423242145 Connection closed.
1771423243096 IOTA_REGISTER_NEW
1771423243101 OMIKRON_CONNECTING
1771423243328 OMIKRON_CONNECTION_SUCCESS
1771423263334 Request timed out after 20 seconds.
1771423263337 Launched
1771423263363 error_internal
1771423263412 Connection closed.
1771423264343 IOTA_REGISTER_NEW
1771423264348 OMIKRON_CONNECTING
1771423264553 OMIKRON_CONNECTION_SUCCESS
1771423284555 Request timed out after 20 seconds.
1771423284558 Launched
1771423284582 error_internal
1771423284609 Connection closed.
1771423285560 IOTA_REGISTER_NEW
1771423285563 OMIKRON_CONNECTING
1771423285770 OMIKRON_CONNECTION_SUCCESS
1771423305772 Request timed out after 20 seconds.
1771423305775 Launched
1771423305801 error_internal
1771423305837 Connection closed.
1771423306776 IOTA_REGISTER_NEW
1771423306786 OMIKRON_CONNECTING
1771423306995 OMIKRON_CONNECTION_SUCCESS
1771423326998 Request timed out after 20 seconds.
1771423327000 Launched
1771423327022 error_internal
1771423327068 Connection closed.
1771423328002 IOTA_REGISTER_NEW
1771423328006 OMIKRON_CONNECTING
1771423328253 OMIKRON_CONNECTION_SUCCESS
1771423348256 Request timed out after 20 seconds.
1771423348259 Launched
1771423348298 error_internal
1771423348335 Connection closed.
1771423349260 IOTA_REGISTER_NEW
1771423349265 OMIKRON_CONNECTING
1771423349504 OMIKRON_CONNECTION_SUCCESS
1771423369505 Request timed out after 20 seconds.
1771423369507 Launched
1771423369535 error_internal
1771423369584 Connection closed.
1771423370508 IOTA_REGISTER_NEW
1771423370512 OMIKRON_CONNECTING
1771423370754 OMIKRON_CONNECTION_SUCCESS
1771423390756 Request timed out after 20 seconds.
1771423390759 Launched
1771423390800 error_internal
1771423390827 Connection closed.
1771423391760 IOTA_REGISTER_NEW
1771423391764 OMIKRON_CONNECTING
1771423392002 OMIKRON_CONNECTION_SUCCESS
1771423412005 Request timed out after 20 seconds.
1771423412008 Launched
1771423412038 error_internal
1771423412065 Connection closed.
1771423413009 IOTA_REGISTER_NEW
1771423413015 OMIKRON_CONNECTING
1771423413208 OMIKRON_CONNECTION_SUCCESS
1771423433210 Request timed out after 20 seconds.
1771423433212 Launched
1771423433234 error_internal
1771423433271 Connection closed.
1771423434215 IOTA_REGISTER_NEW
1771423434221 OMIKRON_CONNECTING
1771423434422 OMIKRON_CONNECTION_SUCCESS
1771423454425 Request timed out after 20 seconds.
1771423454426 Launched
1771423454448 error_internal
1771423454478 Connection closed.
1771423455428 IOTA_REGISTER_NEW
1771423455433 OMIKRON_CONNECTING
1771423455707 OMIKRON_CONNECTION_SUCCESS
1771423475712 Request timed out after 20 seconds.
1771423475716 Launched
1771423475748 error_internal
1771423475779 Connection closed.
1771423476717 IOTA_REGISTER_NEW
1771423476721 OMIKRON_CONNECTING
1771423476935 OMIKRON_CONNECTION_SUCCESS
1771423496936 Request timed out after 20 seconds.
1771423496938 Launched
1771423496970 error_internal
1771423497007 Connection closed.
1771423497939 IOTA_REGISTER_NEW
1771423497945 OMIKRON_CONNECTING
1771423498170 OMIKRON_CONNECTION_SUCCESS
1771423518171 Request timed out after 20 seconds.
1771423518174 Launched
1771423518201 error_internal
1771423518241 Connection closed.
1771423519176 IOTA_REGISTER_NEW
1771423519181 OMIKRON_CONNECTING
1771423519392 OMIKRON_CONNECTION_SUCCESS
1771423539396 Request timed out after 20 seconds.
1771423539398 Launched
1771423539424 error_internal
1771423539455 Connection closed.
1771423540400 IOTA_REGISTER_NEW
1771423540404 OMIKRON_CONNECTING
1771423540643 OMIKRON_CONNECTION_SUCCESS
1771423560644 Request timed out after 20 seconds.
1771423560647 Launched
1771423560687 error_internal
1771423560747 Connection closed.
1771423561649 IOTA_REGISTER_NEW
1771423561653 OMIKRON_CONNECTING
1771423561858 OMIKRON_CONNECTION_SUCCESS
1771423574596 Shutdown signal received.
1771423574597 Web Server shutdown complete.
1771423581860 Request timed out after 20 seconds.
1771423581864 Launched

View file

@ -1,11 +0,0 @@
1771423595203 IOTA ID: 0
1771423595203 User IDS:
1771423595215 Community IDS:
1771423595216 TLS certificate 'certs/cert.pem' not found.
1771423595216 HTTP Server running on 0.0.0.0:1984
1771423595217 Communities active on ws://10.209.226.34:1984/community/...
1771423595217 Downloading ZIP file...
1771423608345 Shutdown signal received.
1771423608346 Web Server shutdown complete.
1771423685485 Failed to download file: Status 504 Gateway Timeout
1771423685485 Error downloading file: Failed to download file: Status 504 Gateway Timeout

View file

@ -1,63 +0,0 @@
1771436282065 IOTA ID: 1771072674214
1771436282065 User IDS:
1771436282073 Community IDS:
1771436282073 TLS certificate 'certs/cert.pem' not found.
1771436282073 HTTP Server running on 0.0.0.0:1984
1771436282074 Communities active on ws://192.168.178.51:1984/community/...
1771436282074 OMIKRON_CONNECTING
1771436282318 OMIKRON_CONNECTION_SUCCESS
1771436282318 Launched
1771436302354 error_internal
1771436302374 Connection closed.
1771436303341 OMIKRON_CONNECTING
1771436303520 OMIKRON_CONNECTION_SUCCESS
1771436303521 Launched
1771436323545 error_internal
1771436323567 Connection closed.
1771436324551 OMIKRON_CONNECTING
1771436324737 OMIKRON_CONNECTION_SUCCESS
1771436324737 Launched
1771436344754 error_internal
1771436344797 Connection closed.
1771436345760 OMIKRON_CONNECTING
1771436345918 OMIKRON_CONNECTION_SUCCESS
1771436345918 Launched
1771436365940 error_internal
1771436365965 Connection closed.
1771436366944 OMIKRON_CONNECTING
1771436367109 OMIKRON_CONNECTION_SUCCESS
1771436367110 Launched
1771436387137 error_internal
1771436387158 Connection closed.
1771436388134 OMIKRON_CONNECTING
1771436388297 OMIKRON_CONNECTION_SUCCESS
1771436388297 Launched
1771436408315 error_internal
1771436408358 Connection closed.
1771436409322 OMIKRON_CONNECTING
1771436409495 OMIKRON_CONNECTION_SUCCESS
1771436409495 Launched
1771436429520 error_internal
1771436429580 Connection closed.
1771436430519 OMIKRON_CONNECTING
1771436430704 OMIKRON_CONNECTION_SUCCESS
1771436430704 Launched
1771436450728 error_internal
1771436450789 Connection closed.
1771436451729 OMIKRON_CONNECTING
1771436451884 OMIKRON_CONNECTION_SUCCESS
1771436451884 Launched
1771436471909 error_internal
1771436471981 Connection closed.
1771436472909 OMIKRON_CONNECTING
1771436473084 OMIKRON_CONNECTION_SUCCESS
1771436473084 Launched
1771436493113 error_internal
1771436493159 Connection closed.
1771436494110 OMIKRON_CONNECTING
1771436494331 OMIKRON_CONNECTION_SUCCESS
1771436494331 Launched
1771436514369 error_internal
1771436514430 Connection closed.
1771436515164 Shutdown signal received.
1771436515164 Web Server shutdown complete.

View file

@ -1,166 +0,0 @@
1771436538793 IOTA ID: 1771072674214
1771436538793 User IDS:
1771436538799 Community IDS:
1771436538800 TLS certificate 'certs/cert.pem' not found.
1771436538800 HTTP Server running on 0.0.0.0:1984
1771436538800 Communities active on ws://192.168.178.51:1984/community/...
1771436538800 OMIKRON_CONNECTING
1771436538965 OMIKRON_CONNECTION_SUCCESS
1771436538965 Launched
1771436558993 error_internal
1771436559015 Connection closed.
1771436559988 OMIKRON_CONNECTING
1771436560155 OMIKRON_CONNECTION_SUCCESS
1771436560156 Launched
1771436580192 error_internal
1771436580244 Connection closed.
1771436581177 OMIKRON_CONNECTING
1771436581398 OMIKRON_CONNECTION_SUCCESS
1771436581399 Launched
1771436601424 error_internal
1771436601483 Connection closed.
1771436602422 OMIKRON_CONNECTING
1771436602569 OMIKRON_CONNECTION_SUCCESS
1771436602569 Launched
1771436622588 error_internal
1771436622615 Connection closed.
1771436623593 OMIKRON_CONNECTING
1771436623791 OMIKRON_CONNECTION_SUCCESS
1771436623791 Launched
1771436643819 error_internal
1771436643844 Connection closed.
1771436644814 OMIKRON_CONNECTING
1771436645183 OMIKRON_CONNECTION_SUCCESS
1771436645183 Launched
1771436665215 error_internal
1771436665238 Connection closed.
1771436666208 OMIKRON_CONNECTING
1771436666364 OMIKRON_CONNECTION_SUCCESS
1771436666364 Launched
1771436686383 error_internal
1771436686411 Connection closed.
1771436687388 OMIKRON_CONNECTING
1771436687544 OMIKRON_CONNECTION_SUCCESS
1771436687544 Launched
1771436707570 error_internal
1771436707626 Connection closed.
1771436708570 OMIKRON_CONNECTING
1771436708771 OMIKRON_CONNECTION_SUCCESS
1771436708771 Launched
1771436728792 error_internal
1771436728812 Connection closed.
1771436729798 OMIKRON_CONNECTING
1771436729969 OMIKRON_CONNECTION_SUCCESS
1771436729970 Launched
1771436749991 error_internal
1771436750026 Connection closed.
1771436750993 OMIKRON_CONNECTING
1771436751270 OMIKRON_CONNECTION_SUCCESS
1771436751270 Launched
1771436771291 error_internal
1771436771313 Connection closed.
1771436772294 OMIKRON_CONNECTING
1771436772455 OMIKRON_CONNECTION_SUCCESS
1771436772455 Launched
1771436792476 error_internal
1771436792506 Connection closed.
1771436793481 OMIKRON_CONNECTING
1771436793642 OMIKRON_CONNECTION_SUCCESS
1771436793643 Launched
1771436813670 error_internal
1771436813707 Connection closed.
1771436814668 OMIKRON_CONNECTING
1771436814859 OMIKRON_CONNECTION_SUCCESS
1771436814859 Launched
1771436834885 error_internal
1771436834911 Connection closed.
1771436835882 OMIKRON_CONNECTING
1771436836100 OMIKRON_CONNECTION_SUCCESS
1771436836100 Launched
1771436856123 error_internal
1771436856157 Connection closed.
1771436857125 OMIKRON_CONNECTING
1771436857279 OMIKRON_CONNECTION_SUCCESS
1771436857279 Launched
1771436877297 error_internal
1771436877330 Connection closed.
1771436878301 OMIKRON_CONNECTING
1771436878459 OMIKRON_CONNECTION_SUCCESS
1771436878459 Launched
1771436898482 error_internal
1771436898510 Connection closed.
1771436899487 OMIKRON_CONNECTING
1771436899669 OMIKRON_CONNECTION_SUCCESS
1771436899670 Launched
1771436919688 error_internal
1771436919716 Connection closed.
1771436920695 OMIKRON_CONNECTING
1771436920924 OMIKRON_CONNECTION_SUCCESS
1771436920924 Launched
1771436940946 error_internal
1771436940976 Connection closed.
1771436941950 OMIKRON_CONNECTING
1771436942115 OMIKRON_CONNECTION_SUCCESS
1771436942115 Launched
1771436962136 error_internal
1771436962218 Connection closed.
1771436963138 OMIKRON_CONNECTING
1771436963295 OMIKRON_CONNECTION_SUCCESS
1771436963295 Launched
1771436983318 error_internal
1771436983351 Connection closed.
1771436984321 OMIKRON_CONNECTING
1771436984488 OMIKRON_CONNECTION_SUCCESS
1771436984488 Launched
1771437004506 error_internal
1771437004546 Connection closed.
1771437005514 OMIKRON_CONNECTING
1771437005674 OMIKRON_CONNECTION_SUCCESS
1771437005674 Launched
1771437025693 error_internal
1771437025714 Connection closed.
1771437026696 OMIKRON_CONNECTING
1771437026985 OMIKRON_CONNECTION_SUCCESS
1771437026985 Launched
1771437047052 error_internal
1771437047072 Connection closed.
1771437048010 OMIKRON_CONNECTING
1771437048193 OMIKRON_CONNECTION_SUCCESS
1771437048193 Launched
1771437068214 error_internal
1771437068248 Connection closed.
1771437069215 OMIKRON_CONNECTING
1771437069393 OMIKRON_CONNECTION_SUCCESS
1771437069393 Launched
1771437089412 error_internal
1771437089436 Connection closed.
1771437090417 OMIKRON_CONNECTING
1771437090587 OMIKRON_CONNECTION_SUCCESS
1771437090588 Launched
1771437110609 error_internal
1771437110646 Connection closed.
1771437111610 OMIKRON_CONNECTING
1771437111764 OMIKRON_CONNECTION_SUCCESS
1771437111765 Launched
1771437131785 error_internal
1771437131847 Connection closed.
1771437132791 OMIKRON_CONNECTING
1771437132976 OMIKRON_CONNECTION_SUCCESS
1771437132977 Launched
1771437152997 error_internal
1771437153061 Connection closed.
1771437154000 OMIKRON_CONNECTING
1771437154171 OMIKRON_CONNECTION_SUCCESS
1771437154172 Launched
1771437174193 error_internal
1771437174213 Connection closed.
1771437175196 OMIKRON_CONNECTING
1771437175344 OMIKRON_CONNECTION_SUCCESS
1771437175345 Launched
1771437195364 error_internal
1771437195401 Connection closed.
1771437196369 OMIKRON_CONNECTING
1771437196525 OMIKRON_CONNECTION_SUCCESS
1771437196525 Launched
1771437202079 Shutdown signal received.
1771437202079 Web Server shutdown complete.

View file

@ -1,11 +0,0 @@
1771437605589 IOTA ID: 1771072674214
1771437605589 User IDS:
1771437605596 Community IDS:
1771437605596 TLS certificate 'certs/cert.pem' not found.
1771437605596 HTTP Server running on 0.0.0.0:1984
1771437605597 Communities active on ws://192.168.178.51:1984/community/...
1771437605597 OMIKRON_CONNECTING
1771437605895 OMIKRON_CONNECTION_SUCCESS
1771437605895 Launched
1771437616609 Shutdown signal received.
1771437616609 Web Server shutdown complete.

View file

@ -1,11 +0,0 @@
1771438219620 IOTA ID: 1771072674214
1771438219620 User IDS:
1771438219626 Community IDS:
1771438219626 TLS certificate 'certs/cert.pem' not found.
1771438219626 HTTP Server running on 0.0.0.0:1984
1771438219627 Communities active on ws://192.168.178.51:1984/community/...
1771438219627 OMIKRON_CONNECTING
1771438219823 OMIKRON_CONNECTION_SUCCESS
1771438219823 Launched
1771438222468 Shutdown signal received.
1771438222468 Web Server shutdown complete.

View file

@ -1,11 +0,0 @@
1771438233418 IOTA ID: 1771072674214
1771438233418 User IDS:
1771438233424 Community IDS:
1771438233425 TLS certificate 'certs/cert.pem' not found.
1771438233425 HTTP Server running on 0.0.0.0:1984
1771438233425 Communities active on ws://192.168.178.51:1984/community/...
1771438233425 OMIKRON_CONNECTING
1771438233604 OMIKRON_CONNECTION_SUCCESS
1771438233604 Launched
1771438236430 Shutdown signal received.
1771438236431 Web Server shutdown complete.

View file

@ -1,16 +0,0 @@
1771438242873 IOTA ID: 1771072674214
1771438242873 User IDS:
1771438242879 Community IDS:
1771438242879 TLS certificate 'certs/cert.pem' not found.
1771438242879 HTTP Server running on 0.0.0.0:1984
1771438242880 Communities active on ws://192.168.178.51:1984/community/...
1771438242880 OMIKRON_CONNECTING
1771438243059 OMIKRON_CONNECTION_SUCCESS
1771438243059 Launched
1771438263092 error_internal
1771438263152 Connection closed.
1771438264100 OMIKRON_CONNECTING
1771438264278 OMIKRON_CONNECTION_SUCCESS
1771438264278 Launched
1771438284301 error_internal
1771438284320 Connection closed.

View file

@ -1,21 +1,30 @@
use std::{any::Any, sync::Arc}; use crate::gui::{
elements::{
elements::{Element, InteractableElement},
log_card::LogCard,
},
interaction_result::InteractionResult,
screens::screens::Screen,
ui::UI,
};
use crossterm::event::KeyEvent; use crossterm::event::KeyEvent;
use ratatui::{ use ratatui::{
Frame, Frame,
layout::Rect, layout::{Constraint, Layout, Margin, Rect},
widgets::{Block, Borders}, widgets::{Block, Borders},
}; };
use std::{any::Any, sync::Arc};
use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen, ui::UI};
pub struct MainScreen { pub struct MainScreen {
ui: Arc<UI>, ui: Arc<UI>,
log_card: LogCard,
} }
impl MainScreen { impl MainScreen {
pub async fn new(ui: Arc<UI>) -> Self { pub async fn new(ui: Arc<UI>) -> Self {
MainScreen { ui } let mut log_card = LogCard::new();
log_card.focus(true);
MainScreen { ui, log_card }
} }
} }
impl Screen for MainScreen { impl Screen for MainScreen {
@ -32,10 +41,25 @@ impl Screen for MainScreen {
} }
fn render(&self, f: &mut Frame, rect: Rect) { fn render(&self, f: &mut Frame, rect: Rect) {
f.render_widget(Block::default().title("Main").borders(Borders::ALL), rect); let main_block = Block::default().title("Main").borders(Borders::ALL);
f.render_widget(main_block, rect);
let inner = rect.inner(Margin {
vertical: 1,
horizontal: 1,
});
let chunks = Layout::vertical([Constraint::Min(0)]).split(inner);
self.log_card.render(f, chunks[0]);
} }
fn handle_input(&mut self, event: KeyEvent) -> InteractionResult { fn handle_input(&mut self, event: KeyEvent) -> InteractionResult {
if self.log_card.is_focused() {
return self.log_card.interact(event);
}
InteractionResult::Unhandled InteractionResult::Unhandled
} }
} }

View file

@ -25,7 +25,7 @@ use crate::gui::ui::start_tui;
use crate::langu::language_creator; use crate::langu::language_creator;
use crate::omikron::omikron_connection::{OMIKRON_CONNECTION, OmikronConnection}; use crate::omikron::omikron_connection::{OMIKRON_CONNECTION, OmikronConnection};
use crate::server::server::start; use crate::server::server::start;
use crate::terms::consent_state::ConsentManager; use crate::terms::consent_state;
use crate::users::user_manager; use crate::users::user_manager;
use crate::util::config_util::CONFIG; use crate::util::config_util::CONFIG;
use crate::util::file_util::download_and_extract_zip; use crate::util::file_util::download_and_extract_zip;
@ -56,7 +56,7 @@ async fn main() {
} }
}); });
let (eula, tos_pp) = ConsentManager::check(ui.clone()).await; let (eula, tos_pp) = consent_state::check(ui.clone()).await;
if !eula { if !eula {
*SHUTDOWN.write().await = true; *SHUTDOWN.write().await = true;

View file

@ -14,142 +14,163 @@ use crate::{
use std::sync::Arc; use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
pub struct ConsentManager; pub async fn check(ui: Arc<UI>) -> (bool, bool) {
impl ConsentManager { let mut state = ConsentState::load_state();
pub async fn check(ui: Arc<UI>) -> (bool, bool) {
let file = load_file("", "agreements");
let mut state = ConsentState::from_str(&file).sanitize();
if !state.accepted_eula { if ensure_initial_consent(ui.clone(), &mut state)
let (tx, rx) = oneshot::channel(); .await
.is_err()
{
return (false, false);
}
if ensure_updates(ui, &mut state).await.is_err() {
return (false, false);
};
ui.set_screen(Box::new(TermsCheckerScreen::new(ui.clone(), Some(tx)))) state = state.sanitize();
.await; state.save_state();
let result = rx.await.unwrap_or(UserChoice::Deny); (state.accepted_eula, state.accepted_tos && state.accepted_pp)
}
match result { async fn ensure_initial_consent(ui: Arc<UI>, state: &mut ConsentState) -> Result<(), ()> {
UserChoice::AcceptEULA | UserChoice::AcceptAll => { if state.accepted_eula {
if let Some((current_eula, current_tos, current_privacy)) = return Ok(());
get_current_docs().await
{
state.accepted_eula = true;
state.eula = Some(current_eula);
if matches!(result, UserChoice::AcceptAll) {
state.accepted_tos = true;
state.accepted_pp = true;
state.tos = Some(current_tos);
state.privacy = Some(current_privacy);
}
}
}
UserChoice::Deny => return (false, false),
}
save_file("", "agreements", &state.to_string());
}
if let Some((eula_update, tos_update, privacy_update)) = Self::get_updates().await {
let is_forced = matches!(eula_update, UpdateDecision::Forced(_))
|| matches!(tos_update, UpdateDecision::Forced(_))
|| matches!(privacy_update, UpdateDecision::Forced(_));
let (tx, rx) = oneshot::channel();
ui.set_screen(Box::new(TermsUpdaterScreen::new(
ui.clone(),
eula_update.clone(),
tos_update.clone(),
privacy_update.clone(),
Some(tx),
)))
.await;
let result = rx.await.unwrap_or(UserChoice::Deny);
if is_forced {
match result {
UserChoice::AcceptAll => {
state.accepted_eula = true;
state.accepted_tos = true;
state.accepted_pp = true;
}
UserChoice::AcceptEULA => {
state.accepted_eula = true;
}
UserChoice::Deny => return (false, false),
}
} else {
match result {
UserChoice::AcceptAll => {
if let UpdateDecision::Future { newest } = eula_update {
state.future_eula = Some(newest);
}
if let UpdateDecision::Future { newest } = tos_update {
state.future_tos = Some(newest);
}
if let UpdateDecision::Future { newest } = privacy_update {
state.future_privacy = Some(newest);
}
}
UserChoice::AcceptEULA => {
if let UpdateDecision::Future { newest } = eula_update {
state.future_eula = Some(newest);
}
}
UserChoice::Deny => {}
}
}
state = state.sanitize();
save_file("", "agreements", &state.to_string());
}
state = ConsentState::from_str(&load_file("", "agreements")).sanitize();
save_file("", "agreements", &state.to_string());
(state.accepted_eula, state.accepted_tos && state.accepted_pp)
} }
async fn get_updates() -> Option<( let (tx, rx) = oneshot::channel();
// Ok(None) indicates no update
// Ok(Some) Indicates a future update ui.set_screen(Box::new(TermsCheckerScreen::new(ui.clone(), Some(tx))))
// Err indicates a update that has to be accepted before the programm can continue .await;
UpdateDecision,
UpdateDecision, let result = rx.await.unwrap_or(UserChoice::Deny);
UpdateDecision,
)> { match result {
UserChoice::AcceptEULA | UserChoice::AcceptAll => {
if let Some((eula, tos, privacy)) = get_current_docs().await {
state.accepted_eula = true;
state.eula = Some(eula);
if matches!(result, UserChoice::AcceptAll) {
state.accepted_tos = true;
state.accepted_pp = true;
state.tos = Some(tos);
state.privacy = Some(privacy);
}
}
&state.save_state();
Ok(())
}
UserChoice::Deny => Err(()),
}
}
async fn ensure_updates(ui: Arc<UI>, state: &mut ConsentState) -> Result<(), ()> {
let Some((eula_update, tos_update, privacy_update)) = get_updates().await else {
return Ok(());
};
let is_forced = matches!(eula_update, UpdateDecision::Forced(_))
|| matches!(tos_update, UpdateDecision::Forced(_))
|| matches!(privacy_update, UpdateDecision::Forced(_));
let (tx, rx) = oneshot::channel();
ui.set_screen(Box::new(TermsUpdaterScreen::new(
ui.clone(),
eula_update.clone(),
tos_update.clone(),
privacy_update.clone(),
Some(tx),
)))
.await;
let result = rx.await.unwrap_or(UserChoice::Deny);
if is_forced {
match result {
UserChoice::AcceptAll => {
state.accepted_eula = true;
state.accepted_tos = true;
state.accepted_pp = true;
}
UserChoice::AcceptEULA => {
state.accepted_eula = true;
}
UserChoice::Deny => return Err(()),
}
} else {
apply_future_updates(state, result, eula_update, tos_update, privacy_update);
}
state.save_state();
Ok(())
}
fn apply_future_updates(
state: &mut ConsentState,
result: UserChoice,
eula_update: UpdateDecision,
tos_update: UpdateDecision,
privacy_update: UpdateDecision,
) {
match result {
UserChoice::AcceptAll => {
if let UpdateDecision::Future { newest } = eula_update {
state.future_eula = Some(newest);
}
if let UpdateDecision::Future { newest } = tos_update {
state.future_tos = Some(newest);
}
if let UpdateDecision::Future { newest } = privacy_update {
state.future_privacy = Some(newest);
}
}
UserChoice::AcceptEULA => {
if let UpdateDecision::Future { newest } = eula_update {
state.future_eula = Some(newest);
}
}
UserChoice::Deny => {}
}
}
async fn get_updates() -> Option<(
// Ok(None) indicates no update
// Ok(Some) Indicates a future update
// Err indicates a update that has to be accepted before the programm can continue
UpdateDecision,
UpdateDecision,
UpdateDecision,
)> {
if let (
Some((current_eula, current_tos, current_privacy)),
Some((newest_eula, newest_tos, newest_privacy)),
) = (get_current_docs().await, get_newest_docs().await)
{
let file = load_file("", "agreements"); let file = load_file("", "agreements");
let accepted_state = ConsentState::from_str(&file).sanitize(); let accepted_state = ConsentState::from_str(&file).sanitize();
save_file("", "agreements", &accepted_state.to_string()); save_file("", "agreements", &accepted_state.to_string());
if let ( let eula_update: UpdateDecision = if current_eula.equals_some(&accepted_state.eula) {
Some((current_eula, current_tos, current_privacy)), if current_eula.equals(&newest_eula) {
Some((newest_eula, newest_tos, newest_privacy)),
) = (get_current_docs().await, get_newest_docs().await)
{
let eula_update: UpdateDecision = if current_eula.equals_some(&accepted_state.eula) {
if current_eula.equals(&newest_eula) {
UpdateDecision::NoChange
} else {
if newest_eula.equals_some(&accepted_state.future_eula) {
UpdateDecision::NoChange
} else {
UpdateDecision::Future {
newest: newest_eula,
}
}
}
} else if newest_eula.equals_some(&accepted_state.eula) {
UpdateDecision::NoChange UpdateDecision::NoChange
} else { } else {
UpdateDecision::Forced(current_eula) if newest_eula.equals_some(&accepted_state.future_eula) {
}; UpdateDecision::NoChange
} else {
UpdateDecision::Future {
newest: newest_eula,
}
}
}
} else if newest_eula.equals_some(&accepted_state.eula) {
UpdateDecision::NoChange
} else {
UpdateDecision::Forced(current_eula)
};
let tos_update: UpdateDecision = if !accepted_state.accepted_tos let tos_update: UpdateDecision =
|| newest_tos.equals_some(&accepted_state.tos) if !accepted_state.accepted_tos || newest_tos.equals_some(&accepted_state.tos) {
{
UpdateDecision::NoChange UpdateDecision::NoChange
} else if accepted_state.accepted_tos && current_tos.equals_some(&accepted_state.tos) { } else if accepted_state.accepted_tos && current_tos.equals_some(&accepted_state.tos) {
if current_tos.equals(&newest_tos) { if current_tos.equals(&newest_tos) {
@ -165,38 +186,34 @@ impl ConsentManager {
UpdateDecision::Forced(current_tos) UpdateDecision::Forced(current_tos)
}; };
let privacy_update: UpdateDecision = if !accepted_state.accepted_pp let privacy_update: UpdateDecision = if !accepted_state.accepted_pp
|| newest_privacy.equals_some(&accepted_state.privacy) || newest_privacy.equals_some(&accepted_state.privacy)
{ {
UpdateDecision::NoChange
} else if accepted_state.accepted_pp && current_privacy.equals_some(&accepted_state.privacy)
{
if current_privacy.equals(&newest_privacy) {
UpdateDecision::NoChange UpdateDecision::NoChange
} else if accepted_state.accepted_pp } else {
&& current_privacy.equals_some(&accepted_state.privacy) if newest_privacy.equals_some(&accepted_state.future_privacy) {
{
if current_privacy.equals(&newest_privacy) {
UpdateDecision::NoChange UpdateDecision::NoChange
} else { } else {
if newest_privacy.equals_some(&accepted_state.future_privacy) { UpdateDecision::Future {
UpdateDecision::NoChange newest: newest_privacy,
} else {
UpdateDecision::Future {
newest: newest_privacy,
}
} }
} }
} else {
UpdateDecision::Forced(current_privacy)
};
match (&eula_update, &tos_update, &privacy_update) {
(
&UpdateDecision::NoChange,
&UpdateDecision::NoChange,
&UpdateDecision::NoChange,
) => None,
_ => Some((eula_update, tos_update, privacy_update)),
} }
} else { } else {
None UpdateDecision::Forced(current_privacy)
};
match (&eula_update, &tos_update, &privacy_update) {
(&UpdateDecision::NoChange, &UpdateDecision::NoChange, &UpdateDecision::NoChange) => {
None
}
_ => Some((eula_update, tos_update, privacy_update)),
} }
} else {
None
} }
} }
@ -262,7 +279,16 @@ impl ConsentState {
self self
} }
pub fn to_string(&self) -> String { pub fn load_state() -> ConsentState {
let file = load_file("", "agreements");
ConsentState::from_str(&file).sanitize()
}
pub fn save_state(&self) {
save_file("", "agreements", &self.to_string());
}
fn to_string(&self) -> String {
let current_secs = SystemTime::now() let current_secs = SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.unwrap() .unwrap()

View file

@ -9,7 +9,11 @@ use std::{
use ratatui::style::Color; use ratatui::style::Color;
use crate::{APP_STATE, gui::elements::log_card::UiLogEntry, langu::language_manager}; use crate::{
APP_STATE,
gui::{elements::log_card::UiLogEntry, ui::UNIQUE},
langu::language_manager,
};
static LOGGER: OnceLock<mpsc::Sender<LogMessage>> = OnceLock::new(); static LOGGER: OnceLock<mpsc::Sender<LogMessage>> = OnceLock::new();
@ -118,6 +122,9 @@ pub fn log_internal_translated(
args: Vec<String>, args: Vec<String>,
) { ) {
if let Some(tx) = LOGGER.get() { if let Some(tx) = LOGGER.get() {
tokio::spawn(async move {
*UNIQUE.write().await = true;
});
let _ = tx.send(LogMessage { let _ = tx.send(LogMessage {
timestamp_ms: SystemTime::now() timestamp_ms: SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@ -135,6 +142,9 @@ pub fn log_internal_translated(
pub fn log_internal(kind: PrintType, prefix: &'static str, is_error: bool, message: String) { pub fn log_internal(kind: PrintType, prefix: &'static str, is_error: bool, message: String) {
if let Some(tx) = LOGGER.get() { if let Some(tx) = LOGGER.get() {
tokio::spawn(async move {
*UNIQUE.write().await = true;
});
let _ = tx.send(LogMessage { let _ = tx.send(LogMessage {
timestamp_ms: SystemTime::now() timestamp_ms: SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)