From 20123348a7f8ed6fe1270cb6cff0f587632fb9ff Mon Sep 17 00:00:00 2001 From: Daniel Nagel Date: Tue, 31 Mar 2026 12:04:08 +0000 Subject: [PATCH] umsortierung. --- gui/.gitignore => .gitignore | 0 __pycache__/database.cpython-312.pyc | Bin 4039 -> 4022 bytes ats_doku.db | Bin 20480 -> 0 bytes data/data_api.py | 2 + database.py => data/database.py | 1 - gui/__pycache__/__init__.cpython-312.pyc | Bin 145 -> 128 bytes gui/__pycache__/main_gui.cpython-312.pyc | Bin 8513 -> 8543 bytes gui/gui_admin.py | 9 + gui/gui_style.py | 22 +++ gui/main_gui.py | 205 ++++++++++------------- main.py | 4 +- 11 files changed, 128 insertions(+), 115 deletions(-) rename gui/.gitignore => .gitignore (100%) delete mode 100644 ats_doku.db create mode 100644 data/data_api.py rename database.py => data/database.py (98%) create mode 100644 gui/gui_admin.py create mode 100644 gui/gui_style.py diff --git a/gui/.gitignore b/.gitignore similarity index 100% rename from gui/.gitignore rename to .gitignore diff --git a/__pycache__/database.cpython-312.pyc b/__pycache__/database.cpython-312.pyc index eea985e8799dd43710ae9f5464465da9f566e712..6628038f4cf71f4dc4703d342826d397d5d0ff8a 100644 GIT binary patch delta 88 zcmX>uzfGR^G%qg~0}yQ8bUHI?BX1oGqx9stEVYbMo26OPnAkLdQpG8gdpQ+1uVBB= r$Y{2?gVTeF(P8sNZfizH-_5+dCm0!nCST(_&#K5M{>fwVDt=i2Wr-Ql delta 105 zcmdlce_WpTG%qg~0}%LEOv&ur$XmxEq@$mlpO==Iu3w&ClwDkqn4CJfhozQLW-}LS z8WW?|=0bK>CN^`Rmg3mS2U)Z>FXNPCVszYmfZLjp(Qoq~o)e6W!IO{joo7{I6#wKk Ic_zOs0B|KAp#T5? diff --git a/ats_doku.db b/ats_doku.db deleted file mode 100644 index 9bb2e983ec44285648f0c879ed6a385f43c60c0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 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 a*=se9MALE|p~ diff --git a/gui/gui_admin.py b/gui/gui_admin.py new file mode 100644 index 0000000..2b69e0b --- /dev/null +++ b/gui/gui_admin.py @@ -0,0 +1,9 @@ +from nicegui import ui +from data import database +from gui import gui_style + +def setup_route(): + @ui.page("/") + + def admin_page(): + ui.label("kasdlkfs") \ No newline at end of file diff --git a/gui/gui_style.py b/gui/gui_style.py new file mode 100644 index 0000000..a6399fa --- /dev/null +++ b/gui/gui_style.py @@ -0,0 +1,22 @@ +from nicegui import ui + +# Funktion die jede GUI Seite am Anfang aufrufen kann. Dann haben alle die gleichen Farbeinstellungen. Und, wenn man was ändert, +# muss man es nur hier ändern! + +def apply_design(): + ui.add_css('body { background-color: #171721; }') + # 1. Dark Mode aktivieren + ui.dark_mode(True) + ui.colors( + primary='#e30013', # Hauptfarbe (z.B. für Standard-Buttons) Wenn keine Farbe angegeben wird, ist es diese Farbe + secondary='#FF3333', # Zweitfarbe + accent='#2078D4', # Akzentfarbe + positive='#188C42', # Farbe für Erfolg (Grün) + negative='#E31919', # Farbe für Fehler/Abbruch (Rot) + info='#939393', # Info-Farbe + warning='#f59e0b', # Warn-Farbe (Orange) +# Farben für Texte + normaltext="#F7F7F7", + accenttext="#2078D4", + infotext="#A8A8A8" + ) diff --git a/gui/main_gui.py b/gui/main_gui.py index b3d8512..ec4af70 100644 --- a/gui/main_gui.py +++ b/gui/main_gui.py @@ -1,127 +1,108 @@ from nicegui import ui from datetime import datetime -import database +from data import database +from gui import gui_style, gui_admin -def build_ui(): - ui.colors(primary='#e30013') - # 1. HAUPT-CONTAINER: - # Spalte die exakt so hoch ist wie der Bildschirm (h-screen). - # 'items-stretch' sorgt dafür, dass die Kinder (Header, Mitte, Footer) die volle Breite nutzen. - with ui.column().classes('w-full h-screen no-wrap gap-0 items-stretch'): - # --------------------------------------------------------- - # BEREICH OBEN (Header) - Feste Höhe (h-25) - # --------------------------------------------------------- - with ui.card().classes("h-25 rounded-none").style("background-color: #e30013"): - # Hinweis: rounded-none entfernt die abgerundeten Ecken, damit es nahtlos aussieht - ui.image('gui/logo.png').classes('absolute top-4 right-4 w-55') +def setup_route(): + @ui.page("/") - # --------------------------------------------------------- - # BEREICH MITTE (Inhalt) - Variable Höhe (flex-1) - # --------------------------------------------------------- - # 'flex-1' ist hier entscheidend. Es sagt: "Nimm allen Platz zwischen Header und Footer". - # 'overflow-hidden' verhindert, dass das ganze Fenster scrollt -> wir wollen nur die Tabelle scrollen. - with ui.row().classes("w-full flex-1 p-4 gap-4 no-wrap overflow-hidden"): + def main_page(): + with ui.column().classes('w-full h-screen no-wrap gap-0 items-stretch'): + # --------------------------------------------------------- + # Header + # --------------------------------------------------------- + with ui.card().classes("h-25 rounded-none").style("background-color: #e30013"): + # Hinweis: rounded-none entfernt die abgerundeten Ecken, damit es nahtlos aussieht + ui.image('gui/logo.png').classes('absolute top-4 right-4 w-55') + # --------------------------------------------------------- + # MITTE + # --------------------------------------------------------- + with ui.row().classes("w-full flex-1 p-4 gap-4 no-wrap overflow-hidden"): - with ui.column(): - # --- Linke Karte: Eingabemaske --- - # 'overflow-y-auto': Falls das Formular zu lang für kleine Bildschirme wird, bekommt nur diese Karte einen Scrollbalken. - with ui.card().classes('overflow-y-auto'): + with ui.column(): + # --- Linke Karte: Eingabemaske --- + with ui.card().classes('overflow-y-auto'): + traeger = database.get_ats_names() + input_name = ui.select(label="ATS Träger Name", options=traeger, with_input=True).classes('w-full') + input_location = ui.input(label='Einsatzort', placeholder='Adresse, oder Beschreibung').classes("w-full") + with ui.row().classes('gap-10'): + today = datetime.now().strftime("%Y-%m-%d") + with ui.input('Datum', value=today).classes('flex-1') as date_input: + with date_input.add_slot('append'): + ui.icon('event').classes('cursor-pointer') \ + .on('click', lambda: menu.open()) + with ui.menu() as menu: + input_date = ui.date().bind_value(date_input) - traeger = database.get_ats_names() - input_name = ui.select(label="ATS Träger Name", options=traeger, with_input=True).classes('w-full') + input_time = ui.number(label="Dauer (Min)", value=0).classes('flex-1') + with ui.row().classes("gap-10 w-full items-center"): + input_type = ui.toggle(["Einsatz", "Übung"]).classes('flex-1 center') + input_device = ui.select(["ATS Gerät 1", "ATS Gerät 2"], label="ATS Gerät auswählen").classes('flex-1') + + def ClearForm(): + input_name.value = "" + input_location.value = "" + input_date.value = today + input_time.value = 0 + input_type.value = "Einsatz" # Achtung: Value sollte zum Toggle passen (String, nicht 0) + input_device.value = None # Select resetten + ui.notify("Gelöscht.") + + def InputDataToTable(): + name = input_name.value + location = input_location.value + date = input_date.value + time = input_time.value + etype = input_type.value + device = input_device.value + # Hinweis: database Aufruf ist hier korrekt, sofern importiert + database.add_data_to_einsaetze(name, location, date, time, etype, device) + einsaetze_table.rows = database.get_einsaetze() + einsaetze_table.update() + ui.notify("Eintrag in Datenbank erstellt.") + ClearForm() - input_location = ui.input(label='Einsatzort', placeholder='Adresse, oder Beschreibung').classes("w-full") - with ui.row().classes('gap-10'): - today = datetime.now().strftime("%Y-%m-%d") - with ui.input('Datum', value=today).classes('flex-1') as date_input: - with date_input.add_slot('append'): - ui.icon('event').classes('cursor-pointer') \ - .on('click', lambda: menu.open()) - with ui.menu() as menu: - input_date = ui.date().bind_value(date_input) - input_time = ui.number(label="Dauer (Min)", value=0).classes('flex-1') - - with ui.row().classes("gap-10 w-full items-center"): - input_type = ui.toggle(["Einsatz", "Übung"]).classes('flex-1 center') - input_device = ui.select(["ATS Gerät 1", "ATS Gerät 2"], label="ATS Gerät auswählen").classes('flex-1') - - def InputDataToTable(): - name = input_name.value - location = input_location.value - date = input_date.value - time = input_time.value - etype = input_type.value - device = input_device.value - # Hinweis: database Aufruf ist hier korrekt, sofern importiert - database.add_data_to_einsaetze(name, location, date, time, etype, device) - - einsaetze_table.rows = database.get_einsaetze() - einsaetze_table.update() - ui.notify("Eintrag in Datenbank erstellt.") - - def ClearForm(): - input_name.value = "" - input_location.value = "" - input_date.value = today - input_time.value = 0 - input_type.value = "Einsatz" # Achtung: Value sollte zum Toggle passen (String, nicht 0) - input_device.value = None # Select resetten - ui.notify("Gelöscht.") - ui.notify(admin_login.value) - - ui.separator() - ui.space() # Drückt die Buttons nach unten (innerhalb der Formular-Karte) - with ui.row().classes('w-full'): - ui.button(text="Leeren", on_click=ClearForm) - ui.space() - ui.button(text="Eintragen", on_click=InputDataToTable) - - admin_container = ui.column().classes("w-full") - - with ui.card().classes("w-full"): - # 1. Das Passwort-Feld - pw_input = ui.input("Passwort", password=True) - - # Das Admin-Panel wird nur angezeigt, wenn der Wert vom Input '1234' ist. - # lambda v: v == '1234' ist die Prüf-Logik (True/False). - - with ui.card().bind_visibility_from(pw_input, 'value', backward=lambda v: v == '1234').classes("w-full"): - ui.label("Admin Panel") + ui.separator() + ui.space() # Drückt die Buttons nach unten (innerhalb der Formular-Karte) with ui.row().classes('w-full'): - ui.input(label="Neuer ATS Träger").classes('flex-1') - ui.button(text="Hinzufügen") + ui.button(text="Leeren", on_click=ClearForm) + ui.space() + ui.button(text="Eintragen", on_click=InputDataToTable) - # --- Rechte Karte: Tabelle --- - # 'flex-1': Diese Karte nimmt die restliche Breite der Reihe ein. - # 'h-full': Diese Karte nutzt die volle Höhe des mittleren Bereichs. - with ui.card().classes('flex-1 h-full p-0'): - collums = [ - {'name': 'date', 'label': 'Datum', 'field': 'date', 'sortable': True, 'align': 'left'}, - {'name': 'name', 'label': 'Name', 'field': 'name', 'sortable': True, 'align': 'left'}, - {'name': 'location', 'label': 'Ort', 'field': 'location', 'align': 'left'}, - {'name': 'time', 'label': 'Dauer', 'field': 'time'}, - {'name': 'etype', 'label': 'Art', 'field': 'etype', "sortable": True}, - {'name': 'device', 'label': 'Gerät', 'field': 'device', "sortable": True}, - ] - # Die Tabelle selbst bekommt auch h-full, damit sie die Karte ausfüllt - einsaetze_table = ui.table( - columns = collums, - rows = database.get_einsaetze(), - row_key = "id" - ).classes("w-full h-full") + with ui.card().classes("w-full"): + # 1. Das Passwort-Feld + pw_input = ui.input("Passwort", password=True) - # --------------------------------------------------------- - # BEREICH UNTEN (Footer) - Automatische Höhe - # --------------------------------------------------------- - # Hier landet dein Switch. Durch 'flex-1' im mittleren Bereich wird dieser Teil - # immer an den unteren Bildschirmrand geschoben. - - with ui.row().classes("p-2 pb-6 items-center"): - dark = ui.dark_mode(True) - #Light/Dark Switch in der Leiste unten. - ui.switch('Dark mode').bind_value(dark) + with ui.card().bind_visibility_from(pw_input, 'value', backward=lambda v: v == '1234').classes("w-full"): + ui.button(text="Admin Seite", on_click=lambda:ui.navigate.to("/admin")) + + # --- Rechte Karte: Tabelle --- + with ui.card().classes('flex-1 h-full p-0'): + collums = [ + {'name': 'date', 'label': 'Datum', 'field': 'date', 'sortable': True, 'align': 'left'}, + {'name': 'name', 'label': 'Name', 'field': 'name', 'sortable': True, 'align': 'left'}, + {'name': 'location', 'label': 'Ort', 'field': 'location', 'align': 'left'}, + {'name': 'time', 'label': 'Dauer', 'field': 'time'}, + {'name': 'etype', 'label': 'Art', 'field': 'etype', "sortable": True}, + {'name': 'device', 'label': 'Gerät', 'field': 'device', "sortable": True}, + ] + # Die Tabelle selbst bekommt auch h-full, damit sie die Karte ausfüllt + einsaetze_table = ui.table( + columns = collums, + rows = database.get_einsaetze(), + row_key = "id" + ).classes("w-full h-full") + + # --------------------------------------------------------- + # Footer + # --------------------------------------------------------- + + with ui.row().classes("p-2 pb-6 items-center"): + dark = ui.dark_mode(True) + #Light/Dark Switch in der Leiste unten. + ui.switch('Dark mode').bind_value(dark) diff --git a/main.py b/main.py index 8ea17c1..702190a 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,10 @@ from gui import main_gui from nicegui import ui -import database +from data import database database.initialize_db() -main_gui.build_ui() +main_gui.setup_route() main_gui.ui.run( title="ATS Träger Dokumentation",