1- from nicegui import ui
1+ from nicegui import app , ui
22import aiohttp
3+ import asyncio
4+ import json
35from theme import menu , get_local_ip
46from pages .settings import load_config
57
68def create_page ():
9+ config = load_config ()
10+ edge_port = config .get ('mobile_client' , {}).get ('port' , 8080 )
11+
712 @ui .page ('/clients' )
813 def clients_page ():
9- config = load_config ()
10- edge_port = config .get ('port' , 8080 )
11-
12- with menu ('Mobile Clients & Pairing' ):
14+ with menu ('Mobile Client Connections' ):
1315 ip = get_local_ip ()
1416 server_url = f"ws://{ ip } :{ edge_port } "
1517
1618 with ui .row ().classes ('w-full gap-8' ):
1719 with ui .card ().classes ('items-center p-6 w-1/3' ):
18- ui .label ('Server Pairing' ).classes ('text-xl font-bold mb-4' )
20+ ui .label ('Server Pairing' ).classes ('text-xl font-bold mb-4 text-gray-800 ' )
1921 ui .label ('Scan this QR code with the AllSpark app:' ).classes ('text-sm text-gray-600 text-center mb-4' )
2022
2123 # Generate a QR code using a public API for the prototype
2224 ui .image (f'https://api.qrserver.com/v1/create-qr-code/?size=150x150&data={ server_url } ' ).classes ('w-32 h-32' )
2325 ui .label (server_url ).classes ('mt-4 font-mono font-bold bg-gray-100 p-2 rounded max-w-full break-all text-center' )
2426
25- with ui .column ().classes ('w-2/3' ):
26- ui .label ('Active Connections' ).classes ('text-xl font-bold mb-4 ' )
27+ with ui .column ().classes ('w-2/3 gap-4 ' ):
28+ ui .label ('Active Connections' ).classes ('text-xl font-bold text-gray-800 ' )
2729
28- cards_container = ui .column ().classes ('w-full' )
30+ cards_container = ui .column ().classes ('w-full gap-2 ' )
2931
3032 async def fetch_and_render_clients ():
3133 try :
3234 async with aiohttp .ClientSession () as session :
3335 async with session .get (f'http://127.0.0.1:{ edge_port } /api/status' , timeout = 2 ) as resp :
3436 if resp .status == 200 :
3537 data = await resp .json ()
36- clients_list = data .get ('clients' , [])
37- # Also handle `connectedClients` just in case
38- if not clients_list and 'connectedClients' in data :
38+ clients_list = data .get ('connections' , [])
39+ if not clients_list and 'clients' in data :
40+ clients_list = data ['clients' ]
41+ elif not clients_list and 'connectedClients' in data :
3942 clients_list = data ['connectedClients' ]
4043 render_clients (clients_list )
4144 else :
@@ -49,7 +52,7 @@ async def request_upload(client_id):
4952 payload = {"command" : "upload" }
5053 async with session .post (f'http://127.0.0.1:{ edge_port } /api/command/{ client_id } ' , json = payload ) as resp :
5154 if resp .status == 200 :
52- ui .notify (f'Upload command sent to { client_id } !' , type = 'positive' )
55+ ui .notify (f'Manual upload command sent to { client_id } !' , type = 'positive' )
5356 else :
5457 ui .notify (f'Failed to send command: HTTP { resp .status } ' , type = 'negative' )
5558 except Exception as e :
@@ -59,7 +62,7 @@ def render_clients(clients_data):
5962 cards_container .clear ()
6063 with cards_container :
6164 if clients_data is None :
62- ui .label (f'Edge server offline or / api/status not reachable on port { edge_port } .' ).classes ('text-red-500 italic p-4' )
65+ ui .label (f'Edge server offline or api/status unreachable on port { edge_port } .' ).classes ('text-red-500 italic p-4' )
6366 return
6467 if not clients_data :
6568 ui .label ('Waiting for mobile rig connections...' ).classes ('text-gray-500 italic p-4' )
@@ -68,17 +71,18 @@ def render_clients(clients_data):
6871 for c in clients_data :
6972 client_id = c .get ('id' , 'Unknown' )
7073 c_type = c .get ('type' , 'Rig' )
71- with ui .card ().classes ('w-full mb-2 ' ):
74+ with ui .card ().classes ('w-full border shadow-sm ' ):
7275 with ui .row ().classes ('w-full justify-between items-center' ):
7376 ui .label (f'{ c_type } (ID: { client_id } )' ).classes ('font-bold' )
7477 ui .badge ('Online' , color = 'green' )
75- # Depending on how edge API shapes IP/Stats, display it safely
7678 ui .label (f"Stats: { c .get ('details' , 'No details available' )} " ).classes ('text-sm text-gray-600 mt-1' )
79+
80+ if c .get ("lastFilename" ):
81+ ui .label (f"Latest File: { c ['lastFilename' ]} " ).classes ('text-sm text-green-700 mt-1' )
82+
7783 with ui .row ().classes ('mt-4 items-center gap-2' ):
78- ui .input ('Start Time' , value = '2026-03-25T09:00:00' ).props ('type=datetime-local borderless dense' ).classes ('w-48' )
79- ui .input ('End Time' , value = '2026-03-25T10:00:00' ).props ('type=datetime-local borderless dense' ).classes ('w-48' )
80- ui .button ('Request Upload' , on_click = lambda ci = client_id : request_upload (ci )).classes ('bg-blue-600 text-white' )
84+ ui .button ('Force Sync Uploads' , on_click = lambda ci = client_id : request_upload (ci )).classes ('bg-blue-600 text-white' )
8185
82- # Poll the API
83- ui .timer (5 .0 , fetch_and_render_clients )
86+ # Poll the API for client list
87+ ui .timer (2 .0 , fetch_and_render_clients )
8488 ui .timer (0.1 , fetch_and_render_clients , once = True )
0 commit comments