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 eea985e..6628038 100644 Binary files a/__pycache__/database.cpython-312.pyc and b/__pycache__/database.cpython-312.pyc differ diff --git a/ats_doku.db b/ats_doku.db deleted file mode 100644 index 9bb2e98..0000000 Binary files a/ats_doku.db and /dev/null differ diff --git a/data/data_api.py b/data/data_api.py new file mode 100644 index 0000000..0b54a3f --- /dev/null +++ b/data/data_api.py @@ -0,0 +1,2 @@ +import sqlite3 +from data.database import DB_NAME \ No newline at end of file diff --git a/database.py b/data/database.py similarity index 98% rename from database.py rename to data/database.py index 06fc2f6..86a5183 100644 --- a/database.py +++ b/data/database.py @@ -29,7 +29,6 @@ def initialize_db(): ''') # Optional: Ein paar Test-ats anlegen, falls die Tabelle leer ist - # (Damit du direkt was im Dropdown siehst) cursor.execute("SELECT count(*) FROM ats") if cursor.fetchone()[0] == 0: ats_liste = [("Tim Grubmüller",), ("Phil Langer",), ("Max Hämmerle",)] diff --git a/gui/__pycache__/__init__.cpython-312.pyc b/gui/__pycache__/__init__.cpython-312.pyc index db09f65..a1de765 100644 Binary files a/gui/__pycache__/__init__.cpython-312.pyc and b/gui/__pycache__/__init__.cpython-312.pyc differ diff --git a/gui/__pycache__/main_gui.cpython-312.pyc b/gui/__pycache__/main_gui.cpython-312.pyc index 9f3724c..516c19b 100644 Binary files a/gui/__pycache__/main_gui.cpython-312.pyc and b/gui/__pycache__/main_gui.cpython-312.pyc differ 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",