Frontend: Removed the server metrics widget

This commit is contained in:
Natty 2024-01-10 21:15:30 +01:00
parent 1366adcebf
commit b2a55f1d6d
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
9 changed files with 0 additions and 830 deletions

View File

@ -61,10 +61,6 @@ export default function (app: App) {
"MkwSlideshow",
defineAsyncComponent(() => import("./slideshow.vue"))
);
app.component(
"MkwServerMetric",
defineAsyncComponent(() => import("./server-metric/index.vue"))
);
app.component(
"MkwOnlineUsers",
defineAsyncComponent(() => import("./online-users.vue"))
@ -108,7 +104,6 @@ export const widgets = [
"federation",
"postForm",
"slideshow",
"serverMetric",
"serverInfo",
"onlineUsers",
"jobQueue",

View File

@ -1,193 +0,0 @@
<template>
<div class="lcfyofjk">
<svg :viewBox="`0 0 ${viewBoxX} ${viewBoxY}`">
<defs>
<linearGradient :id="cpuGradientId" x1="0" x2="0" y1="1" y2="0">
<stop offset="0%" stop-color="hsl(189, 43%, 73%)"></stop>
<stop offset="100%" stop-color="hsl(343, 76%, 68%)"></stop>
</linearGradient>
<mask
:id="cpuMaskId"
x="0"
y="0"
:width="viewBoxX"
:height="viewBoxY"
>
<polygon
:points="cpuPolygonPoints"
fill="#fff"
fill-opacity="0.5"
/>
<polyline
:points="cpuPolylinePoints"
fill="none"
stroke="#fff"
stroke-width="1"
/>
<circle :cx="cpuHeadX" :cy="cpuHeadY" r="1.5" fill="#fff" />
</mask>
</defs>
<rect
x="-2"
y="-2"
:width="viewBoxX + 4"
:height="viewBoxY + 4"
:style="`stroke: none; fill: url(#${cpuGradientId}); mask: url(#${cpuMaskId})`"
/>
<text x="1" y="5">
CPU
<tspan>{{ cpuP }}%</tspan>
</text>
</svg>
<svg :viewBox="`0 0 ${viewBoxX} ${viewBoxY}`">
<defs>
<linearGradient :id="memGradientId" x1="0" x2="0" y1="1" y2="0">
<stop offset="0%" stop-color="hsl(189, 43%, 73%)"></stop>
<stop offset="100%" stop-color="hsl(343, 76%, 68%)"></stop>
</linearGradient>
<mask
:id="memMaskId"
x="0"
y="0"
:width="viewBoxX"
:height="viewBoxY"
>
<polygon
:points="memPolygonPoints"
fill="#fff"
fill-opacity="0.5"
/>
<polyline
:points="memPolylinePoints"
fill="none"
stroke="#fff"
stroke-width="1"
/>
<circle :cx="memHeadX" :cy="memHeadY" r="1.5" fill="#fff" />
</mask>
</defs>
<rect
x="-2"
y="-2"
:width="viewBoxX + 4"
:height="viewBoxY + 4"
:style="`stroke: none; fill: url(#${memGradientId}); mask: url(#${memMaskId})`"
/>
<text x="1" y="5">
MEM
<tspan>{{ memP }}%</tspan>
</text>
</svg>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onBeforeUnmount } from "vue";
import { v4 as uuid } from "uuid";
const props = defineProps<{
connection: any;
meta: any;
}>();
let viewBoxX: number = $ref(50);
let viewBoxY: number = $ref(30);
let stats: any[] = $ref([]);
const cpuGradientId = uuid();
const cpuMaskId = uuid();
const memGradientId = uuid();
const memMaskId = uuid();
let cpuPolylinePoints: string = $ref("");
let memPolylinePoints: string = $ref("");
let cpuPolygonPoints: string = $ref("");
let memPolygonPoints: string = $ref("");
let cpuHeadX: any = $ref(null);
let cpuHeadY: any = $ref(null);
let memHeadX: any = $ref(null);
let memHeadY: any = $ref(null);
let cpuP: string = $ref("");
let memP: string = $ref("");
onMounted(() => {
props.connection.on("stats", onStats);
props.connection.on("statsLog", onStatsLog);
props.connection.send("requestLog", {
id: Math.random().toString().substr(2, 8),
});
});
onBeforeUnmount(() => {
props.connection.off("stats", onStats);
props.connection.off("statsLog", onStatsLog);
});
function onStats(connStats) {
stats.push(connStats);
if (stats.length > 50) stats.shift();
let cpuPolylinePointsStats = stats.map((s, i) => [
viewBoxX - (stats.length - 1 - i),
(1 - s.cpu) * viewBoxY,
]);
let memPolylinePointsStats = stats.map((s, i) => [
viewBoxX - (stats.length - 1 - i),
(1 - s.mem.active / props.meta.mem.total) * viewBoxY,
]);
cpuPolylinePoints = cpuPolylinePointsStats
.map((xy) => `${xy[0]},${xy[1]}`)
.join(" ");
memPolylinePoints = memPolylinePointsStats
.map((xy) => `${xy[0]},${xy[1]}`)
.join(" ");
cpuPolygonPoints = `${
viewBoxX - (stats.length - 1)
},${viewBoxY} ${cpuPolylinePoints} ${viewBoxX},${viewBoxY}`;
memPolygonPoints = `${
viewBoxX - (stats.length - 1)
},${viewBoxY} ${memPolylinePoints} ${viewBoxX},${viewBoxY}`;
cpuHeadX = cpuPolylinePointsStats[cpuPolylinePointsStats.length - 1][0];
cpuHeadY = cpuPolylinePointsStats[cpuPolylinePointsStats.length - 1][1];
memHeadX = memPolylinePointsStats[memPolylinePointsStats.length - 1][0];
memHeadY = memPolylinePointsStats[memPolylinePointsStats.length - 1][1];
cpuP = (connStats.cpu * 100).toFixed(0);
memP = ((connStats.mem.active / props.meta.mem.total) * 100).toFixed(0);
}
function onStatsLog(statsLog) {
for (const revStats of [...statsLog].reverse()) {
onStats(revStats);
}
}
</script>
<style lang="scss" scoped>
.lcfyofjk {
display: flex;
> svg {
display: block;
padding: 10px;
width: 50%;
&:first-child {
padding-right: 5px;
}
&:last-child {
padding-left: 5px;
}
> text {
font-size: 5px;
fill: currentColor;
> tspan {
opacity: 0.5;
}
}
}
}
</style>

View File

@ -1,65 +0,0 @@
<template>
<div class="vrvdvrys">
<XPie class="pie" :value="usage" />
<div>
<p><i class="ph-cpu ph-bold ph-lg"></i>CPU</p>
<p>{{ meta.cpu.cores }} Logical cores</p>
<p>{{ meta.cpu.model }}</p>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onBeforeUnmount } from "vue";
import XPie from "./pie.vue";
const props = defineProps<{
connection: any;
meta: any;
}>();
let usage: number = $ref(0);
function onStats(stats) {
usage = stats.cpu;
}
onMounted(() => {
props.connection.on("stats", onStats);
});
onBeforeUnmount(() => {
props.connection.off("stats", onStats);
});
</script>
<style lang="scss" scoped>
.vrvdvrys {
display: flex;
padding: 16px;
> .pie {
height: 82px;
flex-shrink: 0;
margin-right: 16px;
}
> div {
flex: 1;
> p {
margin: 0;
font-size: 0.8em;
&:first-child {
font-weight: bold;
margin-bottom: 4px;
> i {
margin-right: 4px;
}
}
}
}
}
</style>

