feat(home): surface TollGate status on the Network tile

Add a TollGate row (Enabled/Disabled/Not installed) to the Home
dashboard's Network tile, polling the existing openwrt.get-status RPC
on the same cadence as the other network rows. Only rendered once an
OpenWrt router is actually configured, so nodes without one aren't
cluttered with an always-"Not configured" row.

Also fixes the underlying reason this could never have worked: nothing
in the OpenWrt Gateway flow ever persisted the router's host/credentials
server-side — the "connect" form only kept them in local component
state, so any no-args openwrt.get-status call (this new tile, and even
the Gateway page's own reload) always failed with "No router
configured" despite a fully working, provisioned router. Now
handle_openwrt_get_status saves the connection to router_config.json
whenever a host is explicitly passed in and the connection succeeds.
This commit is contained in:
2026-07-01 13:25:43 +00:00
parent d6c1feca97
commit e497f8fed1
3 changed files with 71 additions and 0 deletions
+34
View File
@@ -49,10 +49,12 @@ export const useHomeStatusStore = defineStore('homeStatus', () => {
const bitcoinStale = ref(false)
const vpnLoadState = ref<LoadState>('idle')
const fipsLoadState = ref<LoadState>('idle')
const tollgateLoadState = ref<LoadState>('idle')
const lastSystemRefreshAt = ref<number | null>(null)
const lastBitcoinRefreshAt = ref<number | null>(null)
const lastVpnRefreshAt = ref<number | null>(null)
const lastFipsRefreshAt = ref<number | null>(null)
const lastTollgateRefreshAt = ref<number | null>(null)
const vpnStatus = ref<{
connected: boolean | null
@@ -67,6 +69,9 @@ export const useHomeStatusStore = defineStore('homeStatus', () => {
authenticated_peer_count?: number
} | null>(null)
// null = no OpenWrt router configured at all (tile row shows "Not configured").
const tollgateStatus = ref<{ installed: boolean; enabled: boolean } | null>(null)
const systemStatsLoaded = computed(() => systemLoadState.value === 'ready')
const bitcoinKnown = computed(() => stats.bitcoinAvailable !== null)
const vpnKnown = computed(() => vpnStatus.value.connected !== null)
@@ -185,12 +190,37 @@ export const useHomeStatusStore = defineStore('homeStatus', () => {
}
}
async function refreshTollgate() {
tollgateLoadState.value = tollgateLoadState.value === 'ready' ? 'ready' : 'loading'
try {
const res = await rpcClient.call<{ tollgate: { installed: boolean; enabled?: boolean } }>({
method: 'openwrt.get-status',
timeout: 15000,
})
tollgateStatus.value = { installed: res.tollgate.installed, enabled: res.tollgate.enabled ?? false }
tollgateLoadState.value = 'ready'
lastTollgateRefreshAt.value = Date.now()
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
if (msg.includes('No router configured')) {
// Not an error — most nodes simply don't have an OpenWrt gateway set up.
tollgateStatus.value = null
tollgateLoadState.value = 'ready'
lastTollgateRefreshAt.value = Date.now()
} else {
// Transient failure (SSH hiccup, router rebooting) — keep last-known state.
tollgateLoadState.value = tollgateStatus.value ? 'ready' : 'error'
}
}
}
async function refresh(packages: Record<string, PackageDataEntry>) {
await Promise.all([
refreshSystemStats(),
refreshBitcoin(packages),
refreshVpn(packages),
refreshFips(),
refreshTollgate(),
])
}
@@ -201,19 +231,23 @@ export const useHomeStatusStore = defineStore('homeStatus', () => {
bitcoinStale,
vpnLoadState,
fipsLoadState,
tollgateLoadState,
systemStatsLoaded,
bitcoinKnown,
vpnKnown,
vpnStatus,
fipsStatus,
tollgateStatus,
lastSystemRefreshAt,
lastBitcoinRefreshAt,
lastVpnRefreshAt,
lastFipsRefreshAt,
lastTollgateRefreshAt,
refresh,
refreshSystemStats,
refreshBitcoin,
refreshVpn,
refreshFips,
refreshTollgate,
}
})