feat(client): 新しいサーバーメトリクスウィジェットの追加
This commit is contained in:
parent
14bcbd5017
commit
d9e9899dbb
7
packages/frontend/src/filters/bytes-net-sizes.ts
Normal file
7
packages/frontend/src/filters/bytes-net-sizes.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export default (v) => {
|
||||
if (v == null) return '?';
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (v === 0) return sizes[0];
|
||||
const i = Math.floor(Math.log(v) / Math.log(1024));
|
||||
return sizes[i];
|
||||
};
|
8
packages/frontend/src/filters/bytes-net-v.ts
Normal file
8
packages/frontend/src/filters/bytes-net-v.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export default (v, digits = 0) => {
|
||||
if (v == null) return '?';
|
||||
if (v === 0) return '0';
|
||||
const isMinus = v < 0;
|
||||
if (isMinus) v = -v;
|
||||
const i = Math.floor(Math.log(v) / Math.log(1024));
|
||||
return (isMinus ? '-' : '') + (v / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '');
|
||||
};
|
105
packages/frontend/src/widgets/server-metric/cpu-mem-net-pie.vue
Normal file
105
packages/frontend/src/widgets/server-metric/cpu-mem-net-pie.vue
Normal file
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<div :class="$style.root">
|
||||
<div :class="$style.div">
|
||||
<XPie :class="$style.pie" :value="cpuUsage"/>
|
||||
<div :class="$style.div2">
|
||||
<p>CPU</p>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text">{{ (cpuUsage * 100).toFixed(1) }}<span style="font-weight: normal; font-size: .75em; margin-left: 2px;">%</span></text>
|
||||
</div>
|
||||
<XPie :class="$style.pie" :value="memUsage"/>
|
||||
<div :class="$style.div2">
|
||||
<p>RAM</p>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text">{{ (memUsage * 100).toFixed(1) }}<span style="font-weight: normal; font-size: .75em; margin-left: 2px;">%</span></text>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="$style.divider"></div>
|
||||
<div :class="$style.div">
|
||||
<!-- 基準が10MBなので、基準を超えるとグラフが壊れる問題がある -->
|
||||
<XPie :class="$style.pie" :value="inRecent / 10000000"/>
|
||||
<div :class="$style.div2">
|
||||
<p>NET rx</p>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text"><tspan>{{ bytes(inRecent, 1) }}<span style="font-weight: normal; font-size: .75em; margin-left: 2px;">{{ bytesSizes(inRecent) }}</span></tspan></text>
|
||||
</div>
|
||||
<!-- 基準が10MBなので、基準を超えるとグラフが壊れる問題がある -->
|
||||
<XPie :class="$style.pie" :value="outRecent / 10000000"/>
|
||||
<div :class="$style.div2">
|
||||
<p>NET tx</p>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text"><tspan>{{ bytes(outRecent, 1) }}<span style="font-weight: normal; font-size: .75em; margin-left: 2px;">{{ bytesSizes(outRecent) }}</span></tspan></text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onBeforeUnmount } from 'vue';
|
||||
import XPie from './pie-compact.vue';
|
||||
import bytes from '@/filters/bytes-net-v';
|
||||
import bytesSizes from '@/filters/bytes-net-sizes';
|
||||
|
||||
const props = defineProps<{
|
||||
connection: any,
|
||||
meta: any,
|
||||
value: number
|
||||
}>();
|
||||
|
||||
let cpuUsage: number = $ref(0);
|
||||
let memUsage: number = $ref(0);
|
||||
let inRecent: number = $ref(0);
|
||||
let outRecent: number = $ref(0);
|
||||
|
||||
function onStats(stats) {
|
||||
cpuUsage = stats.cpu;
|
||||
memUsage = stats.mem.active / props.meta.mem.total;
|
||||
}
|
||||
|
||||
function onConnStats(connStats) {
|
||||
inRecent = connStats.net.rx;
|
||||
outRecent = connStats.net.tx;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
props.connection.on('stats', onStats);
|
||||
props.connection.on('stats', onConnStats);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
props.connection.off('stats', onStats);
|
||||
props.connection.off('stats', onConnStats);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
padding: 16px 32px;
|
||||
}
|
||||
|
||||
.div {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.pie {
|
||||
height: 42px;
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.div2 {
|
||||
flex: 1;
|
||||
margin: auto;
|
||||
|
||||
> p {
|
||||
margin: 0 0 2px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 16px 72px;
|
||||
border-top: solid 0.5px var(--divider);
|
||||
}
|
||||
|
||||
.text {
|
||||
font-weight: bold;
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
|
@ -7,10 +7,12 @@
|
|||
<div v-if="meta" data-cy-mkw-serverMetric class="mkw-serverMetric">
|
||||
<XCpuMemory v-if="widgetProps.view === 0" :connection="connection" :meta="meta"/>
|
||||
<XNet v-else-if="widgetProps.view === 1" :connection="connection" :meta="meta"/>
|
||||
<XCpuMemoryCompact v-if="widgetProps.view === 2" :connection="connection" :meta="meta"/>
|
||||
<XCpu v-else-if="widgetProps.view === 3" :connection="connection" :meta="meta"/>
|
||||
<XMemory v-else-if="widgetProps.view === 4" :connection="connection" :meta="meta"/>
|
||||
<XDisk v-else-if="widgetProps.view === 5" :connection="connection" :meta="meta"/>
|
||||
<XCpuMemoryNetCompact v-if="widgetProps.view === 2" :connection="connection" :meta="meta"/>
|
||||
<XCpuMemoryCompact v-if="widgetProps.view === 3" :connection="connection" :meta="meta"/>
|
||||
<XNetCompact v-if="widgetProps.view === 4" :connection="connection" :meta="meta"/>
|
||||
<XCpu v-else-if="widgetProps.view === 5" :connection="connection" :meta="meta"/>
|
||||
<XMemory v-else-if="widgetProps.view === 6" :connection="connection" :meta="meta"/>
|
||||
<XDisk v-else-if="widgetProps.view === 7" :connection="connection" :meta="meta"/>
|
||||
</div>
|
||||
</MkContainer>
|
||||
</template>
|
||||
|
@ -21,6 +23,8 @@ import { useWidgetPropsManager, Widget, WidgetComponentExpose } from '../widget'
|
|||
import XCpuMemory from './cpu-mem.vue';
|
||||
import XCpuMemoryCompact from './cpu-mem-pie.vue';
|
||||
import XNet from './net.vue';
|
||||
import XNetCompact from './net-pie.vue';
|
||||
import XCpuMemoryNetCompact from './cpu-mem-net-pie.vue';
|
||||
import XCpu from './cpu.vue';
|
||||
import XMemory from './mem.vue';
|
||||
import XDisk from './disk.vue';
|
||||
|
@ -69,7 +73,7 @@ os.api('server-info', {}).then(res => {
|
|||
});
|
||||
|
||||
const toggleView = () => {
|
||||
if (widgetProps.view === 5) {
|
||||
if (widgetProps.view === 7) {
|
||||
widgetProps.view = 0;
|
||||
} else {
|
||||
widgetProps.view++;
|
||||
|
|
73
packages/frontend/src/widgets/server-metric/net-pie.vue
Normal file
73
packages/frontend/src/widgets/server-metric/net-pie.vue
Normal file
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<div :class="$style.root">
|
||||
<!-- 基準が10MBなので、基準を超えるとグラフが壊れる問題がある -->
|
||||
<XPie :class="$style.pie" :value="inRecent / 10000000"/>
|
||||
<div :class="$style.div">
|
||||
<p>NET rx</p>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text"><tspan>{{ bytes(inRecent, 1) }}<span style="font-weight: normal; font-size: .75em; margin-left: 2px;">{{ bytesSizes(inRecent) }}</span></tspan></text>
|
||||
</div>
|
||||
<!-- 基準が10MBなので、基準を超えるとグラフが壊れる問題がある -->
|
||||
<XPie :class="$style.pie" :value="outRecent / 10000000"/>
|
||||
<div :class="$style.div">
|
||||
<p>NET tx</p>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text"><tspan>{{ bytes(outRecent, 1) }}<span style="font-weight: normal; font-size: .75em; margin-left: 2px;">{{ bytesSizes(outRecent) }}</span></tspan></text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onBeforeUnmount } from 'vue';
|
||||
import XPie from './pie-compact.vue';
|
||||
import bytes from '@/filters/bytes-net-v';
|
||||
import bytesSizes from '@/filters/bytes-net-sizes';
|
||||
|
||||
const props = defineProps<{
|
||||
connection: any,
|
||||
meta: any,
|
||||
value: number
|
||||
}>();
|
||||
|
||||
let inRecent: number = $ref(0);
|
||||
let outRecent: number = $ref(0);
|
||||
|
||||
function onStats(connStats) {
|
||||
inRecent = connStats.net.rx;
|
||||
outRecent = connStats.net.tx;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
props.connection.on('stats', onStats);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
props.connection.off('stats', onStats);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
display: flex;
|
||||
padding: 16px 32px;
|
||||
}
|
||||
|
||||
.pie {
|
||||
height: 42px;
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.div {
|
||||
flex: 1;
|
||||
margin: auto;
|
||||
|
||||
> p {
|
||||
margin: 0 0 2px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
font-weight: bold;
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
Loading…
Reference in a new issue