isConfigured only checked integration.secrets for a MASKED value, so any
integration with zero secretFields (hotel_location: lat/lon only, no
secrets) could never show "Configured" even with valid values saved —
same edge case hosted_tables already needed a special-case for. Add the
matching special-case for hotel_location. Also add proper FIELD_LABELS
entries for latitude/longitude instead of showing the raw field name.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Matches settings' new multi-topic-per-client support: the create form's
Topic scope field is now a textarea (one pattern per line), the list shows
all of a client's scopes, and a '+ Topic' button lets an admin grant an
existing client more topic access without recreating it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surfaces settings' new service-client flag in the MQTT Broker Clients tab —
a checkbox that stores the password encrypted so a stack app (e.g.
hvac-backend) can fetch its own login at runtime, plus a 'service' badge in
the client list. Device logins are unchanged (leave the box off).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the flat scrolling capture log with a structured message buffer
(mqttMessages) rendered two ways: a collapsible topic tree showing each
topic's latest value (MQTT-Explorer-ish), and a chronological feed. An
"Auto-refresh" toggle repeats the existing 8s /deploy/exec capture every
~9s and merges results in, rather than requiring a manual click each time.
Still not a genuine live stream (no WebSocket listener on the broker) —
just polling dressed up to feel closer to one, without touching the
broker or NPM config.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
AdminMonitor: new "MQTT" tab reuses the existing Shell tab's /deploy/exec
mechanism to run a bounded (8s) mosquitto_sub capture against the broker
LXC via a read-only "mqtt-inspector" identity — a one-shot capture, not a
live stream, since /deploy/exec is request/response. Retained messages
(most device telemetry) show immediately regardless.
AdminSettings: new "MQTT Clients" tab — create/list/revoke broker
identities via the new settings API, matching forecasting's API Keys
show-once-password UX. Removes the need to hand-run mosquitto_ctrl for
every new device or app that needs broker access.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dashboard now shows today's and upcoming events (mine or all, toggle) for
users with calendar app access. Also gives the portal shell a 1-hour
inactivity default for devices that have never been configured, instead of
following child apps into an unlimited 30-day session — that's why the
dashboard could sit logged in for days without prompting. An explicit "Off"
choice in Admin Settings still overrides it (now written as mins=0 instead
of clearing the cookie, so it's distinguishable from "never configured").
Login.tsx only read the return path from router state, which a hard
cross-document navigation (a child app bouncing the whole shell here
on session expiry) can never carry — so re-authenticating always
landed on the Dashboard instead of back in whatever app you were
using. Login.tsx now also accepts a ?from= query param for that case.
Also wired up AuthGate's inactivity auto-logout timer, which was
defined (getInactivityMs) but never actually called — so the
per-device timeout configurable in Admin Settings had no effect.
Disabled for installed PWAs as intended.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Admin clicks 'Auth secret', re-enters their password, and sees CENTRAL_AUTH_SECRET
with a copy button. Secret auto-clears after 60 seconds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On every iframe load, mirror its current path to the portal URL hash
(e.g. /app/cashup#/reports). On mount, initialSrc reads that hash and
restores the correct page after a refresh. Hash is cleared when
switching apps so it doesn't bleed across slugs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Displays a gold badge next to the latest commit hash when the backend
returns a commitsBehind count greater than zero.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Backup Directory field in the Nextcloud integration card gains a
Browse button that opens an inline panel with: breadcrumb navigation,
scrollable directory list, and a Select button to pick the current path.
Falls back to manual text entry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backups tab shows last-run status, expandable run history with per-item
breakdown (db/vol, size, status), and a Run Now trigger button.
Settings Nextcloud card gains a Backup Directory field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When an app is open, the sidebar collapses to a 44px strip with a
chevron button. Clicking it opens the full sidebar as a fixed overlay
with a backdrop that closes on click. Also closes automatically when
the user interacts with / navigates within the iframe (window blur).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire /admin/settings route and sidebar link; proxy /settings/api/ to the
new settings service at 10.10.10.116. Admin can configure integration
credentials and manage Newbook room ordering from the portal.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sidebar now renders uncategorised apps flat and categorised apps in
collapsible accordion sections; active category stays expanded. Dashboard
groups tiles under category section headings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- index.css: light body (#f4f5f7), white cards, sidebar stays dark navy
- AppIcon.tsx: Lucide icon lookup component for app tiles and nav
- Sidebar.tsx: Lucide nav icons (LayoutGrid, Users, Activity, LogOut)
- Dashboard.tsx: white cards with shadows, coloured Lucide app icons
- AdminMonitor.tsx: light theme throughout, Lucide tab icons,
better status colours for light backgrounds
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defaults to 'Number Four at Stow'. Replaces hardcoded 'Hotel Number Four'
and 'HNF Manage' in sidebar, login page, and browser title. Other hotels
set VITE_HOTEL_NAME in their /opt/portal/.env before rebuilding.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Uptime tab now polls /deploy/health-status (parallel HTTP checks) and
shows a status grid with response times. Removes broken Kuma sub-path
nginx locations. Auto-refreshes every 30s.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>