View File

@ -1,57 +0,0 @@
<template>
<div class="zbwaqsat">
<XPie class="pie" :value="usage" />
<div>
<p><i class="ph-hard-drives ph-bold ph-lg"></i>Disk</p>
<p>Total: {{ bytes(total, 1) }}</p>
<p>Free: {{ bytes(available, 1) }}</p>
<p>Used: {{ bytes(used, 1) }}</p>
</div>
</div>
</template>
<script lang="ts" setup>
import {} from "vue";
import XPie from "./pie.vue";
import bytes from "@/filters/bytes";
const props = defineProps<{
meta: any; // TODO
}>();
const usage = $computed(() => props.meta.fs.used / props.meta.fs.total);
const total = $computed(() => props.meta.fs.total);
const used = $computed(() => props.meta.fs.used);
const available = $computed(() => props.meta.fs.total - props.meta.fs.used);
</script>
<style lang="scss" scoped>
.zbwaqsat {
display: flex;
padding: 16px;
> .pie {
height: 82px;
flex-shrink: 0;
margin-right: 16px;
}
> div {
flex: 1;
> p {
margin: 0;
font-size: 0.8em;
&:first-child {
font-weight: bold;
margin-bottom: 4px;
> i {
margin-right: 4px;
}
}
}
}
}
</style>

