🚧 Refactor + more widgets

* ♻️ segment into smaller widgets, improve mixin
* ♻️ change NextcloudInfo to NextcloudUser
  * a small widget showing branding and uesr info, including quota
*  add NextcloudNotifications widget
  * show and delete Nextcloud notifications
*  add NextcloudUserStatus widget
  * display user statuses of selected users
*  add NextcloudStats widget (admin only)
  * display Nextcloud usage statistics (users, files, shares)
*  add NextcloudSystem widget (admin only)
  * visualise cpu load and memory utilisation, show server versions
*  add NextcloudPhpOpcache widget (admin only)
  * show statistics about php opcache performance
*  add a misc helper for formatting nunbers
* 🌐 add translations to widget templates
* 🌐 add translation entries for en
* 🍱 add scss styles file, shared by all widgets
This commit is contained in:
Marcell Fülöp
2022-06-19 12:06:43 +00:00
parent a43988f3cd
commit 821af62426
12 changed files with 1558 additions and 442 deletions

View File

@@ -0,0 +1,234 @@
<template>
<div v-if="didLoadData" class="nextcloud-widget nextcloud-system-wrapper">
<div class="charts">
<!-- memory gauge -->
<div class="chart-container">
<small>{{ tt('overall') }} {{ tt('memory-utilisation') }}</small>
<GaugeChart :value="memoryGauge.value"
:baseColor="memoryGauge.background"
:gaugeColor="memoryGauge.color">
<p class="percentage">{{ memoryGauge.value }}%</p>
</GaugeChart>
<small>{{ getMemoryGaugeLabel() }}</small>
</div>
<!-- cpu load chart -->
<div>
<div
:id="cpuLoadChartId" class="load-chart"
v-tooltip="$t('widgets.glances.system-load-desc')"></div>
</div>
</div>
<div>
<!-- server info: server -->
<hr />
<p>
<i class="fal fa-server"></i>
<strong>Nextcloud</strong>
<em>{{ server.nextcloud.system.version }}</em> <small> </small>
<strong>{{ server.server.webserver }}/PHP</strong>
<em>{{ server.server.php.version }}</em>
</p>
<hr />
<!-- server info: database -->
<p>
<i class="fal fa-database"></i>
<strong>{{ server.server.database.type }}</strong>
<em>{{ server.server.database.version }}</em> <small>{{ tt('using') }}</small>
<em v-html="convertBytes(server.server.database.size)"></em>
</p>
<hr/>
</div>
</div>
</template>
<script>
import WidgetMixin from '@/mixins/WidgetMixin';
import NextcloudMixin from '@/mixins/NextcloudMixin';
import GaugeChart from '@/components/Charts/Gauge';
import ChartingMixin from '@/mixins/ChartingMixin';
// //import { NcdServer } from '@/utils/ncd';
const NextcloudSystemSchema = {
server: {
server: {
database: {
type: null,
version: null,
size: null,
},
webserver: null,
php: {
version: null,
},
},
nextcloud: {
system: {
version: null,
freespace: null,
cpuload: [],
mem_total: null,
mem_free: null,
mem_percent: null,
},
},
},
memoryGauge: {
value: 0,
color: '#272f4d',
showMoreInfo: false,
moreInfo: null,
background: '#16161d',
},
};
/**
* NextcloudSystem widget - Visualises CPU load and memory utilisation and shows server versions
* Used endpoints
* - serverinfo: requires Nextcloud admin user
*/
export default {
mixins: [WidgetMixin, NextcloudMixin, ChartingMixin],
components: { GaugeChart },
data() {
return NextcloudSystemSchema;
},
computed: {
cpuLoadChartId() {
return `nextcloud-cpu-load-chart-${Math.random().toString().slice(-4)}`;
},
didLoadData() {
return !!(this?.server?.nextcloud?.system?.version);
},
},
methods: {
allowedStatuscodes() {
return [200];
},
async fetchData() {
if (!this.hasValidCredentials()) return;
this.makeRequest(this.endpoint('serverinfo'), this.headers)
// //Promise.resolve(NcdServer)
.then(this.processServerInfo)
.finally(() => this.finishLoading());
},
processServerInfo(serverData) {
const data = this.validateResponse(serverData);
if (!data || data.length === 0) return;
this.server.nextcloud.system = data?.nextcloud?.system;
this.$nextTick();
this.server.server.php.version = data?.server?.php?.version;
this.server.server.database = data?.server?.database;
this.server.server.webserver = data?.server?.webserver;
},
updateMemoryGauge(sys) {
this.memoryGauge.value = parseFloat(
(((sys.mem_total - sys.mem_free) / sys.mem_total) * 100).toFixed(2),
);
this.memoryGauge.color = this.getMemoryGaugeColor(this.memoryGauge.value);
},
updateOpcacheMemory() {
this.opcache_stats.opcache_hit_rate = parseFloat(
this.opcache_stats.opcache_hit_rate,
).toFixed(3);
this.opcache.memory_usage.total_memory = (
this.opcache.memory_usage.used_memory + this.opcache.memory_usage.free_memory
);
this.opcache.memory_usage.used_memory_percentage = parseFloat(
(this.opcache.memory_usage.used_memory / this.opcache.memory_usage.total_memory) * 100,
).toFixed(1);
},
updateOpcacheInterned() {
this.opcache.interned_strings_usage.total_memory = (
this.opcache.interned_strings_usage.used_memory
+ this.opcache.interned_strings_usage.free_memory
);
this.opcache.interned_strings_usage.used_memory_percentage = parseFloat(
(this.opcache.interned_strings_usage.used_memory
/ this.opcache.interned_strings_usage.total_memory) * 100,
).toFixed(5);
},
getMemoryGaugeColor(memPercent) {
if (memPercent < 50) return this.getColorRgba('widget-text-color', 0.6);
if (memPercent < 60) return '#f6f000';
if (memPercent < 80) return '#fca016';
if (memPercent < 100) return '#f80363';
return '#272f4d';
},
getMemoryGaugeLabel() {
const sys = this.server.nextcloud.system;
return `${this.convertBytes((sys.mem_total - sys.mem_free) * 1024, 2, false)} / `
+ `${this.convertBytes(sys.mem_total * 1024, 2, false)}`;
},
updateCpuLoad(load) {
const chartData = {
labels: ['1m', '5m', '15m'],
datasets: [{ values: [load[0], load[1], load[2]] }],
};
const chartTitle = this.tt('load-averages');
this.renderCpuLoadChart(chartData, chartTitle);
},
renderCpuLoadChart(loadBarChartData, chartTitle) {
return new this.Chart(`#${this.cpuLoadChartId}`, {
title: chartTitle,
data: loadBarChartData,
type: 'bar',
height: 180,
colors: [this.getColorRgba('widget-text-color', 0.6)],
barOptions: {
spaceRatio: 0.2,
},
tooltipOptions: {
formatTooltipY: d => `${d} ${this.tt('tasks')}`,
},
});
},
},
created() {
this.overrideUpdateInterval = 30;
},
updated() {
const load = this?.server?.nextcloud?.system?.cpuload;
if (load) this.updateCpuLoad(load);
const sys = this.server.nextcloud.system;
if (sys) this.updateMemoryGauge(sys);
},
};
</script>
<style scoped lang="scss">
@import '@/styles/widgets/nextcloud-shared.scss';
.nextcloud-system-wrapper {
div.charts {
> div {
float: left;
}
> div:first-child {
max-width: 44%;
small {
font-size: 12px;
color: #999999;
display: inline-block;
width: 100%;
text-align: center;
margin: .69rem 0 1rem 0;
}
small:last-child {
margin-top: 16px;
font-size: 10px;
}
}
> div:nth-child(2) {
min-width: 55%;
}
p.percentage {
color: var(--widget-text-color);
text-align: center;
position: absolute;
font-size: 1.3rem;
margin: 0.5rem 0;
width: 100%;
bottom: 0;
}
}
}
</style>