From 2a9fb7dd5efc28d7ee3dbbb8ecc0a8c8ac89191e Mon Sep 17 00:00:00 2001 From: Joris-k Date: Tue, 26 Nov 2024 17:52:30 +0100 Subject: [PATCH] feat(xo-lite): add more info in side panel, persistent selected on table row and improve store --- .../lite/src/libs/xen-api/xen-api.types.ts | 1 + @xen-orchestra/lite/src/locales/en.json | 2 + @xen-orchestra/lite/src/locales/fr.json | 2 + .../lite/src/stores/xen-api/network.store.ts | 117 +++++-- .../lite/src/views/pool/PoolNetworkView.vue | 292 +++++++++++------- 5 files changed, 281 insertions(+), 133 deletions(-) diff --git a/@xen-orchestra/lite/src/libs/xen-api/xen-api.types.ts b/@xen-orchestra/lite/src/libs/xen-api/xen-api.types.ts index e81ad207d10..f5e4026f581 100644 --- a/@xen-orchestra/lite/src/libs/xen-api/xen-api.types.ts +++ b/@xen-orchestra/lite/src/libs/xen-api/xen-api.types.ts @@ -58,6 +58,7 @@ type ObjectTypeToRecordMapping = { host_metrics: XenApiHostMetrics message: XenApiMessage network: XenApiNetwork + pif: XenApiPif pool: XenApiPool sr: XenApiSr vm: XenApiVm diff --git a/@xen-orchestra/lite/src/locales/en.json b/@xen-orchestra/lite/src/locales/en.json index 77c77b30fd1..82622d1b90e 100644 --- a/@xen-orchestra/lite/src/locales/en.json +++ b/@xen-orchestra/lite/src/locales/en.json @@ -147,6 +147,8 @@ "no-tasks": "No tasks", "not-found": "Not found", "object": "Object", + "off": "Off", + "on": "On", "ok": "OK", "on-object": "on {object}", "or": "Or", diff --git a/@xen-orchestra/lite/src/locales/fr.json b/@xen-orchestra/lite/src/locales/fr.json index f9447d25773..8c40c38eb40 100644 --- a/@xen-orchestra/lite/src/locales/fr.json +++ b/@xen-orchestra/lite/src/locales/fr.json @@ -147,6 +147,8 @@ "no-tasks": "Aucune tâche", "not-found": "Non trouvé", "object": "Objet", + "off": "Eteint", + "on": "Allumé", "ok": "OK", "on-object": "sur {object}", "or": "Ou", diff --git a/@xen-orchestra/lite/src/stores/xen-api/network.store.ts b/@xen-orchestra/lite/src/stores/xen-api/network.store.ts index 96c1670dd9d..1c000dca099 100644 --- a/@xen-orchestra/lite/src/stores/xen-api/network.store.ts +++ b/@xen-orchestra/lite/src/stores/xen-api/network.store.ts @@ -1,5 +1,6 @@ import type { XenApiNetwork, XenApiPif } from '@/libs/xen-api/xen-api.types' import { createXapiStoreConfig } from '@/stores/xen-api/create-xapi-store-config' +import { useHostMetricsStore } from '@/stores/xen-api/host-metrics.store' import { useHostStore } from '@/stores/xen-api/host.store' import { usePifStore } from '@/stores/xen-api/pif.store' import { usePoolStore } from '@/stores/xen-api/pool.store' @@ -13,6 +14,7 @@ export const useNetworkStore = defineStore('xen-api-network', () => { poolStore: usePoolStore(), hostStore: useHostStore(), pifStore: usePifStore(), + metricsStore: useHostMetricsStore(), } const { context: baseContext, ...configRest } = createXapiStoreConfig('network', { @@ -22,66 +24,131 @@ export const useNetworkStore = defineStore('xen-api-network', () => { const poolContext = deps.poolStore.getContext() const hostContext = deps.hostStore.getContext() const pifContext = deps.pifStore.getContext() + const metricsContext = deps.metricsStore.getContext() const PIFsByNetwork = computed(() => { const PIFsByNetworkMap = new Map() - poolContext.records.value.forEach(pool => { - const masterPoolRef = pool.master - const currentHostRef = hostContext.records.value.find(host => host.$ref === masterPoolRef) - if (currentHostRef) { - pifContext.records.value - .filter(pif => pif.host === masterPoolRef) - .forEach(pif => { - if (!PIFsByNetworkMap.has(pif.network)) { - PIFsByNetworkMap.set(pif.network, []) - } - PIFsByNetworkMap.get(pif.network)?.push(pif) - }) - } - }) + const poolMasterRef = poolContext.pool.value?.master + + const currentHostRef = hostContext.records.value.find(host => host.$ref === poolMasterRef) + if (currentHostRef) { + pifContext.records.value + .filter(pif => pif.host === poolMasterRef) + .forEach(pif => { + if (!PIFsByNetworkMap.has(pif.network)) { + PIFsByNetworkMap.set(pif.network, []) + } + PIFsByNetworkMap.get(pif.network)?.push(pif) + }) + } + return PIFsByNetworkMap }) const determineStatus = (PIFs: XenApiPif[]): string => { + if (PIFs.length === 0) { + return 'disconnected' + } const currentlyAttached = PIFs.map(PIF => PIF.currently_attached) - if (currentlyAttached.every(attached => attached)) { + + if (currentlyAttached.every(Boolean)) { return 'connected' - } else if (currentlyAttached.some(attached => attached)) { + } + + if (currentlyAttached.some(Boolean)) { return 'partially connected' } + return 'disconnected' } const networksWithVLANs = computed(() => { + const networksInfoMap = new Map< + string, + { network: XenApiNetwork; vlan: string; status: string; selected: boolean } + >() + return baseContext.records.value .filter(network => network.PIFs.length > 0) .map(network => { const relatedPifs = PIFsByNetwork.value.get(network.$ref) || [] - const vlan = relatedPifs.length > 0 ? (relatedPifs[0].VLAN === -1 ? 'None' : relatedPifs[0].VLAN) : '' + + const vlan = + relatedPifs.length > 0 ? (relatedPifs[0].VLAN === -1 ? 'None' : relatedPifs[0].VLAN.toString()) : '' + const status = determineStatus(relatedPifs) - return { - ...network, + const networkWithDetails = { + network, selected: false, vlan, status, } + if (!networksInfoMap.has(network.$ref)) { + networksInfoMap.set(network.$ref, networkWithDetails) + } + networksInfoMap.set(network.$ref, networkWithDetails) + + return networkWithDetails }) }) const hostPrivateNetworks = computed(() => { + const hostPrivateNetworksInfoMap = new Map() + return baseContext.records.value .filter(network => network.PIFs.length === 0) // Only networks without PIFs - .map(network => ({ - ...network, - selected: false, - })) + .map(network => { + const hostPrivateNetworkWithDetails = { + network, + selected: false, + } + + if (!hostPrivateNetworksInfoMap.has(network.$ref)) { + hostPrivateNetworksInfoMap.set(network.$ref, hostPrivateNetworkWithDetails) + } + hostPrivateNetworksInfoMap.set(network.$ref, hostPrivateNetworkWithDetails) + + return hostPrivateNetworkWithDetails + }) + }) + + const PIFsInfoByNetwork = computed(() => { + const PIFsInfoMap = new Map< + string, + { + PIF: XenApiPif + host?: { + name_label?: string + status?: boolean + } + }[] + >() + + pifContext.records.value.forEach(PIF => { + const hostInfo = hostContext.getByOpaqueRef(PIF.host) + const hostStatus = hostInfo?.metrics ? metricsContext.getByOpaqueRef(hostInfo.metrics)?.live || false : false + + const enrichedPIF = { + PIF, + host: { + name_label: hostInfo?.name_label, + hostStatus, + }, + } + + if (!PIFsInfoMap.has(PIF.network)) { + PIFsInfoMap.set(PIF.network, []) + } + PIFsInfoMap.get(PIF.network)?.push(enrichedPIF) + }) + + return PIFsInfoMap }) const getPIFsInformationByNetwork = (network: XenApiNetwork) => { - const PIFsOpaqueRefNetwork = network.PIFs - return PIFsOpaqueRefNetwork.map(ref => pifContext.records.value.find(pif => pif.$ref === ref)).filter(pif => !!pif) + return PIFsInfoByNetwork.value.get(network?.$ref) || [] } const context = { diff --git a/@xen-orchestra/lite/src/views/pool/PoolNetworkView.vue b/@xen-orchestra/lite/src/views/pool/PoolNetworkView.vue index 2d87cdea8c0..b1f768ef55f 100644 --- a/@xen-orchestra/lite/src/views/pool/PoolNetworkView.vue +++ b/@xen-orchestra/lite/src/views/pool/PoolNetworkView.vue @@ -2,6 +2,7 @@