mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-21 13:23:07 +01:00
* chore: updates modules * feat: adds support for exponential moving average * feat: add expoentital moving avg * adds index page * cleans up table * fixes typecheck * adds bar chart * updates dashboard to orgua table * wip * cleans up ui * remove screenshot tests for playwright * adds more tests * fixes icon * fixes default sort * removes unused var * adds vscode settings
156 lines
4.4 KiB
Vue
156 lines
4.4 KiB
Vue
<template>
|
|
<div class="section tile is-ancestor">
|
|
<div class="tile is-parent">
|
|
<div class="tile is-child box">
|
|
<div class="level-item has-text-centered">
|
|
<div>
|
|
<p class="title">{{ containers.length }}</p>
|
|
<p class="heading">{{ $t("label.total-containers") }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tile is-parent">
|
|
<div class="tile is-child box">
|
|
<div class="level-item has-text-centered" data-ci-skip>
|
|
<div>
|
|
<p class="title">{{ totalCpu }}%</p>
|
|
<p class="heading">{{ $t("label.total-cpu-usage") }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tile is-parent">
|
|
<div class="tile is-child box">
|
|
<div class="level-item has-text-centered" data-ci-skip>
|
|
<div>
|
|
<p class="title">{{ formatBytes(totalMem) }}</p>
|
|
<p class="heading">{{ $t("label.total-mem-usage") }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tile is-parent">
|
|
<div class="tile is-child box">
|
|
<div class="level-item has-text-centered">
|
|
<div>
|
|
<p class="title">{{ version }}</p>
|
|
<p class="heading">{{ $t("label.dozzle-version") }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<section class="section table-container">
|
|
<div class="box" data-ci-skip>
|
|
<o-table :data="runningContainers" :defaultSort="['created', 'desc']">
|
|
<o-table-column #default="{ row: container }" label="Container Name" sortable field="name">
|
|
<router-link :to="{ name: 'container-id', params: { id: container.id } }" :title="container.name">
|
|
{{ container.name }}
|
|
</router-link>
|
|
</o-table-column>
|
|
<o-table-column #default="{ row: container }" label="State" sortable field="state">
|
|
{{ container.state }}
|
|
</o-table-column>
|
|
<o-table-column #default="{ row: container }" label="Running" sortable field="created">
|
|
<distance-time :date="container.created" strict :suffix="false"></distance-time>
|
|
</o-table-column>
|
|
<o-table-column #default="{ row: container }" label="Avg. CPU" sortable field="movingAverageStat.cpu">
|
|
<bar-chart :value="container.movingAverageStat.cpu / 100" class="bar-chart">
|
|
<div class="bar-text">
|
|
{{ (container.movingAverageStat.cpu / 100).toLocaleString(undefined, { style: "percent" }) }}
|
|
</div>
|
|
</bar-chart>
|
|
</o-table-column>
|
|
<o-table-column #default="{ row: container }" label="Avg. Memory" sortable field="movingAverageStat.memory">
|
|
<bar-chart :value="container.movingAverageStat.memory / 100" class="bar-chart">
|
|
<div class="bar-text">
|
|
{{ formatBytes(container.movingAverageStat.memoryUsage) }}
|
|
</div>
|
|
</bar-chart>
|
|
</o-table-column>
|
|
</o-table>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
const { version } = config;
|
|
const containerStore = useContainerStore();
|
|
const { containers } = storeToRefs(containerStore);
|
|
|
|
const mostRecentContainers = $computed(() => [...containers.value].sort((a, b) => +b.created - +a.created));
|
|
const runningContainers = $computed(() => mostRecentContainers.filter((c) => c.state === "running"));
|
|
|
|
let totalCpu = $ref(0);
|
|
useIntervalFn(
|
|
() => {
|
|
totalCpu = runningContainers.reduce((acc, c) => acc + (c.stat?.cpu ?? 0), 0);
|
|
},
|
|
1000,
|
|
{ immediate: true },
|
|
);
|
|
|
|
let totalMem = $ref(0);
|
|
useIntervalFn(
|
|
() => {
|
|
totalMem = runningContainers.reduce((acc, c) => acc + (c.stat?.memoryUsage ?? 0), 0);
|
|
},
|
|
1000,
|
|
{ immediate: true },
|
|
);
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.panel {
|
|
border: 1px solid var(--border-color);
|
|
|
|
.panel-block,
|
|
.panel-tabs {
|
|
border-color: var(--border-color);
|
|
|
|
.is-active {
|
|
border-color: var(--border-hover-color);
|
|
}
|
|
|
|
.name {
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.status {
|
|
margin-left: auto;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
}
|
|
|
|
@media screen and (max-width: 768px) {
|
|
.pb-0-is-mobile {
|
|
padding-bottom: 0 !important;
|
|
}
|
|
|
|
.pt-0-is-mobile {
|
|
padding-top: 0 !important;
|
|
}
|
|
}
|
|
|
|
.icon {
|
|
padding: 10px 3px;
|
|
}
|
|
|
|
.bar-chart {
|
|
height: 1.5em;
|
|
.bar-text {
|
|
font-size: 0.9em;
|
|
padding: 0 0.5em;
|
|
}
|
|
}
|
|
|
|
:deep(tr td) {
|
|
padding-top: 1em;
|
|
padding-bottom: 1em;
|
|
}
|
|
</style>
|