"""Dashboard API endpoints.""" from flask import Blueprint, current_app from flask_jwt_extended import jwt_required from shopdb.extensions import db from shopdb.core.models import Machine, MachineType, MachineStatus from shopdb.utils.responses import success_response dashboard_bp = Blueprint('dashboard', __name__) @dashboard_bp.route('/summary', methods=['GET']) @dashboard_bp.route('', methods=['GET']) @jwt_required(optional=True) def get_dashboard(): """Get dashboard summary data.""" # Count machines by category equipment_count = db.session.query(Machine).join(MachineType).filter( Machine.isactive == True, MachineType.category == 'Equipment' ).count() pc_count = db.session.query(Machine).join(MachineType).filter( Machine.isactive == True, MachineType.category == 'PC' ).count() network_count = db.session.query(Machine).join(MachineType).filter( Machine.isactive == True, MachineType.category == 'Network' ).count() # Count by status status_counts = db.session.query( MachineStatus.status, db.func.count(Machine.machineid) ).outerjoin( Machine, db.and_(Machine.statusid == MachineStatus.statusid, Machine.isactive == True) ).group_by(MachineStatus.status).all() # Recent machines recent_machines = Machine.query.filter_by(isactive=True).order_by( Machine.createddate.desc() ).limit(10).all() # Build status dict status_dict = {status: count for status, count in status_counts} return success_response({ # Fields expected by frontend 'totalmachines': equipment_count + pc_count + network_count, 'totalequipment': equipment_count, 'totalpc': pc_count, 'totalnetwork': network_count, 'activemachines': status_dict.get('In Use', 0), 'inrepair': status_dict.get('In Repair', 0), # Also include structured data 'counts': { 'equipment': equipment_count, 'pcs': pc_count, 'networkdevices': network_count, 'total': equipment_count + pc_count + network_count }, 'bystatus': status_dict, 'recent': [ { 'machineid': m.machineid, 'machinenumber': m.machinenumber, 'machinetype': m.machinetype.machinetype if m.machinetype else None, 'createddate': m.createddate.isoformat() + 'Z' if m.createddate else None } for m in recent_machines ] }) @dashboard_bp.route('/stats', methods=['GET']) @jwt_required(optional=True) def get_stats(): """Get detailed statistics.""" # Machine type breakdown type_counts = db.session.query( MachineType.machinetype, MachineType.category, db.func.count(Machine.machineid) ).outerjoin( Machine, db.and_(Machine.machinetypeid == MachineType.machinetypeid, Machine.isactive == True) ).filter(MachineType.isactive == True).group_by( MachineType.machinetypeid ).all() return success_response({ 'bytype': [ {'type': t, 'category': c, 'count': count} for t, c, count in type_counts ] }) @dashboard_bp.route('/navigation', methods=['GET']) def get_navigation(): """Get navigation items from all loaded plugins.""" pm = current_app.extensions.get('plugin_manager') if not pm: return success_response([]) all_items = [] # Core navigation items (always present) all_items.extend([ {'name': 'Dashboard', 'icon': 'layout-dashboard', 'route': '/', 'position': 0}, {'name': 'Map', 'icon': 'map', 'route': '/map', 'position': 4}, ]) # Collect navigation items from all plugins for name, plugin in pm.get_all_plugins().items(): try: items = plugin.get_navigation_items() for item in items: item['plugin'] = name all_items.extend(items) except Exception: pass # Add core information section items all_items.extend([ {'name': 'Applications', 'icon': 'app-window', 'route': '/applications', 'position': 30, 'section': 'information'}, {'name': 'Knowledge Base', 'icon': 'book-open', 'route': '/knowledgebase', 'position': 35, 'section': 'information'}, {'name': 'Reports', 'icon': 'bar-chart-3', 'route': '/reports', 'position': 40, 'section': 'information'}, ]) # Sort by position all_items.sort(key=lambda x: x.get('position', 99)) return success_response(all_items) @dashboard_bp.route('/health', methods=['GET']) def health_check(): """Health check endpoint (no auth required).""" try: # Test database connection db.session.execute(db.text('SELECT 1')) db_status = 'healthy' except Exception as e: db_status = f'unhealthy: {str(e)}' return success_response({ 'status': 'ok' if db_status == 'healthy' else 'degraded', 'database': db_status, 'version': '1.0.0' })