View File

@ -1,135 +0,0 @@
<template>
<MkContainer
:show-header="widgetProps.showHeader"
:naked="widgetProps.transparent"
>
<template #header
><i class="ph-hard-drives ph-bold ph-lg"></i
>{{ i18n.ts._widgets.serverMetric }}</template
>
<template #func
><button class="_button" @click="toggleView()">
<i class="ph-sort-ascending ph-bold ph-lg"></i></button
></template>
<div v-if="meta" class="mkw-serverMetric">
<XCpuMemory
v-if="widgetProps.view === 0"
:connection="connection"
:meta="meta"
/>
<XNet
v-else-if="widgetProps.view === 1"
:connection="connection"
:meta="meta"
/>
<XCpu
v-else-if="widgetProps.view === 2"
:connection="connection"
:meta="meta"
/>
<XMemory
v-else-if="widgetProps.view === 3"
:connection="connection"
:meta="meta"
/>
<XDisk
v-else-if="widgetProps.view === 4"
:connection="connection"
:meta="meta"
/>
<XMeili
v-else-if="
instance.features.searchFilters && widgetProps.view === 5
"
:connection="connection"
:meta="meta"
/>
</div>
</MkContainer>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from "vue";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
} from "../widget";
import XCpuMemory from "./cpu-mem.vue";
import XNet from "./net.vue";
import XCpu from "./cpu.vue";
import XMemory from "./mem.vue";
import XDisk from "./disk.vue";
import XMeili from "./meilisearch.vue";
import MkContainer from "@/components/MkContainer.vue";
import { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import { stream } from "@/stream";
import { i18n } from "@/i18n";
import { instance } from "@/instance";
const name = "serverMetric";
const widgetPropsDef = {
showHeader: {
type: "boolean" as const,
default: true,
},
transparent: {
type: "boolean" as const,
default: false,
},
view: {
type: "number" as const,
default: 0,
hidden: true,
},
};
type WidgetProps = GetFormResultType<typeof widgetPropsDef>;
// vueimporttype
//const props = defineProps<WidgetComponentProps<WidgetProps>>();
//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>();
const props = defineProps<{ widget?: Widget<WidgetProps> }>();
const emit = defineEmits<{ (ev: "updateProps", props: WidgetProps) }>();
const { widgetProps, configure, save } = useWidgetPropsManager(
name,
widgetPropsDef,
props,
emit
);
const meta = ref(null);
os.api("server-info", {}).then((res) => {
meta.value = res;
});
const toggleView = () => {
if (
(widgetProps.view === 5 && instance.features.searchFilters) ||
(widgetProps.view === 4 && !instance.features.searchFilters)
) {
widgetProps.view = 0;
} else {
widgetProps.view++;
}
save();
};
const connection = stream.useChannel("serverStats");
onUnmounted(() => {
connection.dispose();
});
defineExpose<WidgetComponentExpose>({
name,
configure,
id: props.widget ? props.widget.id : null,
});
</script>

View File

@ -1,85 +0,0 @@
<template>
<div class="verusivbr">
<XPie
v-tooltip="i18n.ts.meiliIndexCount"
class="pie"
:value="progress"
:reverse="true"
/>
<div>
<p><i class="ph-file-search ph-bold ph-lg"></i>MeiliSearch</p>
<p>{{ i18n.ts._widgets.meiliStatus }}: {{ available }}</p>
<p>{{ i18n.ts._widgets.meiliSize }}: {{ bytes(totalSize, 1) }}</p>
<p>{{ i18n.ts._widgets.meiliIndexCount }}: {{ indexCount }}</p>
</div>
</div>
<br />
</template>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted } from "vue";
import bytes from "@/filters/bytes";
import XPie from "./pie.vue";
import { i18n } from "@/i18n";
import * as os from "@/os";
const props = defineProps<{
connection: any;
meta: any;
}>();
let progress: number = $ref(0);
let serverStats = $ref(null);
let totalSize: number = $ref(0);
let indexCount: number = $ref(0);
let available: string = $ref("unavailable");
function onStats(stats) {
totalSize = stats.meilisearch.size;
indexCount = stats.meilisearch.indexed_count;
available = stats.meilisearch.health;
progress = indexCount / serverStats.notesCount;
}
onMounted(() => {
os.api("stats", {}).then((res) => {
serverStats = res;
});
props.connection.on("stats", onStats);
});
onBeforeUnmount(() => {
props.connection.off("stats", onStats);
});
</script>
<style lang="scss" scoped>
.verusivbr {
display: flex;
padding: 16px;
> .pie {
height: 82px;
flex-shrink: 0;
margin-right: 16px;
}
> div {
flex: 1;
> p {
margin: 0;
font-size: 0.8em;
&:first-child {
font-weight: bold;
margin-bottom: 4px;
> i {
margin-right: 4px;
}
}
}
}
}
</style>

