This commit is contained in:
pe1hvh
2026-03-12 13:49:47 +01:00
parent ec1c36373e
commit 637551cdad
2 changed files with 43 additions and 99 deletions
+43 -92
View File
@@ -34,7 +34,6 @@ class _DeletedClientFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
return 'Client has been deleted' not in record.getMessage()
logging.getLogger('nicegui').addFilter(_DeletedClientFilter())
@@ -230,10 +229,9 @@ body, .q-layout, .q-page {
</style>
'''
# ── Landing SVG loader ────────────────────────────────────────────────
# Reads the SVG from config.LANDING_SVG_PATH and replaces {callsign}
# with config.OPERATOR_CALLSIGN. Falls back to a minimal placeholder
# with config.OPERATOR_CALLSIGN. Falls back to a minimal placeholder
# when the file is missing.
@@ -261,16 +259,15 @@ def _load_landing_svg() -> str:
# ── Standalone menu items (no submenus) ──────────────────────────────
_STANDALONE_ITEMS = [
('👥', 'CONTACTS', 'contacts'),
('🗺️', 'MAP', 'map'),
('📡', 'DEVICE', 'device'),
('', 'ACTIONS', 'actions'),
('📊', 'RX LOG', 'rxlog'),
('\U0001f465', 'CONTACTS', 'contacts'),
('\U0001f5fa\ufe0f', 'MAP', 'map'),
('\U0001f4e1', 'DEVICE', 'device'),
('\u26a1', 'ACTIONS', 'actions'),
('\U0001f4ca', 'RX LOG', 'rxlog'),
]
_EXT_LINKS = config.EXT_LINKS
# ── Shared button styles ─────────────────────────────────────────────
_SUB_BTN_STYLE = (
@@ -293,12 +290,7 @@ class DashboardPage:
shared: SharedDataReader for data access and command dispatch.
"""
def __init__(
self,
shared: SharedDataReader,
pin_store: PinStore,
room_password_store: RoomPasswordStore,
) -> None:
def __init__(self, shared: SharedDataReader, pin_store: PinStore, room_password_store: RoomPasswordStore) -> None:
self._shared = shared
self._pin_store = pin_store
self._room_password_store = room_password_store
@@ -351,12 +343,7 @@ class DashboardPage:
# Create panel instances (UNCHANGED functional wiring)
put_cmd = self._shared.put_command
self._device = DevicePanel()
self._contacts = ContactsPanel(
put_cmd,
self._pin_store,
self._shared.set_auto_add_enabled,
self._on_add_room_server,
)
self._contacts = ContactsPanel(put_cmd, self._pin_store, self._shared.set_auto_add_enabled, self._on_add_room_server)
self._map = MapPanel()
self._messages = MessagesPanel(put_cmd)
self._actions = ActionsPanel(put_cmd, self._shared.set_bot_enabled)
@@ -392,57 +379,46 @@ class DashboardPage:
# ── 💬 MESSAGES (expandable with channel submenu) ──────
with ui.expansion(
'💬 MESSAGES',
icon=None,
value=False,
'\U0001f4ac MESSAGES', icon=None, value=False,
).props('dense header-class="q-pa-none"').classes('w-full'):
self._msg_sub_container = ui.column().classes('w-full gap-0')
with self._msg_sub_container:
self._make_sub_btn(
'ALL',
lambda: self._navigate_panel('messages', channel=None),
'ALL', lambda: self._navigate_panel('messages', channel=None)
)
self._make_sub_btn(
'DM',
lambda: self._navigate_panel('messages', channel='DM'),
'DM', lambda: self._navigate_panel('messages', channel='DM')
)
# Dynamic channel items populated by _update_submenus
# ── 🏠 ROOMS (expandable with room submenu) ───────────
with ui.expansion(
'🏠 ROOMS',
icon=None,
value=False,
'\U0001f3e0 ROOMS', icon=None, value=False,
).props('dense header-class="q-pa-none"').classes('w-full'):
self._rooms_sub_container = ui.column().classes('w-full gap-0')
with self._rooms_sub_container:
self._make_sub_btn(
'ALL',
lambda: self._navigate_panel('rooms'),
'ALL', lambda: self._navigate_panel('rooms')
)
# Pre-populate from persisted rooms
for entry in self._room_password_store.get_rooms():
short = entry.name or entry.pubkey[:12]
self._make_sub_btn(
f'🏠 {short}',
f'\U0001f3e0 {short}',
lambda: self._navigate_panel('rooms'),
)
# ── 📚 ARCHIVE (expandable with channel submenu) ──────
with ui.expansion(
'📚 ARCHIVE',
icon=None,
value=False,
'\U0001f4da ARCHIVE', icon=None, value=False,
).props('dense header-class="q-pa-none"').classes('w-full'):
self._archive_sub_container = ui.column().classes('w-full gap-0')
with self._archive_sub_container:
self._make_sub_btn(
'ALL',
lambda: self._navigate_panel('archive', channel=None),
'ALL', lambda: self._navigate_panel('archive', channel=None)
)
self._make_sub_btn(
'DM',
lambda: self._navigate_panel('archive', channel='DM'),
'DM', lambda: self._navigate_panel('archive', channel='DM')
)
# Dynamic channel items populated by _update_submenus
@@ -474,9 +450,7 @@ class DashboardPage:
# Footer in drawer
ui.space()
ui.label(f'© 2026 {config.OPERATOR_CALLSIGN}').classes(
'domca-footer'
).style('padding: 0 1.2rem 1rem')
ui.label(f'\u00a9 2026 {config.OPERATOR_CALLSIGN}').classes('domca-footer').style('padding: 0 1.2rem 1rem')
# ── Header ────────────────────────────────────────────────
with ui.header().classes('items-center px-4 py-2 shadow-md'):
@@ -490,7 +464,7 @@ class DashboardPage:
lambda e: menu_btn.props(f'icon={"close" if e.value else "menu"}')
)
ui.label(f'🔗 MeshCore v{config.VERSION}').classes(
ui.label(f'\U0001f517 MeshCore v{config.VERSION}').classes(
'text-lg font-bold ml-2 domca-header-text'
).style("font-family: 'JetBrains Mono', monospace")
@@ -530,11 +504,11 @@ class DashboardPage:
panel_defs = [
('messages', self._messages),
('contacts', self._contacts),
('map', self._map),
('device', self._device),
('actions', self._actions),
('rxlog', self._rxlog),
('rooms', self._room_server),
('map', self._map),
('device', self._device),
('actions', self._actions),
('rxlog', self._rxlog),
('rooms', self._room_server),
]
for panel_id, panel_obj in panel_defs:
@@ -594,12 +568,10 @@ class DashboardPage:
self._msg_sub_container.clear()
with self._msg_sub_container:
self._make_sub_btn(
'ALL',
lambda: self._navigate_panel('messages', channel=None),
'ALL', lambda: self._navigate_panel('messages', channel=None)
)
self._make_sub_btn(
'DM',
lambda: self._navigate_panel('messages', channel='DM'),
'DM', lambda: self._navigate_panel('messages', channel='DM')
)
for ch in channels:
idx = ch['idx']
@@ -614,12 +586,10 @@ class DashboardPage:
self._archive_sub_container.clear()
with self._archive_sub_container:
self._make_sub_btn(
'ALL',
lambda: self._navigate_panel('archive', channel=None),
'ALL', lambda: self._navigate_panel('archive', channel=None)
)
self._make_sub_btn(
'DM',
lambda: self._navigate_panel('archive', channel='DM'),
'DM', lambda: self._navigate_panel('archive', channel='DM')
)
for ch in channels:
idx = ch['idx']
@@ -640,13 +610,12 @@ class DashboardPage:
self._rooms_sub_container.clear()
with self._rooms_sub_container:
self._make_sub_btn(
'ALL',
lambda: self._navigate_panel('rooms'),
'ALL', lambda: self._navigate_panel('rooms')
)
for entry in rooms:
short = entry.name or entry.pubkey[:12]
self._make_sub_btn(
f'🏠 {short}',
f'\U0001f3e0 {short}',
lambda: self._navigate_panel('rooms'),
)
@@ -708,12 +677,16 @@ class DashboardPage:
container.set_visibility(pid == panel_id)
self._active_panel = panel_id
# Apply channel filter to messages panel
if panel_id == 'messages' and self._messages:
self._messages.set_active_channel(channel)
# Apply channel filter to archive panel
if panel_id == 'archive' and self._archive_page:
self._archive_page.set_channel_filter(channel)
self._refresh_active_panel_now(force_map_center=(panel_id == 'map'))
# Update active menu highlight (standalone buttons only)
for pid, btn in self._menu_buttons.items():
if pid == panel_id:
@@ -721,10 +694,6 @@ class DashboardPage:
else:
btn.classes(remove='domca-menu-active')
# Refresh only the selected panel immediately so the user does not
# need to wait for the next 500 ms dashboard tick.
self._refresh_active_panel_now(force_map_center=(panel_id == 'map'))
# Close drawer after selection
if self._drawer:
self._drawer.hide()
@@ -737,27 +706,22 @@ class DashboardPage:
"""
data = self._shared.get_snapshot()
if data.get('channels') and self._messages:
if data.get('channels'):
self._messages.update_filters(data)
self._messages.update_channel_options(data['channels'])
self._update_submenus(data)
if self._active_panel == 'device' and self._device:
if self._active_panel == 'device':
self._device.update(data)
elif self._active_panel == 'map' and self._map:
data = dict(data)
elif self._active_panel == 'map':
if force_map_center:
data['force_center'] = True
self._map.update(data)
elif self._active_panel == 'actions' and self._actions:
elif self._active_panel == 'actions':
self._actions.update(data)
elif self._active_panel == 'contacts' and self._contacts:
elif self._active_panel == 'contacts':
self._contacts.update(data)
elif self._active_panel == 'messages' and self._messages:
elif self._active_panel == 'messages':
self._messages.update(
data,
self._messages.channel_filters,
@@ -767,16 +731,11 @@ class DashboardPage:
if self._room_server else None
),
)
elif self._active_panel == 'rooms' and self._room_server:
elif self._active_panel == 'rooms':
self._room_server.update(data)
elif self._active_panel == 'rxlog' and self._rxlog:
elif self._active_panel == 'rxlog':
self._rxlog.update(data)
elif self._active_panel == 'archive' and self._archive_page:
self._archive_page.refresh()
# ------------------------------------------------------------------
# Room Server callback (from ContactsPanel)
# ------------------------------------------------------------------
@@ -817,7 +776,7 @@ class DashboardPage:
# Channel-dependent drawer/submenu state may stay global.
# The helpers below already contain equality checks, so this
# remains cheap while keeping navigation consistent.
if data['channels'] and self._messages:
if data['channels']:
self._messages.update_filters(data)
self._messages.update_channel_options(data['channels'])
self._update_submenus(data)
@@ -858,14 +817,6 @@ class DashboardPage:
if data['rxlog_updated'] or is_first:
self._rxlog.update(data)
elif self._active_panel == 'archive' and self._archive_page:
if (
data.get('messages_updated')
or data.get('channels_updated')
or is_first
):
self._archive_page.refresh()
# Signal worker that GUI is ready for data
if is_first and data['channels'] and data['contacts']:
self._shared.mark_gui_initialized()
-7
View File
@@ -634,15 +634,8 @@
}
}
<<<<<<< HEAD
const hasSnapshotWork = Boolean(current.snapshot);
const hasLiveMap = maps.has(containerId);
if (!hasSnapshotWork && !hasLiveMap) {
=======
if (!current.snapshot && current.theme && !maps.has(containerId)) {
pending.set(containerId, current);
>>>>>>> b76eacf1119026c49c25d2811a6d713da8f8e01b
return;
}