first feasability of event management feature

This commit is contained in:
2025-06-19 07:34:56 +00:00
parent dc7fa6b2cb
commit 19f817b796
8 changed files with 120 additions and 19 deletions

1
.gitignore vendored
View File

@@ -72,3 +72,4 @@ dashboard/pages/test.py
.gitignore
dashboard/sidebar_test.py
dashboard/assets/responsive-sidebar.css
certs/

View File

@@ -36,6 +36,10 @@ app.layout = dmc.MantineProvider([
])
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8050, debug=(ENV=="development"))
app.run(
host="0.0.0.0",
port=8050,
debug=(ENV=="development"),
ssl_context=("/workspace/certs/dev.crt", "/workspace/certs/dev.key")
)

View File

@@ -201,11 +201,30 @@ body {
z-index: var(--mantine-z-index-modal, 3000) !important;
}
/* Modalbox */
.mantine-Modal-inner,
.mantine-Modal-content {
z-index: 4000 !important;
}
/* Popups (Dropdowns, Datepicker, Autocomplete, Menüs) innerhalb der Modalbox */
.mantine-Popover-dropdown,
.mantine-Select-dropdown,
.mantine-DatePicker-dropdown,
.mantine-Autocomplete-dropdown,
.mantine-Menu-dropdown {
z-index: 4100 !important;
}
/* Optional: Overlay für Popups noch höher, falls benötigt */
.mantine-Popover-root,
.mantine-Select-root,
.mantine-DatePicker-root,
.mantine-Autocomplete-root,
.mantine-Menu-root {
z-index: 4101 !important;
}
/* Sidebar collapsed: Icon-Farbe normal */
.sidebar.collapsed .sidebar-item-collapsed svg {
color: #7c5617; /* Icon-Linie/Text */

View File

@@ -1,4 +1,4 @@
from dash import Input, Output, State, callback, html, dcc, no_update
from dash import Input, Output, State, callback, html, dcc, no_update, ctx
import dash_mantine_components as dmc
from dash_iconify import DashIconify
import dash_quill
@@ -313,7 +313,6 @@ def update_end_time_options(search_value):
prevent_initial_call=True
)
def handle_end_time(start_time, reset_clicks, current_end_time):
ctx = callback.ctx
if not ctx.triggered:
return no_update
trigger_id = ctx.triggered[0]['prop_id'].split('.')[0]
@@ -338,7 +337,7 @@ def handle_end_time(start_time, reset_clicks, current_end_time):
@callback(
[
Output('title-input', 'value'),
Output('start-date-input', 'value'),
Output('start-date-input', 'value', allow_duplicate=True),
Output('time-start', 'value'),
Output('type-input', 'value'),
Output('description-input', 'value'),

View File

@@ -2,9 +2,13 @@
import requests
import json
from flask import session
from dash import Input, Output, State, callback, ctx, dash
from dash import Input, Output, State, callback, ctx, dash, no_update
import os
import sys
from datetime import datetime, timedelta
# --- Modalbox öffnen: jetzt auch auf Kalenderklick reagieren ---
sys.path.append('/workspace')
print("appointments_callbacks.py geladen")
@@ -69,19 +73,86 @@ def load_events(view_dates):
@callback(
Output("appointment-modal", "opened"),
[
Output("appointment-modal", "opened"),
Output("start-date-input", "value", allow_duplicate=True),
Output("time-start", "value", allow_duplicate=True),
Output("time-end", "value", allow_duplicate=True),
],
[
Input("calendar", "lastDateClick"),
Input("calendar", "lastSelect"),
Input("open-appointment-modal-btn", "n_clicks"),
Input("close-appointment-modal-btn", "n_clicks")
Input("close-appointment-modal-btn", "n_clicks"),
],
State("appointment-modal", "opened"),
prevent_initial_call=True
)
def toggle_appointment_modal(open_click, close_click, is_open):
from dash import ctx
def open_modal(date_click, select, open_click, close_click, is_open):
trigger = ctx.triggered_id
# Bereichsauswahl (lastSelect)
if trigger == "calendar" and select:
try:
start_dt = datetime.fromisoformat(select["start"])
end_dt = datetime.fromisoformat(select["end"])
return (
True,
start_dt.date().isoformat(),
start_dt.strftime("%H:%M"),
end_dt.strftime("%H:%M"),
)
except Exception as e:
print("Fehler beim Parsen von select:", e)
return no_update, no_update, no_update, no_update
# Einzelklick (lastDateClick)
if trigger == "calendar" and date_click:
try:
dt = datetime.fromisoformat(date_click)
# Versuche, die Slotlänge aus dem Kalender zu übernehmen (optional)
# Hier als Beispiel 30 Minuten aufaddieren, falls keine Endzeit vorhanden
end_dt = dt + timedelta(minutes=30)
return (
True,
dt.date().isoformat(),
dt.strftime("%H:%M"),
end_dt.strftime("%H:%M"),
)
except Exception as e:
print("Fehler beim Parsen von date_click:", e)
return no_update, no_update, no_update, no_update
# Modal öffnen per Button
if trigger == "open-appointment-modal-btn" and open_click:
return True
now = datetime.now()
end_dt = now + timedelta(minutes=30)
return True, now.date().isoformat(), now.strftime("%H:%M"), end_dt.strftime("%H:%M")
# Modal schließen
if trigger == "close-appointment-modal-btn" and close_click:
return False
return is_open
return False, no_update, no_update, no_update
return is_open, no_update, no_update, no_update
# @callback(
# Output("time-end", "value", allow_duplicate=True),
# Input("time-start", "value"),
# prevent_initial_call=True
# )
# def handle_end_time(start_time, duration="00:30"):
# trigger = ctx.triggered_id
# if trigger == "time-start" and start_time and duration:
# try:
# # Beispiel für start_time: "09:00"
# start_dt = datetime.strptime(start_time, "%H:%M")
# # Dauer in Stunden und Minuten, z.B. "01:30"
# hours, minutes = map(int, duration.split(":"))
# # Endzeit berechnen: Dauer addieren!
# end_dt = start_dt + timedelta(hours=hours, minutes=minutes)
# return end_dt.strftime("%H:%M")
# except Exception as e:
# print("Fehler bei der Berechnung der Endzeit:", e)
# return no_update

View File

@@ -62,11 +62,6 @@ def get_appointment_modal():
title="Neuen Termin anlegen",
centered=True,
size="auto", # oder "80vw"
# fullScreen=True,
# styles={
# "modal": {"zIndex": 2001, "position": "relative"},
# "overlay": {"zIndex": 2000}
# },
children=[
dmc.Container([
dmc.Grid([
@@ -147,13 +142,14 @@ def get_appointment_modal():
{"value": "website", "label": "Website"},
{"value": "video", "label": "Video"},
{"value": "message", "label": "Nachricht"},
{"value": "webuntis", "label": "WebUntis"},
{"value": "other", "label": "Sonstiges"}
],
id="type-input",
required=True,
style={"flex": 1}
),
"Wählen Sie den Typ des Termins für bessere Kategorisierung"
"Wählen Sie die Art der Präsentation aus."
),
html.Div(id="type-specific-fields"),
create_input_with_tooltip_full(

View File

@@ -11,6 +11,7 @@ services:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- server
- dashboard

View File

@@ -7,6 +7,16 @@ http {
listen 80;
server_name _;
# Optional: HTTP auf HTTPS weiterleiten
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name _;
ssl_certificate /etc/nginx/certs/dev.crt;
ssl_certificate_key /etc/nginx/certs/dev.key;
location /api/ {
proxy_pass http://infoscreen-api:8000/api/;
}