View File

@ -1,73 +0,0 @@
<template>
<div class="zlxnikvl">
<XPie class="pie" :value="usage" />
<div>
<p><i class="ph-microchip ph-bold ph-lg"></i>RAM</p>
<p>Total: {{ bytes(total, 1) }}</p>
<p>Used: {{ bytes(used, 1) }}</p>
<p>Free: {{ bytes(free, 1) }}</p>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onBeforeUnmount } from "vue";
import XPie from "./pie.vue";
import bytes from "@/filters/bytes";
const props = defineProps<{
connection: any;
meta: any;
}>();
let usage: number = $ref(0);
let total: number = $ref(0);
let used: number = $ref(0);
let free: number = $ref(0);
function onStats(stats) {
usage = stats.mem.active / props.meta.mem.total;
total = props.meta.mem.total;
used = stats.mem.active;
free = total - used;
}
onMounted(() => {
props.connection.on("stats", onStats);
});
onBeforeUnmount(() => {
props.connection.off("stats", onStats);
});
</script>
<style lang="scss" scoped>
.zlxnikvl {
display: flex;
padding: 16px;
> .pie {
height: 82px;
flex-shrink: 0;
margin-right: 16px;
}
> div {
flex: 1;
> p {
margin: 0;
font-size: 0.8em;
&:first-child {
font-weight: bold;
margin-bottom: 4px;
> i {
margin-right: 4px;
}
}
}
}
}
</style>

View File

