feat(lite): display storage usage (#6421)

This commit is contained in:
Mathieu 2022-10-03 17:20:44 +02:00 committed by Julien Fontanet
parent 4b3728e8d8
commit 7f3d25964f
9 changed files with 146 additions and 1 deletions

View File

@ -0,0 +1,103 @@
<template>
<UiCard>
<UiTitle type="h4">{{ $t("storage-usage") }}</UiTitle>
<UsageBar :data="data.result" :nItems="5">
<template #header>
<span>{{ $t("storage") }}</span>
<span>{{ $t("top-#", { n: 5 }) }}</span>
</template>
<template #footer v-if="showFooter">
<div class="footer-card">
<p>{{ $t("total-used") }}:</p>
<div class="footer-value">
<p>{{ percentUsed }}%</p>
<p>
{{ formatSize(data.usedSize) }}
</p>
</div>
</div>
<div class="footer-card">
<p>{{ $t("total-free") }}:</p>
<div class="footer-value">
<p>{{ percentFree }}%</p>
<p>
{{ formatSize(data.maxSize) }}
</p>
</div>
</div>
</template>
</UsageBar>
</UiCard>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import UsageBar from "@/components/UsageBar.vue";
import UiCard from "@/components/ui/UiCard.vue";
import UiTitle from "@/components/ui/UiTitle.vue";
import { formatSize, percent } from "@/libs/utils";
import { useSrStore } from "@/stores/storage.store";
const srStore = useSrStore();
const percentUsed = computed(() =>
percent(data.value.usedSize, data.value.maxSize, 1)
);
const percentFree = computed(() =>
percent(data.value.maxSize - data.value.usedSize, data.value.maxSize, 1)
);
const showFooter = computed(() => !isNaN(percentUsed.value));
const data = computed<{
result: { label: string; value: number }[];
maxSize: number;
usedSize: number;
}>(() => {
const result: { label: string; value: number }[] = [];
let maxSize = 0;
let usedSize = 0;
srStore.allRecords.forEach(
({ name_label, physical_size, physical_utilisation }) => {
if (physical_size < 0 || physical_utilisation < 0) {
return;
}
maxSize += physical_size;
usedSize += physical_utilisation;
const percent = (physical_utilisation / physical_size) * 100;
if (isNaN(percent)) {
return;
}
result.push({
label: name_label,
value: percent,
});
}
);
return { result, maxSize, usedSize };
});
</script>
<style lang="postcss" scoped>
.footer-card {
color: var(--color-blue-scale-200);
display: flex;
text-transform: uppercase;
}
.footer-card p {
font-weight: 700;
}
.footer-value {
display: flex;
flex-direction: column;
text-align: right;
}
</style>

View File

@ -1,4 +1,5 @@
import { utcParse } from "d3-time-format";
import humanFormat from "human-format";
import { round } from "lodash-es";
import type { Filter } from "@/types/filter";
import { faSquareCheck } from "@fortawesome/free-regular-svg-icons";
@ -32,6 +33,12 @@ const iconsByType = {
enum: faList,
};
export function formatSize(bytes: number) {
return bytes != null
? humanFormat(bytes, { scale: "binary", unit: "B" })
: "N/D";
}
export function getFilterIcon(filter: Filter | undefined) {
if (!filter) {
return;

View File

@ -79,6 +79,12 @@ export interface XenApiHost extends XenApiRecord {
resident_VMs: string[];
}
export interface XenApiSr extends XenApiRecord {
name_label: string;
physical_size: number;
physical_utilisation: number;
}
export interface XenApiVm extends XenApiRecord {
name_label: string;
name_description: string;

View File

@ -33,9 +33,11 @@
"stats": "Stats",
"status": "Status",
"storage": "Storage",
"storage-usage": "Storage usage",
"switch-theme": "Switch theme",
"system": "System",
"tasks": "Tasks",
"top-#": "Top {n}",
"total-free": "Total free",
"total-used": "Total used",
"vms": "VMs"

View File

@ -33,9 +33,11 @@
"stats": "Stats",
"status": "Statut",
"storage": "Stockage",
"storage-usage": "Utilisation du stockage",
"switch-theme": "Changer de thème",
"system": "Système",
"tasks": "Tâches",
"top-#": "Top {n}",
"total-free": "Total libre",
"total-used": "Total utilisé",
"vms": "VMs"

View File

@ -0,0 +1,7 @@
import { defineStore } from "pinia";
import type { XenApiSr } from "@/libs/xen-api";
import { createRecordContext } from "@/stores/index";
export const useSrStore = defineStore("SR", () =>
createRecordContext<XenApiSr>("SR")
);

View File

@ -9,6 +9,7 @@ import { useHostMetricsStore } from "@/stores/host-metrics.store";
import { useHostStore } from "@/stores/host.store";
import { usePoolStore } from "@/stores/pool.store";
import { useRecordsStore } from "@/stores/records.store";
import { useSrStore } from "@/stores/storage.store";
import { useVmGuestMetricsStore } from "@/stores/vm-guest-metrics.store";
import { useVmMetricsStore } from "@/stores/vm-metrics.store";
import { useVmStore } from "@/stores/vm.store";
@ -76,11 +77,13 @@ export const useXenApiStore = defineStore("xen-api", () => {
const hostMetricsStore = useHostMetricsStore();
const vmMetricsStore = useVmMetricsStore();
const vmGuestMetricsStore = useVmGuestMetricsStore();
const srStore = useSrStore();
await Promise.all([
hostMetricsStore.init(),
vmMetricsStore.init(),
vmGuestMetricsStore.init(),
srStore.init(),
]);
const consoleStore = useConsoleStore();

View File

@ -1,3 +1,16 @@
declare module "human-format" {
function bytes(value: number): string;
type Options = {
decimals?: number;
maxDecimals?: number;
prefix?: string;
scale?: string;
separator?: string;
unit?: string;
};
function humanFormat(value: number, opts?: Options): number;
function bytes(value: number): number;
humanFormat.bytes = bytes;
export default humanFormat;
}

View File

@ -1,11 +1,13 @@
<template>
<div class="pool-dashboard-view">
<PoolDashboardStatus class="item" />
<PoolDashboardStorageUsage class="item" />
</div>
</template>
<script lang="ts" setup>
import PoolDashboardStatus from "@/components/pool/dashboard/PoolDashboardStatus.vue";
import PoolDashboardStorageUsage from "@/components/pool/dashboard/PoolDashboardStorageUsage.vue";
</script>
<style lang="postcss" scoped>