Improve admin dashboard
This commit is contained in:
parent
f9f2ca51ac
commit
aadd5b95b8
|
@ -1082,6 +1082,8 @@ admin/views/dashboard.vue:
|
|||
dashboard: "ダッシュボード"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
|
|
113
src/client/app/admin/views/ap-log.vue
Normal file
113
src/client/app/admin/views/ap-log.vue
Normal file
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div class="hyhctythnmwihguaaapnbrbszsjqxpio">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>%fa:exchange-alt% In/Out</th>
|
||||
<th>%fa:server% Host</th>
|
||||
<th>%fa:bolt% Activity</th>
|
||||
<th>%fa:user% Actor</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="log in logs" :key="log.id">
|
||||
<td :class="log.direction">{{ log.direction == 'in' ? '<' : '>' }} {{ log.direction }}</td>
|
||||
<td>{{ log.host }}</td>
|
||||
<td>{{ log.activity }}</td>
|
||||
<td>@{{ log.actor }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
logs: [],
|
||||
connection: null
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.connection = (this as any).os.stream.useSharedConnection('apLog');
|
||||
this.connection.on('stats', this.onLog);
|
||||
this.connection.on('statsLog', this.onLogs);
|
||||
this.connection.send('requestLog', {
|
||||
id: Math.random().toString().substr(2, 8),
|
||||
length: 50
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
this.onLog({
|
||||
direction: ['in', 'out'][Math.floor(Math.random() * 2)],
|
||||
activity: 'Create',
|
||||
host: 'misskey.ai',
|
||||
actor: 'foobar'
|
||||
});
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.connection.dispose();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onLog(log) {
|
||||
log.id = Math.random();
|
||||
this.logs.unshift(log);
|
||||
if (this.logs.length > 50) this.logs.pop();
|
||||
},
|
||||
|
||||
onLogs(logs) {
|
||||
logs.reverse().forEach(log => this.onLog(log));
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.hyhctythnmwihguaaapnbrbszsjqxpio
|
||||
display block
|
||||
padding 16px
|
||||
height 250px
|
||||
overflow auto
|
||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||
background var(--face)
|
||||
border-radius 8px
|
||||
|
||||
> table
|
||||
width 100%
|
||||
max-width 100%
|
||||
overflow auto
|
||||
border-spacing 0
|
||||
border-collapse collapse
|
||||
color #555
|
||||
|
||||
thead
|
||||
font-weight bold
|
||||
border-bottom solid 2px #eee
|
||||
|
||||
tr
|
||||
th
|
||||
text-align left
|
||||
|
||||
tbody
|
||||
tr
|
||||
&:nth-child(odd)
|
||||
background #fbfbfb
|
||||
|
||||
th, td
|
||||
padding 8px 16px
|
||||
min-width 128px
|
||||
|
||||
td.in
|
||||
color #d26755
|
||||
|
||||
td.out
|
||||
color #55bb83
|
||||
|
||||
</style>
|
|
@ -7,6 +7,7 @@
|
|||
<p><b>Node</b><span>{{ meta.node }}</span></p>
|
||||
<p>藍ちゃかわいい</p>
|
||||
</header>
|
||||
|
||||
<div v-if="stats" class="stats">
|
||||
<div>
|
||||
<div>
|
||||
|
@ -34,22 +35,22 @@
|
|||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>%fa:user%</div>
|
||||
<div>%fa:database%</div>
|
||||
<div>
|
||||
<span>%i18n:@accounts%</span>
|
||||
<b>{{ stats.usersCount | number }}</b>
|
||||
<span>%i18n:@drive%</span>
|
||||
<b>{{ stats.driveUsageLocal | bytes }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>%fa:globe% %i18n:@federated%</span>
|
||||
<span>%fa:home% %i18n:@this-instance%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>%fa:pencil-alt%</div>
|
||||
<div>%fa:hdd R%</div>
|
||||
<div>
|
||||
<span>%i18n:@notes%</span>
|
||||
<b>{{ stats.notesCount | number }}</b>
|
||||
<span>%i18n:@instances%</span>
|
||||
<b>{{ stats.instances | number }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -65,6 +66,10 @@
|
|||
<div class="cpu-memory">
|
||||
<x-cpu-memory :connection="connection"/>
|
||||
</div>
|
||||
|
||||
<div class="ap">
|
||||
<x-ap-log/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -72,11 +77,13 @@
|
|||
import Vue from "vue";
|
||||
import XCpuMemory from "./cpu-memory.vue";
|
||||
import XCharts from "./charts.vue";
|
||||
import XApLog from "./ap-log.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XCpuMemory,
|
||||
XCharts
|
||||
XCharts,
|
||||
XApLog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
Vue.filter('bytes', (v, digits = 0) => {
|
||||
if (v == null) return '?';
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (v == 0) return '0';
|
||||
const isMinus = v < 0;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
Vue.filter('number', (n) => {
|
||||
if (n == null) return 'N/A';
|
||||
return n.toLocaleString();
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ import perform from '../../../remote/activitypub/perform';
|
|||
import { resolvePerson, updatePerson } from '../../../remote/activitypub/models/person';
|
||||
import { toUnicode } from 'punycode';
|
||||
import { URL } from 'url';
|
||||
import { publishApLogStream } from '../../../stream';
|
||||
|
||||
const log = debug('misskey:queue:inbox');
|
||||
|
||||
|
@ -61,6 +62,15 @@ export default async (job: bq.Job, done: any): Promise<void> => {
|
|||
}) as IRemoteUser;
|
||||
}
|
||||
|
||||
//#region Log
|
||||
publishApLogStream({
|
||||
direction: 'in',
|
||||
activity: activity.type,
|
||||
host: user.host,
|
||||
actor: user.username
|
||||
});
|
||||
//#endregion
|
||||
|
||||
// Update activityの場合は、ここで署名検証/更新処理まで実施して終了
|
||||
if (activity.type === 'Update') {
|
||||
if (activity.object && activity.object.type === 'Person') {
|
||||
|
|
|
@ -6,6 +6,7 @@ const crypto = require('crypto');
|
|||
|
||||
import config from '../../config';
|
||||
import { ILocalUser } from '../../models/user';
|
||||
import { publishApLogStream } from '../../stream';
|
||||
|
||||
const log = debug('misskey:activitypub:deliver');
|
||||
|
||||
|
@ -64,4 +65,13 @@ export default (user: ILocalUser, url: string, object: any) => new Promise((reso
|
|||
});
|
||||
|
||||
req.end(data);
|
||||
|
||||
//#region Log
|
||||
publishApLogStream({
|
||||
direction: 'out',
|
||||
activity: object.type,
|
||||
host: null,
|
||||
actor: user.username
|
||||
});
|
||||
//#endregion
|
||||
});
|
||||
|
|
24
src/server/api/stream/channels/ap-log.ts
Normal file
24
src/server/api/stream/channels/ap-log.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import autobind from 'autobind-decorator';
|
||||
import Channel from '../channel';
|
||||
|
||||
export default class extends Channel {
|
||||
public readonly chName = 'apLog';
|
||||
public static shouldShare = true;
|
||||
|
||||
@autobind
|
||||
public async init(params: any) {
|
||||
// Subscribe events
|
||||
this.subscriber.on('apLog', this.onLog);
|
||||
}
|
||||
|
||||
@autobind
|
||||
private async onLog(log: any) {
|
||||
this.send('log', log);
|
||||
}
|
||||
|
||||
@autobind
|
||||
public dispose() {
|
||||
// Unsubscribe events
|
||||
this.subscriber.off('apLog', this.onLog);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import messaging from './messaging';
|
|||
import messagingIndex from './messaging-index';
|
||||
import drive from './drive';
|
||||
import hashtag from './hashtag';
|
||||
import apLog from './ap-log';
|
||||
import gamesReversi from './games/reversi';
|
||||
import gamesReversiGame from './games/reversi-game';
|
||||
|
||||
|
@ -26,6 +27,7 @@ export default {
|
|||
messagingIndex,
|
||||
drive,
|
||||
hashtag,
|
||||
apLog,
|
||||
gamesReversi,
|
||||
gamesReversiGame
|
||||
};
|
||||
|
|
|
@ -100,6 +100,10 @@ class Publisher {
|
|||
public publishHashtagStream = (note: any): void => {
|
||||
this.publish('hashtag', null, note);
|
||||
}
|
||||
|
||||
public publishApLogStream = (log: any): void => {
|
||||
this.publish('apLog', null, log);
|
||||
}
|
||||
}
|
||||
|
||||
const publisher = new Publisher();
|
||||
|
@ -119,3 +123,4 @@ export const publishLocalTimelineStream = publisher.publishLocalTimelineStream;
|
|||
export const publishHybridTimelineStream = publisher.publishHybridTimelineStream;
|
||||
export const publishGlobalTimelineStream = publisher.publishGlobalTimelineStream;
|
||||
export const publishHashtagStream = publisher.publishHashtagStream;
|
||||
export const publishApLogStream = publisher.publishApLogStream;
|
||||
|
|
Loading…
Reference in a new issue