@ -1,153 +0,0 @@
<template>
<div class="oxxrhrto">
<svg :viewBox="`0 0 ${viewBoxX} ${viewBoxY}`">
<polygon
:points="inPolygonPoints"
fill="#f6c177"
fill-opacity="0.5"
/>
<polyline
:points="inPolylinePoints"
fill="none"
stroke="#f6c177"
stroke-width="1"
/>
<circle :cx="inHeadX" :cy="inHeadY" r="1.5" fill="#f6c177" />
<text x="1" y="5">
NET rx
<tspan>{{ bytes(inRecent) }}</tspan>
</text>
</svg>
<svg :viewBox="`0 0 ${viewBoxX} ${viewBoxY}`">
<polygon
:points="outPolygonPoints"
fill="#31748f"
fill-opacity="0.5"
/>
<polyline
:points="outPolylinePoints"
fill="none"
stroke="#31748f"
stroke-width="1"
/>
<circle :cx="outHeadX" :cy="outHeadY" r="1.5" fill="#31748f" />
<text x="1" y="5">
NET tx
<tspan>{{ bytes(outRecent) }}</tspan>
</text>
</svg>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onBeforeUnmount } from "vue";
import bytes from "@/filters/bytes";
const props = defineProps<{
connection: any;
meta: any;
}>();
let viewBoxX: number = $ref(50);
let viewBoxY: number = $ref(30);
let stats: any[] = $ref([]);
let inPolylinePoints: string = $ref("");
let outPolylinePoints: string = $ref("");
let inPolygonPoints: string = $ref("");
let outPolygonPoints: string = $ref("");
let inHeadX: any = $ref(null);
let inHeadY: any = $ref(null);
let outHeadX: any = $ref(null);
let outHeadY: any = $ref(null);
let inRecent: number = $ref(0);
let outRecent: number = $ref(0);
onMounted(() => {
props.connection.on("stats", onStats);
props.connection.on("statsLog", onStatsLog);
props.connection.send("requestLog", {
id: Math.random().toString().substr(2, 8),
});
});
onBeforeUnmount(() => {
props.connection.off("stats", onStats);
props.connection.off("statsLog", onStatsLog);
});
function onStats(connStats) {
stats.push(connStats);
if (stats.length > 50) stats.shift();
const inPeak = Math.max(1024 * 64, Math.max(...stats.map((s) => s.net.rx)));
const outPeak = Math.max(
1024 * 64,
Math.max(...stats.map((s) => s.net.tx))
);
let inPolylinePointsStats = stats.map((s, i) => [
viewBoxX - (stats.length - 1 - i),
(1 - s.net.rx / inPeak) * viewBoxY,
]);
let outPolylinePointsStats = stats.map((s, i) => [
viewBoxX - (stats.length - 1 - i),
(1 - s.net.tx / outPeak) * viewBoxY,
]);
inPolylinePoints = inPolylinePointsStats
.map((xy) => `${xy[0]},${xy[1]}`)
.join(" ");
outPolylinePoints = outPolylinePointsStats
.map((xy) => `${xy[0]},${xy[1]}`)
.join(" ");
inPolygonPoints = `${
viewBoxX - (stats.length - 1)
},${viewBoxY} ${inPolylinePoints} ${viewBoxX},${viewBoxY}`;
outPolygonPoints = `${
viewBoxX - (stats.length - 1)
},${viewBoxY} ${outPolylinePoints} ${viewBoxX},${viewBoxY}`;
inHeadX = inPolylinePointsStats[inPolylinePointsStats.length - 1][0];
inHeadY = inPolylinePointsStats[inPolylinePointsStats.length - 1][1];
outHeadX = outPolylinePointsStats[outPolylinePointsStats.length - 1][0];
outHeadY = outPolylinePointsStats[outPolylinePointsStats.length - 1][1];
inRecent = connStats.net.rx;
outRecent = connStats.net.tx;
}
function onStatsLog(statsLog) {
for (const revStats of [...statsLog].reverse()) {
onStats(revStats);
}
}
</script>
<style lang="scss" scoped>
.oxxrhrto {
display: flex;
> svg {
display: block;
padding: 10px;
width: 50%;
&:first-child {
padding-right: 5px;
}
&:last-child {
padding-left: 5px;
}
> text {
font-size: 5px;
fill: currentColor;
> tspan {
opacity: 0.5;
}
}
}
}
</style>

View File

@ -1,64 +0,0 @@
<template>
<svg class="hsalcinq" viewBox="0 0 1 1" preserveAspectRatio="none">
<circle
:r="r"
cx="50%"
cy="50%"
fill="none"
stroke-width="0.1"
stroke="rgba(0, 0, 0, 0.05)"
/>
<circle
:r="r"
cx="50%"
cy="50%"
:stroke-dasharray="Math.PI * (r * 2)"
:stroke-dashoffset="strokeDashoffset"
fill="none"
stroke-width="0.1"
:stroke="color"
/>
<text x="50%" y="50%" dy="0.05" text-anchor="middle">
{{ (value * 100).toFixed(0) }}%
</text>
</svg>
</template>
<script lang="ts" setup>
import {} from "vue";
const props = defineProps<{
value: number;
reverse?: boolean;
}>();
const r = 0.45;
const color = $computed(
() =>
`hsl(${
props.reverse ? props.value * 180 : 180 - props.value * 180
}, 80%, 70%)`
);
const strokeDashoffset = $computed(
() => (1 - props.value) * (Math.PI * (r * 2))
);
</script>
<style lang="scss" scoped>
.hsalcinq {
display: block;
height: 100%;
> circle {
transform-origin: center;
transform: rotate(-90deg);
transition: stroke-dashoffset 0.5s ease;
}
> text {
font-size: 0.15px;
fill: currentColor;
}
}
</style>