447 lines
18 KiB
Vue
447 lines
18 KiB
Vue
<template>
|
|
<div>
|
|
<h2 class="outside-card-header mb-1">
|
|
{{ $gettext('Administration') }}
|
|
</h2>
|
|
|
|
<b-row>
|
|
<b-col v-for="(panel, key) in adminPanels" :key="key" sm="12" lg="4" class="mb-4">
|
|
<b-card no-body>
|
|
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<h2 class="card-title">{{ panel.label }}</h2>
|
|
</div>
|
|
<div class="flex-shrink-0 pt-1">
|
|
<icon class="lg" :icon="panel.icon"></icon>
|
|
</div>
|
|
</b-card-header>
|
|
|
|
<b-list-group>
|
|
<b-list-group-item v-for="(item, key) in panel.items" :key="key" :href="item.url">{{
|
|
item.label
|
|
}}
|
|
</b-list-group-item>
|
|
</b-list-group>
|
|
</b-card>
|
|
</b-col>
|
|
</b-row>
|
|
|
|
<h2 class="outside-card-header mb-1">
|
|
{{ $gettext('Server Status') }}
|
|
</h2>
|
|
|
|
<b-row>
|
|
<b-col sm="12" lg="6" xl="6" class="mb-4">
|
|
<b-card no-body>
|
|
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<h2 class="card-title">
|
|
{{ $gettext('Memory') }}
|
|
</h2>
|
|
</div>
|
|
|
|
<div class="flex-shrink-0">
|
|
<b-button variant="outline-light" size="sm" class="py-2"
|
|
@click.prevent="showMemoryStatsHelpModal">
|
|
<icon icon="help_outline"></icon>
|
|
</b-button>
|
|
</div>
|
|
</b-card-header>
|
|
|
|
<b-card-body>
|
|
<h6 class="mb-1 text-center">
|
|
{{ $gettext('Total RAM') }}
|
|
:
|
|
{{ stats.memory.readable.total }}
|
|
</h6>
|
|
|
|
<b-progress :max="stats.memory.bytes.total" :label="stats.memory.readable.used"
|
|
class="h-20 mb-3 mt-2">
|
|
<b-progress-bar variant="primary" :value="stats.memory.bytes.used"></b-progress-bar>
|
|
<b-progress-bar variant="warning"
|
|
:value="stats.memory.bytes.cached"></b-progress-bar>
|
|
</b-progress>
|
|
|
|
<b-row>
|
|
<b-col>
|
|
<b-badge pill variant="primary"> </b-badge>
|
|
{{ $gettext('Used') }}
|
|
: {{ stats.memory.readable.used }}
|
|
</b-col>
|
|
<b-col>
|
|
<b-badge pill variant="warning"> </b-badge>
|
|
{{ $gettext('Cached') }}
|
|
: {{ stats.memory.readable.cached }}
|
|
</b-col>
|
|
</b-row>
|
|
</b-card-body>
|
|
</b-card>
|
|
</b-col>
|
|
|
|
<b-col sm="12" lg="6" xl="6" class="mb-4">
|
|
<b-card no-body>
|
|
<b-card-header header-bg-variant="primary-dark">
|
|
<h2 class="card-title">
|
|
{{ $gettext('Disk Space') }}
|
|
</h2>
|
|
</b-card-header>
|
|
|
|
<b-card-body>
|
|
<h6 class="mb-1 text-center">
|
|
{{ $gettext('Total Disk Space') }}
|
|
:
|
|
{{ stats.disk.readable.total }}
|
|
</h6>
|
|
|
|
<b-progress :max="stats.disk.bytes.total" :label="stats.disk.readable.used"
|
|
class="h-20 mb-3 mt-2">
|
|
<b-progress-bar variant="primary" :value="stats.disk.bytes.used"></b-progress-bar>
|
|
</b-progress>
|
|
|
|
<b-row>
|
|
<b-col>
|
|
<b-badge pill variant="primary"> </b-badge>
|
|
{{ $gettext('Used') }}
|
|
:
|
|
{{ stats.disk.readable.used }}
|
|
</b-col>
|
|
</b-row>
|
|
</b-card-body>
|
|
</b-card>
|
|
</b-col>
|
|
</b-row>
|
|
|
|
<b-row>
|
|
<b-col sm="12" lg="8" xl="6" class="mb-4">
|
|
<b-card no-body>
|
|
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<h2 class="card-title">
|
|
{{ $gettext('CPU Load') }}
|
|
</h2>
|
|
</div>
|
|
|
|
<div class="flex-shrink-0">
|
|
<b-button variant="outline-light" size="sm" class="py-2"
|
|
@click.prevent="showCpuStatsHelpModal">
|
|
<icon icon="help_outline"></icon>
|
|
</b-button>
|
|
</div>
|
|
</b-card-header>
|
|
|
|
<b-card-body>
|
|
<h5 class="mb-1 text-center">{{ formatCpuName(stats.cpu.total.name) }}</h5>
|
|
|
|
<b-progress max="100" :label="formatPercentageString(stats.cpu.total.usage)"
|
|
class="h-20 mb-3 mt-2">
|
|
<b-progress-bar variant="danger" :value="stats.cpu.total.steal"></b-progress-bar>
|
|
<b-progress-bar variant="warning" :value="stats.cpu.total.io_wait"></b-progress-bar>
|
|
<b-progress-bar variant="primary" :value="stats.cpu.total.usage"></b-progress-bar>
|
|
</b-progress>
|
|
|
|
<b-row>
|
|
<b-col>
|
|
<b-badge pill variant="danger"> </b-badge>
|
|
{{ $gettext('Steal') }}
|
|
: {{ stats.cpu.total.steal }}%
|
|
</b-col>
|
|
<b-col>
|
|
<b-badge pill variant="warning"> </b-badge>
|
|
{{ $gettext('Wait') }}
|
|
: {{ stats.cpu.total.io_wait }}%
|
|
</b-col>
|
|
<b-col>
|
|
<b-badge pill variant="primary"> </b-badge>
|
|
{{ $gettext('Use') }}
|
|
: {{ stats.cpu.total.usage }}%
|
|
</b-col>
|
|
</b-row>
|
|
|
|
<hr>
|
|
|
|
<b-row>
|
|
<b-col v-for="core in stats.cpu.cores" :key="core.name" lg="6">
|
|
<h6 class="mb-1 text-center">{{ formatCpuName(core.name) }}</h6>
|
|
|
|
<b-progress max="100" :label="formatPercentageString(core.usage)" class="h-20">
|
|
<b-progress-bar variant="danger" :value="core.steal"></b-progress-bar>
|
|
<b-progress-bar variant="warning" :value="core.io_wait"></b-progress-bar>
|
|
<b-progress-bar variant="primary" :value="core.usage"></b-progress-bar>
|
|
</b-progress>
|
|
|
|
<b-row no-gutters class="mb-2 mt-1">
|
|
<b-col>
|
|
St: {{ core.steal }}%
|
|
</b-col>
|
|
<b-col>
|
|
Wa: {{ core.io_wait }}%
|
|
</b-col>
|
|
<b-col>
|
|
Us: {{ core.usage }}%
|
|
</b-col>
|
|
</b-row>
|
|
</b-col>
|
|
</b-row>
|
|
</b-card-body>
|
|
|
|
<b-card-footer>
|
|
<h6 class="mb-1 text-center">
|
|
{{ $gettext('Load Average') }}
|
|
</h6>
|
|
<b-row class="text-center" no-gutters>
|
|
<b-col>
|
|
<h6>1-Min</h6>
|
|
{{ stats.cpu.load[0].toFixed(2) }}
|
|
</b-col>
|
|
<b-col>
|
|
<h6>5-Min</h6>
|
|
{{ stats.cpu.load[1].toFixed(2) }}
|
|
</b-col>
|
|
<b-col>
|
|
<h6>15-Min</h6>
|
|
{{ stats.cpu.load[2].toFixed(2) }}
|
|
</b-col>
|
|
</b-row>
|
|
</b-card-footer>
|
|
</b-card>
|
|
</b-col>
|
|
|
|
<b-col sm="12" lg="4" xl="6" class="mb-4">
|
|
<b-card no-body>
|
|
<b-card-header header-bg-variant="primary-dark" class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<h2 class="card-title">
|
|
{{ $gettext('Services') }}
|
|
</h2>
|
|
</div>
|
|
</b-card-header>
|
|
|
|
<table class="table table-sm table-striped table-responsive mb-0">
|
|
<colgroup>
|
|
<col style="width: 5%;">
|
|
<col style="width: 75%;">
|
|
<col style="width: 20%;">
|
|
</colgroup>
|
|
<tbody>
|
|
<tr class="align-middle" v-for="service in services" :key="service.name">
|
|
<td class="text-center pr-2">
|
|
<template v-if="service.running">
|
|
<b-badge pill variant="success" :title="langServiceRunning">
|
|
|
|
<span class="sr-only">{{ langServiceRunning }}</span>
|
|
</b-badge>
|
|
</template>
|
|
<template v-else>
|
|
<b-badge pill variant="danger" :title="langServiceStopped">
|
|
|
|
<span class="sr-only">{{ langServiceStopped }}</span>
|
|
</b-badge>
|
|
</template>
|
|
</td>
|
|
<td class="pl-2">
|
|
<h6 class="mb-0">
|
|
{{ service.name }}<br>
|
|
<small>{{ service.description }}</small>
|
|
</h6>
|
|
</td>
|
|
<td>
|
|
<b-button-group size="sm" v-if="service.links.restart">
|
|
<b-button size="sm" :variant="service.running ? 'bg' : 'danger'"
|
|
@click.prevent="doRestart(service.links.restart)">
|
|
{{ $gettext('Restart') }}
|
|
</b-button>
|
|
</b-button-group>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</b-card>
|
|
</b-col>
|
|
</b-row>
|
|
|
|
<b-row>
|
|
<b-col>
|
|
<b-card no-body>
|
|
<b-card-header header-bg-variant="primary-dark">
|
|
<h2 class="card-title">
|
|
{{ $gettext('Network Interfaces') }}
|
|
</h2>
|
|
</b-card-header>
|
|
|
|
<b-tabs content-class="mt-3" pills card>
|
|
<b-tab v-for="netInterface in stats.network" :key="netInterface.interface_name"
|
|
:title="netInterface.interface_name">
|
|
<b-row class="mb-3">
|
|
<b-col class="mb-3">
|
|
<h5 class="mb-1 text-center">
|
|
{{ $gettext('Received') }}
|
|
</h5>
|
|
<b-table striped responsive
|
|
:items="getNetworkInterfaceTableItems(netInterface.received)"
|
|
:fields="getNetworkInterfaceTableFields(netInterface.received)">
|
|
</b-table>
|
|
</b-col>
|
|
<b-col>
|
|
<h5 class="mb-1 text-center">
|
|
{{ $gettext('Transmitted') }}
|
|
</h5>
|
|
<b-table striped responsive
|
|
:items="getNetworkInterfaceTableItems(netInterface.transmitted)"
|
|
:fields="getNetworkInterfaceTableFields(netInterface.transmitted)">
|
|
</b-table>
|
|
</b-col>
|
|
</b-row>
|
|
</b-tab>
|
|
</b-tabs>
|
|
</b-card>
|
|
</b-col>
|
|
</b-row>
|
|
|
|
<cpu-stats-help-modal ref="cpuStatsHelpModal"></cpu-stats-help-modal>
|
|
<memory-stats-help-modal ref="memoryStatsHelpModal"></memory-stats-help-modal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Icon from '~/components/Common/Icon';
|
|
import InfoCard from '~/components/Common/InfoCard';
|
|
import CpuStatsHelpModal from "./Index/CpuStatsHelpModal";
|
|
import MemoryStatsHelpModal from "./Index/MemoryStatsHelpModal";
|
|
import _ from 'lodash';
|
|
|
|
export default {
|
|
name: 'AdminIndex',
|
|
components: {InfoCard, CpuStatsHelpModal, MemoryStatsHelpModal, Icon},
|
|
props: {
|
|
adminPanels: Object,
|
|
statsUrl: String,
|
|
servicesUrl: String
|
|
},
|
|
data() {
|
|
return {
|
|
stats: {
|
|
cpu: {
|
|
total: {
|
|
name: 'Total',
|
|
steal: 0,
|
|
io_wait: 0,
|
|
usage: 0
|
|
},
|
|
cores: [],
|
|
load: [
|
|
0,
|
|
0,
|
|
0
|
|
]
|
|
},
|
|
memory: {
|
|
bytes: {
|
|
total: 0,
|
|
used: 0,
|
|
cached: 0
|
|
},
|
|
readable: {
|
|
total: '',
|
|
used: '',
|
|
cached: ''
|
|
}
|
|
},
|
|
disk: {
|
|
bytes: {
|
|
total: 0,
|
|
used: 0
|
|
},
|
|
readable: {
|
|
total: '',
|
|
used: ''
|
|
}
|
|
},
|
|
network: []
|
|
},
|
|
services: []
|
|
};
|
|
},
|
|
created() {
|
|
this.updateStats();
|
|
this.updateServices();
|
|
},
|
|
computed: {
|
|
langServiceRunning() {
|
|
return this.$gettext('Service Running');
|
|
},
|
|
langServiceStopped() {
|
|
return this.$gettext('Service Stopped');
|
|
}
|
|
},
|
|
methods: {
|
|
formatCpuName(cpuName) {
|
|
return _.upperFirst(cpuName);
|
|
},
|
|
formatPercentageString(value) {
|
|
return value + '%';
|
|
},
|
|
getNetworkInterfaceTableFields(interfaceData) {
|
|
let fields = [];
|
|
|
|
Object.keys(interfaceData).forEach((key) => {
|
|
fields.push({
|
|
key: key,
|
|
sortable: false
|
|
});
|
|
});
|
|
|
|
return fields;
|
|
},
|
|
getNetworkInterfaceTableItems(interfaceData) {
|
|
let item = {};
|
|
|
|
Object.entries(interfaceData).forEach((data) => {
|
|
let key = data[0];
|
|
let value = data[1];
|
|
|
|
if (_.isObject(value)) {
|
|
value = value.readable + '/s';
|
|
}
|
|
|
|
item[key] = value;
|
|
});
|
|
|
|
return [item];
|
|
},
|
|
updateStats() {
|
|
this.axios.get(this.statsUrl).then((response) => {
|
|
this.stats = response.data;
|
|
|
|
setTimeout(this.updateStats, (!document.hidden) ? 1000 : 5000);
|
|
}).catch((error) => {
|
|
if (!error.response || error.response.data.code !== 403) {
|
|
setTimeout(this.updateStats, (!document.hidden) ? 5000 : 10000);
|
|
}
|
|
});
|
|
},
|
|
updateServices() {
|
|
this.axios.get(this.servicesUrl).then((response) => {
|
|
this.services = response.data;
|
|
|
|
setTimeout(this.updateServices, (!document.hidden) ? 5000 : 15000);
|
|
}).catch((error) => {
|
|
if (!error.response || error.response.data.code !== 403) {
|
|
setTimeout(this.updateServices, (!document.hidden) ? 15000 : 30000);
|
|
}
|
|
});
|
|
},
|
|
doRestart(serviceUrl) {
|
|
this.axios.post(serviceUrl).then((resp) => {
|
|
this.$notifySuccess(resp.data.message);
|
|
});
|
|
},
|
|
showCpuStatsHelpModal() {
|
|
this.$refs.cpuStatsHelpModal.create();
|
|
},
|
|
showMemoryStatsHelpModal() {
|
|
this.$refs.memoryStatsHelpModal.create();
|
|
},
|
|
}
|
|
};
|
|
</script>
|