diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile index 0ebca70..e99d86b 100644 --- a/dashboard/Dockerfile +++ b/dashboard/Dockerfile @@ -14,6 +14,7 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* # --- Python-Abhängigkeiten kopieren und installieren --- +COPY dash_using_fullcalendar-0.0.1.tar.gz ./ COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt diff --git a/dashboard/Dockerfile.dev b/dashboard/Dockerfile.dev index 4c0e404..3385cef 100644 --- a/dashboard/Dockerfile.dev +++ b/dashboard/Dockerfile.dev @@ -27,6 +27,7 @@ RUN groupadd -g ${GROUP_ID} infoscreen_taa \ WORKDIR /app # Kopiere nur Requirements für schnellen Rebuild +COPY dash_using_fullcalendar-0.0.1.tar.gz ./ COPY requirements.txt ./ COPY requirements-dev.txt ./ diff --git a/dashboard/app.py b/dashboard/app.py index d75a3dd..6d17f61 100644 --- a/dashboard/app.py +++ b/dashboard/app.py @@ -9,6 +9,7 @@ from components.header import Header # from components.sidebar import Sidebar import callbacks.ui_callbacks # wichtig! import dashboard.callbacks.overview_callbacks # <-- Das registriert die Callbacks +import dashboard.callbacks.appointments_callbacks from config import SECRET_KEY, ENV server = Flask(__name__) @@ -18,15 +19,19 @@ app = Dash( __name__, server=server, use_pages=True, - external_stylesheets=[dbc.themes.BOOTSTRAP], - suppress_callback_exceptions=True + # external_stylesheets=[dbc.themes.BOOTSTRAP], + suppress_callback_exceptions=True, + serve_locally=True ) app.layout = html.Div([ Header(), dcc.Store(id="sidebar-state", data={"collapsed": False}), + # dcc.Store(id="calendar-click-store"), + # dcc.Store(id="calendar-event-store"), html.Div(id="sidebar"), # Sidebar wird dynamisch gerendert html.Div(page_container, className="page-content"), + html.Div("TEST", id="test-div"), ]) diff --git a/dashboard/callbacks/appoinments_callbacks.py b/dashboard/callbacks/appoinments_callbacks.py deleted file mode 100644 index fb17367..0000000 --- a/dashboard/callbacks/appoinments_callbacks.py +++ /dev/null @@ -1,27 +0,0 @@ -# dashboard/callbacks/appointments_callbacks.py -import dash -from dash import Input, Output, State, dcc -from flask import session -from utils.db import execute_query, execute_non_query - -@dash.callback( - Output("appointments-feedback", "children"), - Input("btn-add-appointment", "n_clicks"), - State("input-client-id", "value"), - State("input-appointment-date", "date"), - State("input-appointment-time", "value"), - State("input-appointment-desc", "value"), - prevent_initial_call=True -) -def add_appointment(n_clicks, client_id, date, time_str, desc): - if "role" not in session: - return dcc.Location(href="/login") - if n_clicks and n_clicks > 0: - datetime_str = f"{date} {time_str}:00" - sql = """ - INSERT INTO appointments (client_id, start_datetime, description) - VALUES (%s, %s, %s) - """ - rc = execute_non_query(sql, (client_id, datetime_str, desc)) - return "Erstellt." if rc else "Fehler beim Anlegen." - return "" diff --git a/dashboard/callbacks/appointments_callbacks.py b/dashboard/callbacks/appointments_callbacks.py new file mode 100644 index 0000000..7baf82a --- /dev/null +++ b/dashboard/callbacks/appointments_callbacks.py @@ -0,0 +1,36 @@ +# dashboard/callbacks/appointments_callbacks.py +import sys +sys.path.append('/workspace') +from dash import Input, Output, State, callback, ctx, dash +from flask import session +import json + +print("appointments_callbacks.py geladen") + +@callback( + dash.Output('output', 'children'), + dash.Input('calendar', 'lastDateClick') +) +def display_date(date_str): + if date_str: + return f"Letzter Klick auf: {date_str}" + return "Klicke auf ein Datum im Kalender!" + +@callback( + dash.Output('event-output', 'children'), + dash.Input('calendar', 'lastEventClick') +) +def display_event(event_id): + if event_id: + return f"Letztes Event geklickt: {event_id}" + return "Klicke auf ein Event im Kalender!" + +@callback( + dash.Output('select-output', 'children'), + dash.Input('calendar', 'lastSelect') +) +def display_select(select_info): + if select_info: + return f"Markiert: {select_info['start']} bis {select_info['end']} (ganztägig: {select_info['allDay']})" + return "Markiere einen Bereich im Kalender!" + diff --git a/dashboard/callbacks/overview_callbacks.py b/dashboard/callbacks/overview_callbacks.py index cf09a40..0ebc052 100644 --- a/dashboard/callbacks/overview_callbacks.py +++ b/dashboard/callbacks/overview_callbacks.py @@ -15,6 +15,8 @@ import time import pytz from datetime import datetime +print("overview_callbacks.py geladen") + API_BASE_URL = os.getenv("API_BASE_URL", "http://192.168.43.100") mqtt_thread_started = False diff --git a/dashboard/dash_using_fullcalendar-0.0.1.tar.gz b/dashboard/dash_using_fullcalendar-0.0.1.tar.gz new file mode 100644 index 0000000..6d0058a Binary files /dev/null and b/dashboard/dash_using_fullcalendar-0.0.1.tar.gz differ diff --git a/dashboard/pages/appointments.py b/dashboard/pages/appointments.py index 3983191..0763c91 100644 --- a/dashboard/pages/appointments.py +++ b/dashboard/pages/appointments.py @@ -1,16 +1,60 @@ # dashboard/pages/appointments.py -from dash import html +from dash import html, dcc import dash +from dash_using_fullcalendar import DashUsingFullcalendar + +# dash.register_page(__name__, path="/appointments", name="Termine") +# def layout(): # Als Funktion definieren +# return html.Div([ +# dcc.Store(id="calendar-click-store"), +# dcc.Store(id="calendar-event-store"), +# dcc.Input(id="test-input"), +# html.Div("TEST") +# ]) +import dash_bootstrap_components as dbc dash.register_page(__name__, path="/appointments", name="Termine") -layout = html.Div( - className="appointments-page", - children=[ - html.H3("Terminverwaltung"), - html.Div(id="calendar-container"), - html.Button("Neuen Termin anlegen", id="btn-add-appointment"), - html.Div(id="appointments-feedback"), - # Hier später das Modal oder das FullCalendar‐Element einfügen - ] -) +layout = dbc.Container([ + dbc.Row([ + dbc.Col(html.H2("Dash FullCalendar mit Bootstrap 5")) + ]), + dbc.Row([ + dbc.Col( + DashUsingFullcalendar( + id='calendar', + events=[ + {"id": "1", "title": "Meeting", "date": "2025-06-13T09:00:00"}, + {"id": "2", "title": "Workshop", "date": "2025-06-15T14:30:00"} + ], + initialView="timeGridWeek", + headerToolbar={ + "left": "prev,next today", + "center": "title", + "right": "dayGridMonth,timeGridWeek,timeGridDay" + }, + height=600, + locale="de", + slotDuration="00:30:00", + slotMinTime="00:00:00", + slotMaxTime="24:00:00", + scrollTime="07:00:00", + weekends=True, + allDaySlot=False, + firstDay=1, + # themeSystem kann auf "bootstrap5" gesetzt werden, wenn das Plugin eingebunden ist + themeSystem="bootstrap5" + ) + ) + ]), + dbc.Row([ + dbc.Col(html.Div(id='output')) + ]), + dbc.Row([ + dbc.Col(html.Div(id='event-output')) + ]), + dbc.Row([ + dbc.Col(html.Div(id='select-output')) + ]) +], fluid=True) + diff --git a/dashboard/requirements.txt b/dashboard/requirements.txt index 7447fd4..4e531a3 100644 --- a/dashboard/requirements.txt +++ b/dashboard/requirements.txt @@ -10,3 +10,4 @@ paho-mqtt>=2.1.0 python-dotenv>=1.1.0 PyMySQL>=1.1.1 SQLAlchemy>=2.0.41 +./dash_using_fullcalendar-0.0.1.tar.gz