diff --git a/dashboard.py b/dashboard.py index 1f9fa9d..87b105a 100644 --- a/dashboard.py +++ b/dashboard.py @@ -3,6 +3,7 @@ from flask import Flask, render_template_string, jsonify from datetime import datetime, date app = Flask(__name__) +# Updated path for Docker volume DB_FILE = "/app/data/cleaning_logs.db" # Room definitions @@ -25,7 +26,6 @@ BUILDINGS = { } def get_all_defined_rooms(): - """Get a set of all room numbers defined in buildings""" rooms = set() for floors in BUILDINGS.values(): for floor in floors: @@ -33,16 +33,17 @@ def get_all_defined_rooms(): return rooms def get_room_statuses(): - """Returns dict: {room_number: (last_cleaned_time, is_today)}""" today = date.today().strftime("%Y-%m-%d") - - with sqlite3.connect(DB_FILE) as conn: - cursor = conn.execute(""" - SELECT room_number, MAX(cleaned_at) as last_cleaned - FROM cleaning_events - GROUP BY room_number - """) - rows = cursor.fetchall() + try: + with sqlite3.connect(DB_FILE) as conn: + cursor = conn.execute(""" + SELECT room_number, MAX(cleaned_at) as last_cleaned + FROM cleaning_events + GROUP BY room_number + """) + rows = cursor.fetchall() + except sqlite3.OperationalError: + return {} statuses = {} for room, last_cleaned in rows: @@ -51,18 +52,11 @@ def get_room_statuses(): "is_today": is_today, "last_cleaned": last_cleaned } - return statuses def get_special_rooms(statuses): - """Get rooms that aren't in any defined building""" defined_rooms = get_all_defined_rooms() - special_rooms = [] - - for room_number in statuses.keys(): - if room_number not in defined_rooms: - special_rooms.append(room_number) - + special_rooms = [r for r in statuses.keys() if r not in defined_rooms] return sorted(special_rooms) @app.route('/') @@ -78,7 +72,6 @@ def dashboard(): @app.route('/api/status') def api_status(): - """API endpoint for live updates""" statuses = get_room_statuses() special_rooms = get_special_rooms(statuses) return jsonify({ @@ -95,224 +88,172 @@ TEMPLATE = ''' body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; } h1 { color: #333; } .controls { margin-bottom: 20px; } - .toggle { padding: 10px 20px; font-size: 16px; cursor: pointer; } - .building { margin-bottom: 30px; background: white; padding: 15px; border-radius: 8px; } - .building h2 { margin-top: 0; color: #555; } + .toggle { padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 5px; border: 1px solid #ccc; } + .building { margin-bottom: 30px; background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } + .building h2 { margin-top: 0; color: #555; border-bottom: 2px solid #eee; padding-bottom: 5px; } .floor { margin-bottom: 15px; } - .floor-label { font-weight: bold; margin-bottom: 5px; color: #777; } + .floor-label { font-weight: bold; margin-bottom: 8px; color: #777; } .rooms { display: flex; flex-wrap: wrap; gap: 8px; } .room { padding: 10px 15px; border-radius: 5px; - min-width: 80px; + min-width: 90px; text-align: center; font-weight: bold; - transition: background 0.3s ease; + transition: all 0.3s ease; } .room.cleaned { background: #4CAF50; color: white; } .room.not-cleaned { background: #f44336; color: white; } - .room.cleaned .time-display, .room.not-cleaned .time-display { + .time-display { display: block; font-size: 14px; font-weight: normal; margin-top: 6px; - line-height: 1.4; + line-height: 1.2; } .hidden { display: none !important; }