| 1 |
<template> |
| 2 |
<div class="network-status"> |
| 3 |
<div class="flex items-center space-x-2"> |
| 4 |
<!-- Status indicator --> |
| 5 |
<div |
| 6 |
class="w-2 h-2 rounded-full" |
| 7 |
:class="{ |
| 8 |
'bg-green-500': status === 'online', |
| 9 |
'bg-yellow-500': status === 'degraded', |
| 10 |
'bg-red-500': status === 'offline', |
| 11 |
'bg-gray-400': status === 'unknown' |
| 12 |
}" |
| 13 |
></div> |
| 14 |
|
| 15 |
<!-- Status text --> |
| 16 |
<span class="text-xs text-gray-600 dark:text-gray-400 capitalize"> |
| 17 |
{{ status }} |
| 18 |
</span> |
| 19 |
</div> |
| 20 |
|
| 21 |
<!-- Details --> |
| 22 |
<div v-if="networkData" class="mt-2 text-xs text-gray-500 dark:text-gray-400 space-y-1"> |
| 23 |
<div class="flex justify-between"> |
| 24 |
<span>Nodes:</span> |
| 25 |
<span>{{ networkData.nodes.length }}</span> |
| 26 |
</div> |
| 27 |
<div class="flex justify-between"> |
| 28 |
<span>Storage:</span> |
| 29 |
<span>{{ formatBytes(networkData.usedStorage) }} / {{ formatBytes(networkData.totalStorage) }}</span> |
| 30 |
</div> |
| 31 |
<div class="flex justify-between"> |
| 32 |
<span>Health:</span> |
| 33 |
<span>{{ Math.round(networkData.healthScore * 100) }}%</span> |
| 34 |
</div> |
| 35 |
</div> |
| 36 |
</div> |
| 37 |
</template> |
| 38 |
|
| 39 |
<script setup lang="ts"> |
| 40 |
import { ref, onMounted, onUnmounted } from 'vue' |
| 41 |
import { apiClient } from '@/services/api' |
| 42 |
import type { NetworkStatus } from '@shared/types' |
| 43 |
|
| 44 |
const status = ref<'online' | 'degraded' | 'offline' | 'unknown'>('unknown') |
| 45 |
const networkData = ref<NetworkStatus | null>(null) |
| 46 |
|
| 47 |
let ws: WebSocket | null = null |
| 48 |
let reconnectTimeout: NodeJS.Timeout | null = null |
| 49 |
|
| 50 |
function formatBytes(bytes: number): string { |
| 51 |
if (bytes === 0) return '0 B' |
| 52 |
const k = 1024 |
| 53 |
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] |
| 54 |
const i = Math.floor(Math.log(bytes) / Math.log(k)) |
| 55 |
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i] |
| 56 |
} |
| 57 |
|
| 58 |
function connectWebSocket() { |
| 59 |
try { |
| 60 |
ws = apiClient.createStatusWebSocket() |
| 61 |
|
| 62 |
ws.onopen = () => { |
| 63 |
status.value = 'online' |
| 64 |
if (reconnectTimeout) { |
| 65 |
clearTimeout(reconnectTimeout) |
| 66 |
reconnectTimeout = null |
| 67 |
} |
| 68 |
} |
| 69 |
|
| 70 |
ws.onmessage = (event) => { |
| 71 |
try { |
| 72 |
const data = JSON.parse(event.data) |
| 73 |
|
| 74 |
if (data.type === 'status_update') { |
| 75 |
networkData.value = data.data.network |
| 76 |
|
| 77 |
// Determine overall status |
| 78 |
if (networkData.value.healthScore > 0.8) { |
| 79 |
status.value = 'online' |
| 80 |
} else if (networkData.value.healthScore > 0.5) { |
| 81 |
status.value = 'degraded' |
| 82 |
} else { |
| 83 |
status.value = 'offline' |
| 84 |
} |
| 85 |
} |
| 86 |
} catch (error) { |
| 87 |
console.error('Failed to parse WebSocket message:', error) |
| 88 |
} |
| 89 |
} |
| 90 |
|
| 91 |
ws.onclose = () => { |
| 92 |
status.value = 'offline' |
| 93 |
// Attempt to reconnect after 5 seconds |
| 94 |
reconnectTimeout = setTimeout(() => { |
| 95 |
connectWebSocket() |
| 96 |
}, 5000) |
| 97 |
} |
| 98 |
|
| 99 |
ws.onerror = () => { |
| 100 |
status.value = 'offline' |
| 101 |
} |
| 102 |
} catch (error) { |
| 103 |
console.error('Failed to connect WebSocket:', error) |
| 104 |
status.value = 'offline' |
| 105 |
|
| 106 |
// Retry connection |
| 107 |
reconnectTimeout = setTimeout(() => { |
| 108 |
connectWebSocket() |
| 109 |
}, 5000) |
| 110 |
} |
| 111 |
} |
| 112 |
|
| 113 |
async function loadInitialStatus() { |
| 114 |
try { |
| 115 |
networkData.value = await apiClient.getNetworkStatus() |
| 116 |
status.value = 'online' |
| 117 |
} catch (error) { |
| 118 |
console.error('Failed to load network status:', error) |
| 119 |
status.value = 'offline' |
| 120 |
} |
| 121 |
} |
| 122 |
|
| 123 |
onMounted(() => { |
| 124 |
loadInitialStatus() |
| 125 |
connectWebSocket() |
| 126 |
}) |
| 127 |
|
| 128 |
onUnmounted(() => { |
| 129 |
if (ws) { |
| 130 |
ws.close() |
| 131 |
} |
| 132 |
if (reconnectTimeout) { |
| 133 |
clearTimeout(reconnectTimeout) |
| 134 |
} |
| 135 |
}) |
| 136 |
</script> |