WIP: Improve admin dashboard

This commit is contained in:
syuilo 2020-08-13 17:58:16 +09:00
parent c59d7d941a
commit ed17636fb9
3 changed files with 71 additions and 13 deletions

View file

@ -562,6 +562,7 @@ metrics: "メトリクス"
overview: "概要" overview: "概要"
logs: "ログ" logs: "ログ"
delayed: "遅延" delayed: "遅延"
database: "データベース"
_sidebar: _sidebar:
full: "フル" full: "フル"

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="ukygtjoj _panel" :class="{ naked, hideHeader: !showHeader, scrollable }" v-size="{ max: [380], el: resizeBaseEl }"> <div class="ukygtjoj _panel" :class="{ naked, hideHeader: !showHeader, scrollable, closed: !showBody }" v-size="{ max: [380], el: resizeBaseEl }">
<header v-if="showHeader"> <header v-if="showHeader" ref="header">
<div class="title"><slot name="header"></slot></div> <div class="title"><slot name="header"></slot></div>
<slot name="func"></slot> <slot name="func"></slot>
<button class="_button" v-if="bodyTogglable" @click="() => showBody = !showBody"> <button class="_button" v-if="bodyTogglable" @click="() => showBody = !showBody">
@ -62,6 +62,18 @@ export default Vue.extend({
faAngleUp, faAngleDown faAngleUp, faAngleDown
}; };
}, },
mounted() {
this.$watch('showBody', showBody => {
this.$el.style.minHeight = `${this.$refs.header.offsetHeight}px`;
if (showBody) {
this.$el.style.flexBasis = `auto`;
} else {
this.$el.style.flexBasis = `${this.$refs.header.offsetHeight}px`;
}
}, {
immediate: true
});
},
methods: { methods: {
toggleContent(show: boolean) { toggleContent(show: boolean) {
if (!this.bodyTogglable) return; if (!this.bodyTogglable) return;

View file

@ -6,11 +6,11 @@
<mk-folder> <mk-folder>
<template #header><fa :icon="faTachometerAlt"/> {{ $t('overview') }}</template> <template #header><fa :icon="faTachometerAlt"/> {{ $t('overview') }}</template>
<div class="sboqnrfi"> <div class="sboqnrfi" :style="{ gridTemplateRows: overviewHeight }">
<mk-instance-stats :chart-limit="300" :detailed="true"/> <mk-instance-stats :chart-limit="300" :detailed="true" class="stats" ref="stats"/>
<div class="column"> <div class="column">
<mk-container :body-togglable="false" :resize-base-el="() => $el"> <mk-container :body-togglable="true" :resize-base-el="() => $el" class="info">
<template #header><fa :icon="faInfoCircle"/>{{ $t('instanceInfo') }}</template> <template #header><fa :icon="faInfoCircle"/>{{ $t('instanceInfo') }}</template>
<div class="_content"> <div class="_content">
@ -22,8 +22,16 @@
<div class="_keyValue"><b>Redis</b><span>v{{ serverInfo.redis }}</span></div> <div class="_keyValue"><b>Redis</b><span>v{{ serverInfo.redis }}</span></div>
</div> </div>
</mk-container> </mk-container>
<mk-container :body-togglable="true" :scrollable="true" :resize-base-el="() => $el" class="db">
<template #header><fa :icon="faDatabase"/>{{ $t('database') }}</template>
<mkw-federation/> <div class="_content" v-if="dbInfo">
<div class="_keyValue" v-for="table in Object.entries(dbInfo)"><b>{{ table[0] }}</b><span>{{ table[1].count | number }}</span><span>{{ table[1].size | bytes }}</span></div>
</div>
</mk-container>
<mkw-federation class="fed"/>
</div> </div>
</div> </div>
</mk-folder> </mk-folder>
@ -161,7 +169,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import { faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList } from '@fortawesome/free-solid-svg-icons'; import { faDatabase, faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList } from '@fortawesome/free-solid-svg-icons';
import Chart from 'chart.js'; import Chart from 'chart.js';
import VueJsonPretty from 'vue-json-pretty'; import VueJsonPretty from 'vue-json-pretty';
import MkInstanceStats from '../../components/instance-stats.vue'; import MkInstanceStats from '../../components/instance-stats.vue';
@ -218,7 +226,9 @@ export default Vue.extend({
logLevel: 'all', logLevel: 'all',
logDomain: '', logDomain: '',
modLogs: [], modLogs: [],
faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList, dbInfo: null,
overviewHeight: '1fr',
faDatabase, faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList,
} }
}, },
@ -485,6 +495,20 @@ export default Vue.extend({
}); });
}); });
}); });
this.$root.api('admin/get-table-stats', {}).then(res => {
this.dbInfo = res;
});
this.$nextTick(() => {
const ro = new ResizeObserver((entries, observer) => {
if (this.$refs.stats) {
this.overviewHeight = this.$refs.stats.$el.offsetHeight + 'px';
}
});
ro.observe(this.$refs.stats.$el);
});
}, },
beforeDestroy() { beforeDestroy() {
@ -590,11 +614,32 @@ export default Vue.extend({
grid-template-rows: 1fr; grid-template-rows: 1fr;
gap: 16px 16px; gap: 16px 16px;
> .stats {
height: min-content;
}
> .column { > .column {
display: grid; display: flex;
grid-template-columns: 1fr; flex-direction: column;
grid-template-rows: auto 1fr;
gap: 16px 16px; > .info {
flex-shrink: 0;
flex-grow: 0;
}
> .db {
flex: 1;
flex-grow: 0;
}
> .fed {
flex: 1;
flex-grow: 0;
}
> *:not(:last-child) {
margin-bottom: var(--margin);
}
} }
} }
@ -608,7 +653,7 @@ export default Vue.extend({
.vkyrmkwb { .vkyrmkwb {
display: grid; display: grid;
grid-template-columns: 0.5fr 1fr 1fr; grid-template-columns: 0.5fr 1fr 1fr;
grid-template-rows: 385px; grid-template-rows: 400px;
gap: 16px 16px; gap: 16px 16px;
} }