diff options
Diffstat (limited to 'src/client/components/instance-stats.vue')
| -rw-r--r-- | src/client/components/instance-stats.vue | 487 |
1 files changed, 15 insertions, 472 deletions
diff --git a/src/client/components/instance-stats.vue b/src/client/components/instance-stats.vue index 5e7c71ea65..fd0b75609f 100644 --- a/src/client/components/instance-stats.vue +++ b/src/client/components/instance-stats.vue @@ -24,35 +24,26 @@ <option value="drive-total">{{ $ts._charts.storageUsageTotal }}</option> </optgroup> </MkSelect> - <MkSelect v-model="chartSpan" style="margin: 0;"> + <MkSelect v-model="chartSpan" style="margin: 0 0 0 10px;"> <option value="hour">{{ $ts.perHour }}</option> <option value="day">{{ $ts.perDay }}</option> </MkSelect> </div> - <canvas ref="chart"></canvas> + <MkChart :src="chartSrc" :span="chartSpan" :limit="chartLimit" :detailed="detailed"></MkChart> </div> </template> <script lang="ts"> -import { defineComponent, markRaw } from 'vue'; -import Chart from 'chart.js'; -import MkSelect from './form/select.vue'; -import number from '@client/filters/number'; - -const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); -const negate = arr => arr.map(x => -x); -const alpha = (hex, a) => { - const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!; - const r = parseInt(result[1], 16); - const g = parseInt(result[2], 16); - const b = parseInt(result[3], 16); - return `rgba(${r}, ${g}, ${b}, ${a})`; -}; +import { defineComponent, onMounted, ref, watch } from 'vue'; +import MkSelect from '@client/components/form/select.vue'; +import MkChart from '@client/components/chart.vue'; import * as os from '@client/os'; +import { defaultStore } from '@client/store'; export default defineComponent({ components: { - MkSelect + MkSelect, + MkChart, }, props: { @@ -68,463 +59,15 @@ export default defineComponent({ }, }, - data() { - return { - notesLocalWoW: 0, - notesLocalDoD: 0, - notesRemoteWoW: 0, - notesRemoteDoD: 0, - usersLocalWoW: 0, - usersLocalDoD: 0, - usersRemoteWoW: 0, - usersRemoteDoD: 0, - now: null, - chart: null, - chartInstance: null, - chartSrc: 'notes', - chartSpan: 'hour', - } - }, - - computed: { - data(): any { - if (this.chart == null) return null; - switch (this.chartSrc) { - case 'federation-instances': return this.federationInstancesChart(false); - case 'federation-instances-total': return this.federationInstancesChart(true); - case 'users': return this.usersChart(false); - case 'users-total': return this.usersChart(true); - case 'active-users': return this.activeUsersChart(); - case 'notes': return this.notesChart('combined'); - case 'local-notes': return this.notesChart('local'); - case 'remote-notes': return this.notesChart('remote'); - case 'notes-total': return this.notesTotalChart(); - case 'drive': return this.driveChart(); - case 'drive-total': return this.driveTotalChart(); - case 'drive-files': return this.driveFilesChart(); - case 'drive-files-total': return this.driveFilesTotalChart(); - } - }, - - stats(): any[] { - const stats = - this.chartSpan == 'day' ? this.chart.perDay : - this.chartSpan == 'hour' ? this.chart.perHour : - null; - - return stats; - } - }, - - watch: { - chartSrc() { - this.renderChart(); - }, - - chartSpan() { - this.renderChart(); - } - }, - - async created() { - this.now = new Date(); + setup() { + const chartSpan = ref<'hour' | 'day'>('hour'); + const chartSrc = ref('notes'); - this.fetchChart(); + return { + chartSrc, + chartSpan, + }; }, - - methods: { - async fetchChart() { - const [perHour, perDay] = await Promise.all([Promise.all([ - os.api('charts/federation', { limit: this.chartLimit, span: 'hour' }), - os.api('charts/users', { limit: this.chartLimit, span: 'hour' }), - os.api('charts/active-users', { limit: this.chartLimit, span: 'hour' }), - os.api('charts/notes', { limit: this.chartLimit, span: 'hour' }), - os.api('charts/drive', { limit: this.chartLimit, span: 'hour' }), - ]), Promise.all([ - os.api('charts/federation', { limit: this.chartLimit, span: 'day' }), - os.api('charts/users', { limit: this.chartLimit, span: 'day' }), - os.api('charts/active-users', { limit: this.chartLimit, span: 'day' }), - os.api('charts/notes', { limit: this.chartLimit, span: 'day' }), - os.api('charts/drive', { limit: this.chartLimit, span: 'day' }), - ])]); - - const chart = { - perHour: { - federation: perHour[0], - users: perHour[1], - activeUsers: perHour[2], - notes: perHour[3], - drive: perHour[4], - }, - perDay: { - federation: perDay[0], - users: perDay[1], - activeUsers: perDay[2], - notes: perDay[3], - drive: perDay[4], - } - }; - - this.chart = chart; - - this.renderChart(); - }, - - renderChart() { - if (this.chartInstance) { - this.chartInstance.destroy(); - } - - // TODO: var(--panel)の色が暗いか明るいかで判定する - const gridColor = this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; - - Chart.defaults.global.defaultFontColor = getComputedStyle(document.documentElement).getPropertyValue('--fg'); - this.chartInstance = markRaw(new Chart(this.$refs.chart, { - type: 'line', - data: { - labels: new Array(this.chartLimit).fill(0).map((_, i) => this.getDate(i).toLocaleString()).slice().reverse(), - datasets: this.data.series.map(x => ({ - label: x.name, - data: x.data.slice().reverse(), - pointRadius: 0, - lineTension: 0, - borderWidth: 2, - borderColor: x.color, - borderDash: x.borderDash || [], - backgroundColor: alpha(x.color, 0.1), - fill: x.fill == null ? true : x.fill, - hidden: !!x.hidden - })) - }, - options: { - aspectRatio: 2.5, - layout: { - padding: { - left: 16, - right: 16, - top: 16, - bottom: 8 - } - }, - legend: { - position: 'bottom', - labels: { - boxWidth: 16, - } - }, - scales: { - xAxes: [{ - type: 'time', - time: { - stepSize: 1, - unit: this.chartSpan == 'day' ? 'month' : 'day', - }, - gridLines: { - display: this.detailed, - color: gridColor, - zeroLineColor: gridColor, - }, - ticks: { - display: this.detailed - } - }], - yAxes: [{ - position: 'left', - gridLines: { - color: gridColor, - zeroLineColor: gridColor, - }, - ticks: { - display: this.detailed - } - }] - }, - tooltips: { - intersect: false, - mode: 'index', - } - } - })); - }, - - getDate(ago: number) { - const y = this.now.getFullYear(); - const m = this.now.getMonth(); - const d = this.now.getDate(); - const h = this.now.getHours(); - - return this.chartSpan == 'day' ? new Date(y, m, d - ago) : new Date(y, m, d, h - ago); - }, - - format(arr) { - const now = Date.now(); - return arr.map((v, i) => ({ - x: new Date(now - ((this.chartSpan == 'day' ? 86400000 :3600000 ) * i)), - y: v - })); - }, - - federationInstancesChart(total: boolean): any { - return { - series: [{ - name: 'Instances', - color: '#008FFB', - data: this.format(total - ? this.stats.federation.instance.total - : sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec)) - ) - }] - }; - }, - - notesChart(type: string): any { - return { - series: [{ - name: 'All', - type: 'line', - color: '#008FFB', - borderDash: [5, 5], - fill: false, - data: this.format(type == 'combined' - ? sum(this.stats.notes.local.inc, negate(this.stats.notes.local.dec), this.stats.notes.remote.inc, negate(this.stats.notes.remote.dec)) - : sum(this.stats.notes[type].inc, negate(this.stats.notes[type].dec)) - ) - }, { - name: 'Renotes', - type: 'area', - color: '#00E396', - data: this.format(type == 'combined' - ? sum(this.stats.notes.local.diffs.renote, this.stats.notes.remote.diffs.renote) - : this.stats.notes[type].diffs.renote - ) - }, { - name: 'Replies', - type: 'area', - color: '#FEB019', - data: this.format(type == 'combined' - ? sum(this.stats.notes.local.diffs.reply, this.stats.notes.remote.diffs.reply) - : this.stats.notes[type].diffs.reply - ) - }, { - name: 'Normal', - type: 'area', - color: '#FF4560', - data: this.format(type == 'combined' - ? sum(this.stats.notes.local.diffs.normal, this.stats.notes.remote.diffs.normal) - : this.stats.notes[type].diffs.normal - ) - }] - }; - }, - - notesTotalChart(): any { - return { - series: [{ - name: 'Combined', - type: 'line', - color: '#008FFB', - data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total)) - }, { - name: 'Local', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.notes.local.total) - }, { - name: 'Remote', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.notes.remote.total) - }] - }; - }, - - usersChart(total: boolean): any { - return { - series: [{ - name: 'Combined', - type: 'line', - color: '#008FFB', - data: this.format(total - ? sum(this.stats.users.local.total, this.stats.users.remote.total) - : sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec)) - ) - }, { - name: 'Local', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(total - ? this.stats.users.local.total - : sum(this.stats.users.local.inc, negate(this.stats.users.local.dec)) - ) - }, { - name: 'Remote', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(total - ? this.stats.users.remote.total - : sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec)) - ) - }] - }; - }, - - activeUsersChart(): any { - return { - series: [{ - name: 'Combined', - type: 'line', - color: '#008FFB', - data: this.format(sum(this.stats.activeUsers.local.count, this.stats.activeUsers.remote.count)) - }, { - name: 'Local', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.activeUsers.local.count) - }, { - name: 'Remote', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.activeUsers.remote.count) - }] - }; - }, - - driveChart(): any { - return { - bytes: true, - series: [{ - name: 'All', - type: 'line', - color: '#09d8e2', - borderDash: [5, 5], - fill: false, - data: this.format( - sum( - this.stats.drive.local.incSize, - negate(this.stats.drive.local.decSize), - this.stats.drive.remote.incSize, - negate(this.stats.drive.remote.decSize) - ) - ) - }, { - name: 'Local +', - type: 'area', - color: '#008FFB', - data: this.format(this.stats.drive.local.incSize) - }, { - name: 'Local -', - type: 'area', - color: '#FF4560', - data: this.format(negate(this.stats.drive.local.decSize)) - }, { - name: 'Remote +', - type: 'area', - color: '#00E396', - data: this.format(this.stats.drive.remote.incSize) - }, { - name: 'Remote -', - type: 'area', - color: '#FEB019', - data: this.format(negate(this.stats.drive.remote.decSize)) - }] - }; - }, - - driveTotalChart(): any { - return { - bytes: true, - series: [{ - name: 'Combined', - type: 'line', - color: '#008FFB', - data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize)) - }, { - name: 'Local', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.drive.local.totalSize) - }, { - name: 'Remote', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.drive.remote.totalSize) - }] - }; - }, - - driveFilesChart(): any { - return { - series: [{ - name: 'All', - type: 'line', - color: '#09d8e2', - borderDash: [5, 5], - fill: false, - data: this.format( - sum( - this.stats.drive.local.incCount, - negate(this.stats.drive.local.decCount), - this.stats.drive.remote.incCount, - negate(this.stats.drive.remote.decCount) - ) - ) - }, { - name: 'Local +', - type: 'area', - color: '#008FFB', - data: this.format(this.stats.drive.local.incCount) - }, { - name: 'Local -', - type: 'area', - color: '#FF4560', - data: this.format(negate(this.stats.drive.local.decCount)) - }, { - name: 'Remote +', - type: 'area', - color: '#00E396', - data: this.format(this.stats.drive.remote.incCount) - }, { - name: 'Remote -', - type: 'area', - color: '#FEB019', - data: this.format(negate(this.stats.drive.remote.decCount)) - }] - }; - }, - - driveFilesTotalChart(): any { - return { - series: [{ - name: 'Combined', - type: 'line', - color: '#008FFB', - data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount)) - }, { - name: 'Local', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.drive.local.totalCount) - }, { - name: 'Remote', - type: 'area', - color: '#008FFB', - hidden: true, - data: this.format(this.stats.drive.remote.totalCount) - }] - }; - }, - - number - } }); </script> |