2026-01-24 22:59:20 +00:00
|
|
|
<template>
|
|
|
|
|
<div>
|
feat: cloud native file browser, settings Claude auth, deploy hardening
- Add native Cloud file browser with FileBrowser API integration
- Add cloud store, filebrowser-client, useAudioPlayer, useFileType composables
- Add Cloud components: FileGrid, FileCard, FileCardGrid, CloudToolbar
- Add Claude authentication section to Settings with OAuth status check
- Harden deploy script to preserve /aiui/ and claude-login.html
- Add nginx proxies for btcpay, homeassistant, filebrowser (HTTPS block)
- Add app configs for filebrowser, searxng, penpot in package.rs
- Update goal progress tracking with app aliases
- Improve mobile back button composable with ResizeObserver
- Update various views with cloud integration and UI refinements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:05:01 +00:00
|
|
|
<div class="hidden md:block mb-8">
|
2026-01-24 22:59:20 +00:00
|
|
|
<h1 class="text-3xl font-bold text-white mb-2">Network</h1>
|
|
|
|
|
<p class="text-white/70">Manage your network infrastructure and Web3 services</p>
|
|
|
|
|
<p class="text-sm text-white/60 mt-2">{{ connectedNodes }} connected nodes</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Quick Actions Container -->
|
|
|
|
|
<div class="glass-card p-6 mb-6">
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
2026-01-24 22:59:20 +00:00
|
|
|
<!-- Service Status -->
|
2026-02-17 20:40:26 +00:00
|
|
|
<div data-controller-container tabindex="0" class="flex flex-col gap-3 p-4 bg-white/5 rounded-lg min-w-0">
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="flex items-center gap-3 min-w-0">
|
|
|
|
|
<div class="relative shrink-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="w-3 h-3 rounded-full" :class="servicesRunning ? 'bg-green-400' : 'bg-red-400'"></div>
|
|
|
|
|
<div v-if="servicesRunning" class="absolute inset-0 w-3 h-3 rounded-full bg-green-400 animate-ping opacity-75"></div>
|
|
|
|
|
</div>
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="min-w-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<p class="text-sm font-medium text-white">Services</p>
|
|
|
|
|
<p class="text-xs text-white/60">{{ servicesRunning ? 'All Running' : 'Some Stopped' }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button
|
|
|
|
|
@click="restartServices"
|
2026-02-17 15:03:34 +00:00
|
|
|
class="w-fit px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors disabled:opacity-50"
|
2026-01-24 22:59:20 +00:00
|
|
|
:disabled="restarting"
|
|
|
|
|
>
|
|
|
|
|
{{ restarting ? 'Restarting...' : 'Restart' }}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Connectivity Status -->
|
2026-02-17 20:40:26 +00:00
|
|
|
<div data-controller-container tabindex="0" class="flex flex-col gap-3 p-4 bg-white/5 rounded-lg min-w-0">
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="flex items-center gap-3 min-w-0">
|
|
|
|
|
<div class="relative shrink-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="w-3 h-3 rounded-full" :class="connectivityStatus === 'connected' ? 'bg-green-400' : connectivityStatus === 'checking' ? 'bg-yellow-400' : 'bg-red-400'"></div>
|
|
|
|
|
<div v-if="connectivityStatus === 'connected'" class="absolute inset-0 w-3 h-3 rounded-full bg-green-400 animate-ping opacity-75"></div>
|
|
|
|
|
</div>
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="min-w-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<p class="text-sm font-medium text-white">Connectivity</p>
|
|
|
|
|
<p class="text-xs text-white/60 capitalize">{{ connectivityStatus }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button
|
|
|
|
|
@click="checkConnectivity"
|
2026-02-17 15:03:34 +00:00
|
|
|
class="w-fit px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors disabled:opacity-50"
|
2026-01-24 22:59:20 +00:00
|
|
|
:disabled="checkingConnectivity"
|
|
|
|
|
>
|
|
|
|
|
{{ checkingConnectivity ? 'Checking...' : 'Check' }}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Auto-Sync Toggle -->
|
2026-02-17 20:40:26 +00:00
|
|
|
<div data-controller-container tabindex="0" class="flex flex-col gap-3 p-4 bg-white/5 rounded-lg min-w-0">
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="flex items-center gap-3 min-w-0">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
2026-01-24 22:59:20 +00:00
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
|
|
|
|
|
</svg>
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="min-w-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<p class="text-sm font-medium text-white">Auto-Sync</p>
|
|
|
|
|
<p class="text-xs text-white/60">{{ autoSyncEnabled ? 'Enabled' : 'Disabled' }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button
|
|
|
|
|
@click="toggleAutoSync"
|
2026-02-17 15:03:34 +00:00
|
|
|
class="relative inline-flex h-6 w-11 items-center rounded-full transition-colors self-start"
|
2026-01-24 22:59:20 +00:00
|
|
|
:class="autoSyncEnabled ? 'bg-green-500' : 'bg-white/20'"
|
|
|
|
|
>
|
|
|
|
|
<span
|
|
|
|
|
class="inline-block h-4 w-4 transform rounded-full bg-white transition-transform"
|
|
|
|
|
:class="autoSyncEnabled ? 'translate-x-6' : 'translate-x-1'"
|
|
|
|
|
/>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Logs & Diagnostics -->
|
2026-02-17 20:40:26 +00:00
|
|
|
<div data-controller-container tabindex="0" class="flex flex-col gap-3 p-4 bg-white/5 rounded-lg min-w-0">
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="flex items-center gap-3 min-w-0">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
2026-01-24 22:59:20 +00:00
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
|
|
|
</svg>
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="min-w-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<p class="text-sm font-medium text-white">Logs</p>
|
|
|
|
|
<p class="text-xs text-white/60">{{ logCount > 0 ? `${logCount} new` : 'No new logs' }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button
|
|
|
|
|
@click="viewLogs"
|
2026-02-17 15:03:34 +00:00
|
|
|
class="w-fit px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors"
|
2026-01-24 22:59:20 +00:00
|
|
|
>
|
|
|
|
|
View
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Overview Cards -->
|
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
|
|
|
|
<!-- Local Network Card -->
|
2026-02-17 20:40:26 +00:00
|
|
|
<div data-controller-container tabindex="0" class="glass-card p-6 flex flex-col h-full min-h-0">
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="flex items-start gap-4 mb-4 shrink-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
|
|
|
|
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex-1">
|
|
|
|
|
<h2 class="text-xl font-semibold text-white mb-2">Local Network</h2>
|
|
|
|
|
<p class="text-white/70 text-sm mb-4">OpenWRT-integrated router and network management</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="space-y-3 flex-1 min-h-0">
|
2026-03-11 00:04:26 +00:00
|
|
|
<!-- Skeleton loading -->
|
|
|
|
|
<template v-if="networkLoading">
|
|
|
|
|
<div v-for="i in 4" :key="i" class="flex items-center justify-between p-3 bg-white/5 rounded-lg animate-pulse">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<div class="w-5 h-5 bg-white/10 rounded"></div>
|
|
|
|
|
<div class="w-24 h-4 bg-white/10 rounded"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="w-16 h-4 bg-white/10 rounded"></div>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
2026-03-11 00:04:26 +00:00
|
|
|
</template>
|
2026-01-24 22:59:20 +00:00
|
|
|
|
2026-03-11 00:04:26 +00:00
|
|
|
<template v-else>
|
|
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">Firewall Active</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="text-green-400 text-sm font-medium">Protected</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-11 00:04:26 +00:00
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">WiFi Networks</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="text-white/60 text-sm">{{ networkData.wifiCount }}</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-11 00:04:26 +00:00
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">Connectivity</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="text-sm" :class="networkData.torConnected ? 'text-green-400' : 'text-white/60'">{{ networkData.torConnected ? 'Tor Connected' : 'N/A' }}</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
2026-03-11 00:04:26 +00:00
|
|
|
|
|
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">Port Forwarding</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="text-white/60 text-sm">{{ networkData.forwardCount }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
|
2026-02-17 15:03:34 +00:00
|
|
|
<button class="mt-auto pt-4 w-full px-4 py-2 glass-button rounded-lg text-sm font-medium text-white/90 hover:text-white transition-colors shrink-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
Manage Local Network
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Web3 Card -->
|
2026-02-17 20:40:26 +00:00
|
|
|
<div data-controller-container tabindex="0" class="glass-card p-6 flex flex-col h-full min-h-0">
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="flex items-start gap-4 mb-4 shrink-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="flex-shrink-0 w-12 h-12 rounded-lg bg-white/10 flex items-center justify-center">
|
|
|
|
|
<svg class="w-6 h-6 text-white/80" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex-1">
|
|
|
|
|
<h2 class="text-xl font-semibold text-white mb-2">Web3</h2>
|
|
|
|
|
<p class="text-white/70 text-sm mb-4">Decentralized web hosting and services</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-17 15:03:34 +00:00
|
|
|
<div class="space-y-3 flex-1 min-h-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">Hosted Websites</span>
|
|
|
|
|
</div>
|
2026-03-11 00:05:12 +00:00
|
|
|
<span class="text-white/40 text-xs px-2 py-0.5 bg-white/5 rounded-full">Coming Soon</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">SSL Certificates</span>
|
|
|
|
|
</div>
|
2026-03-11 00:05:12 +00:00
|
|
|
<span class="text-white/40 text-xs px-2 py-0.5 bg-white/5 rounded-full">Coming Soon</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">IPFS Storage</span>
|
|
|
|
|
</div>
|
2026-03-11 00:05:12 +00:00
|
|
|
<span class="text-white/40 text-xs px-2 py-0.5 bg-white/5 rounded-full">Coming Soon</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="flex items-center justify-between p-3 bg-white/5 rounded-lg">
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<svg class="w-5 h-5 text-white/60" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
|
|
|
|
|
</svg>
|
|
|
|
|
<span class="text-white/80 text-sm">ENS Domains</span>
|
|
|
|
|
</div>
|
2026-03-11 00:05:12 +00:00
|
|
|
<span class="text-white/40 text-xs px-2 py-0.5 bg-white/5 rounded-full">Coming Soon</span>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-02-17 15:03:34 +00:00
|
|
|
<button class="mt-auto pt-4 w-full px-4 py-2 glass-button rounded-lg text-sm font-medium text-white/90 hover:text-white transition-colors shrink-0">
|
2026-01-24 22:59:20 +00:00
|
|
|
Manage Web3 Services
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-03-11 00:04:26 +00:00
|
|
|
import { ref, onMounted } from 'vue'
|
2026-03-04 05:23:42 +00:00
|
|
|
import { rpcClient } from '@/api/rpc-client'
|
2026-01-24 22:59:20 +00:00
|
|
|
|
|
|
|
|
// Connected nodes
|
2026-03-11 00:04:26 +00:00
|
|
|
const connectedNodes = ref(0)
|
2026-01-24 22:59:20 +00:00
|
|
|
|
|
|
|
|
// Service status
|
|
|
|
|
const servicesRunning = ref(true)
|
|
|
|
|
const restarting = ref(false)
|
|
|
|
|
|
|
|
|
|
// Connectivity status: 'connected' | 'disconnected' | 'checking'
|
|
|
|
|
const connectivityStatus = ref<'connected' | 'disconnected' | 'checking'>('connected')
|
|
|
|
|
const checkingConnectivity = ref(false)
|
|
|
|
|
|
|
|
|
|
// Auto-sync toggle
|
|
|
|
|
const autoSyncEnabled = ref(true)
|
|
|
|
|
|
|
|
|
|
// Logs
|
2026-03-11 00:04:26 +00:00
|
|
|
const logCount = ref(0)
|
|
|
|
|
|
|
|
|
|
// Network data
|
|
|
|
|
const networkLoading = ref(true)
|
|
|
|
|
const networkData = ref({
|
|
|
|
|
wifiCount: 'N/A',
|
|
|
|
|
torConnected: false,
|
|
|
|
|
forwardCount: 'N/A',
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
async function loadNetworkData() {
|
|
|
|
|
networkLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const [diagRes, fwdRes] = await Promise.allSettled([
|
|
|
|
|
rpcClient.call<{ wan_ip: string | null; nat_type: string; upnp_available: boolean; tor_connected: boolean; wifi_count?: number }>({ method: 'network.diagnostics' }),
|
|
|
|
|
rpcClient.call<{ forwards: unknown[] }>({ method: 'router.list-forwards' }),
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
if (diagRes.status === 'fulfilled') {
|
|
|
|
|
networkData.value.torConnected = diagRes.value.tor_connected
|
|
|
|
|
networkData.value.wifiCount = diagRes.value.wifi_count !== undefined
|
|
|
|
|
? `${diagRes.value.wifi_count} configured`
|
|
|
|
|
: 'N/A'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fwdRes.status === 'fulfilled') {
|
|
|
|
|
const count = fwdRes.value.forwards?.length ?? 0
|
|
|
|
|
networkData.value.forwardCount = `${count} rule${count !== 1 ? 's' : ''}`
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// Keep N/A defaults on failure
|
|
|
|
|
} finally {
|
|
|
|
|
networkLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load peer count
|
|
|
|
|
async function loadPeerCount() {
|
|
|
|
|
try {
|
|
|
|
|
const res = await rpcClient.listPeers()
|
|
|
|
|
connectedNodes.value = res.peers?.length ?? 0
|
|
|
|
|
} catch {
|
|
|
|
|
connectedNodes.value = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
loadNetworkData()
|
|
|
|
|
loadPeerCount()
|
|
|
|
|
})
|
2026-01-24 22:59:20 +00:00
|
|
|
|
2026-03-04 05:23:42 +00:00
|
|
|
async function restartServices() {
|
2026-01-24 22:59:20 +00:00
|
|
|
restarting.value = true
|
|
|
|
|
servicesRunning.value = false
|
2026-03-04 05:23:42 +00:00
|
|
|
try {
|
|
|
|
|
await rpcClient.restartServer()
|
|
|
|
|
} catch {
|
|
|
|
|
if (import.meta.env.DEV) console.warn('Restart RPC unavailable, using mock')
|
|
|
|
|
}
|
2026-01-24 22:59:20 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
|
restarting.value = false
|
|
|
|
|
servicesRunning.value = true
|
|
|
|
|
}, 2000)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 05:23:42 +00:00
|
|
|
async function checkConnectivity() {
|
2026-01-24 22:59:20 +00:00
|
|
|
checkingConnectivity.value = true
|
|
|
|
|
connectivityStatus.value = 'checking'
|
2026-03-04 05:23:42 +00:00
|
|
|
try {
|
|
|
|
|
await rpcClient.call({ method: 'server.health', params: {} })
|
2026-01-24 22:59:20 +00:00
|
|
|
connectivityStatus.value = 'connected'
|
2026-03-04 05:23:42 +00:00
|
|
|
} catch {
|
|
|
|
|
connectivityStatus.value = 'disconnected'
|
|
|
|
|
} finally {
|
|
|
|
|
checkingConnectivity.value = false
|
|
|
|
|
}
|
2026-01-24 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleAutoSync() {
|
|
|
|
|
autoSyncEnabled.value = !autoSyncEnabled.value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function viewLogs() {
|
|
|
|
|
logCount.value = 0
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|