Files
ipwatch/frontend/src/components/IPGrid.vue
2026-02-07 16:57:37 +01:00

156 lines
5.2 KiB
Vue
Executable File

<template>
<div class="flex flex-col h-full">
<!-- Grille d'IPs par sous-réseaux -->
<div class="flex-1 overflow-auto p-4">
<!-- Pour chaque sous-réseau -->
<div v-for="subnet in groupedSubnets" :key="subnet.name" class="mb-6">
<!-- En-tête de section -->
<div class="mb-3 pb-2 border-b-2 border-monokai-cyan/30">
<p class="text-xs text-monokai-comment">{{ subnet.name }}</p>
<h3 v-if="subnet.start && subnet.end" class="text-lg font-bold text-monokai-cyan mt-0.5">
{{ subnet.start }} à {{ subnet.end }}
</h3>
</div>
<!-- Grille des IPs de ce sous-réseau -->
<div class="grid grid-cols-4 gap-3">
<IPCell
v-for="ip in subnet.ips"
:key="ip.ip"
:ip="ip"
/>
</div>
</div>
<!-- Message si vide -->
<div v-if="groupedSubnets.length === 0" class="text-center text-monokai-comment mt-10">
<p>Aucune IP à afficher</p>
<p class="text-sm mt-2">Ajustez les filtres ou lancez un scan</p>
</div>
</div>
<!-- Légende -->
<div class="bg-monokai-bg border-t border-monokai-comment p-3">
<div class="flex gap-6 text-xs">
<div class="flex items-center gap-2">
<div class="w-4 h-4 rounded border-2 border-monokai-green bg-monokai-green/15"></div>
<span class="text-monokai-text">En ligne (connue)</span>
</div>
<div class="flex items-center gap-2">
<div class="w-4 h-4 rounded border-2 border-monokai-cyan bg-monokai-cyan/15"></div>
<span class="text-monokai-text">En ligne (inconnue)</span>
</div>
<div class="flex items-center gap-2">
<div class="w-4 h-4 rounded border-2 border-dashed border-monokai-pink bg-monokai-pink/10 opacity-50"></div>
<span class="text-monokai-text">Hors ligne (connue)</span>
</div>
<div class="flex items-center gap-2">
<div class="w-4 h-4 rounded border-2 border-dashed border-monokai-purple bg-monokai-purple/10 opacity-50"></div>
<span class="text-monokai-text">Hors ligne (inconnue)</span>
</div>
<div class="flex items-center gap-2">
<div class="w-4 h-4 rounded border-2 border-monokai-comment bg-monokai-comment/20"></div>
<span class="text-monokai-text">Libre</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useIPStore } from '@/stores/ipStore'
import IPCell from './IPCell.vue'
const ipStore = useIPStore()
const { filteredIPs } = storeToRefs(ipStore)
// Subnets depuis la config
const subnets = ref([])
// Charger les subnets depuis la config
onMounted(async () => {
try {
const response = await fetch('/api/ips/config/content')
if (response.ok) {
const data = await response.json()
// Parser le YAML pour extraire les subnets
const yamlContent = data.content
const subnetMatches = yamlContent.match(/subnets:[\s\S]*?(?=\n\w+:|\n$)/)?.[0]
if (subnetMatches) {
// Simple parsing des subnets (améliorer si nécessaire)
const subnetLines = subnetMatches.split('\n')
let currentSubnet = null
subnetLines.forEach(line => {
if (line.includes('- name:')) {
if (currentSubnet) subnets.value.push(currentSubnet)
currentSubnet = { name: line.split('"')[1] }
} else if (currentSubnet) {
if (line.includes('start:')) currentSubnet.start = line.split('"')[1]
if (line.includes('end:')) currentSubnet.end = line.split('"')[1]
if (line.includes('cidr:')) currentSubnet.cidr = line.split('"')[1]
}
})
if (currentSubnet) subnets.value.push(currentSubnet)
console.log('=== SUBNETS LOADED V2 ===', Date.now(), subnets.value)
}
}
} catch (error) {
console.error('Erreur chargement subnets:', error)
}
})
// Fonction pour vérifier si une IP appartient à un subnet
function ipInSubnet(ip, start, end) {
const ipNum = ipToNumber(ip)
const startNum = ipToNumber(start)
const endNum = ipToNumber(end)
return ipNum >= startNum && ipNum <= endNum
}
// Convertir une IP en nombre
function ipToNumber(ip) {
return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet), 0) >>> 0
}
// Grouper les IPs par subnet
const groupedSubnets = computed(() => {
const groups = []
// Pour chaque subnet défini
subnets.value.forEach(subnet => {
const subnetIPs = filteredIPs.value.filter(ip =>
ipInSubnet(ip.ip, subnet.start, subnet.end)
)
if (subnetIPs.length > 0) {
groups.push({
name: subnet.name,
start: subnet.start,
end: subnet.end,
ips: subnetIPs.sort((a, b) => ipToNumber(a.ip) - ipToNumber(b.ip))
})
}
})
// Ajouter section "Autres" pour les IPs hors subnets
const otherIPs = filteredIPs.value.filter(ip => {
return !subnets.value.some(subnet => ipInSubnet(ip.ip, subnet.start, subnet.end))
})
if (otherIPs.length > 0) {
groups.push({
name: 'Autres',
start: '',
end: '',
ips: otherIPs.sort((a, b) => ipToNumber(a.ip) - ipToNumber(b.ip))
})
}
return groups
})
</script>