wip
This commit is contained in:
@ -29,7 +29,7 @@ import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
data: {
|
||||
chart: {
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
@ -39,7 +39,6 @@ export default Vue.extend({
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: this.data,
|
||||
viewBoxX: 365,
|
||||
viewBoxY: 70,
|
||||
pointsNote: null,
|
||||
@ -49,21 +48,17 @@ export default Vue.extend({
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.chart.forEach(d => {
|
||||
d.notes = this.type == 'local' ? d.localNotes : d.remoteNotes;
|
||||
d.replies = this.type == 'local' ? d.localReplies : d.remoteReplies;
|
||||
d.renotes = this.type == 'local' ? d.localRenotes : d.remoteRenotes;
|
||||
});
|
||||
|
||||
this.chart.forEach(d => {
|
||||
d.total = d.notes + d.replies + d.renotes;
|
||||
});
|
||||
|
||||
const peak = Math.max.apply(null, this.chart.map(d => d.total));
|
||||
const peak = Math.max.apply(null, this.chart.map(d => this.type == 'local' ? d.notes.local.diff : d.notes.remote.diff));
|
||||
|
||||
if (peak != 0) {
|
||||
const data = this.chart.slice().reverse();
|
||||
this.pointsNote = data.map((d, i) => `${i},${(1 - (d.notes / peak)) * this.viewBoxY}`).join(' ');
|
||||
const data = this.chart.slice().reverse().map(x => ({
|
||||
normal: this.type == 'local' ? x.notes.local.diffs.normal : x.notes.remote.diffs.normal,
|
||||
replies: this.type == 'local' ? x.notes.local.diffs.replies : x.notes.remote.diffs.replies,
|
||||
renotes: this.type == 'local' ? x.notes.local.diffs.renotes : x.notes.remote.diffs.renotes,
|
||||
total: this.type == 'local' ? x.notes.local.diff : x.notes.remote.diff
|
||||
}));
|
||||
|
||||
this.pointsNote = data.map((d, i) => `${i},${(1 - (d.normal / peak)) * this.viewBoxY}`).join(' ');
|
||||
this.pointsReply = data.map((d, i) => `${i},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' ');
|
||||
this.pointsRenote = data.map((d, i) => `${i},${(1 - (d.renotes / peak)) * this.viewBoxY}`).join(' ');
|
||||
this.pointsTotal = data.map((d, i) => `${i},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ');
|
||||
|
@ -3,11 +3,11 @@
|
||||
<header>%i18n:@title%</header>
|
||||
<div class="card">
|
||||
<header>%i18n:@local%</header>
|
||||
<x-chart v-if="data" :data="data" type="local"/>
|
||||
<x-chart v-if="chart" :chart="chart" type="local"/>
|
||||
</div>
|
||||
<div class="card">
|
||||
<header>%i18n:@remote%</header>
|
||||
<x-chart v-if="data" :data="data" type="remote"/>
|
||||
<x-chart v-if="chart" :chart="chart" type="remote"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -20,15 +20,10 @@ export default Vue.extend({
|
||||
components: {
|
||||
XChart
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
(this as any).api('aggregation/notes').then(res => {
|
||||
this.data = res;
|
||||
});
|
||||
props: {
|
||||
chart: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -13,7 +13,7 @@ import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
data: {
|
||||
chart: {
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
@ -23,21 +23,19 @@ export default Vue.extend({
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chart: this.data,
|
||||
viewBoxX: 365,
|
||||
viewBoxY: 70,
|
||||
points: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.chart.forEach(d => {
|
||||
d.count = this.type == 'local' ? d.local : d.remote;
|
||||
});
|
||||
|
||||
const peak = Math.max.apply(null, this.chart.map(d => d.count));
|
||||
const peak = Math.max.apply(null, this.chart.map(d => this.type == 'local' ? d.users.local.diff : d.users.remote.diff));
|
||||
|
||||
if (peak != 0) {
|
||||
const data = this.chart.slice().reverse();
|
||||
const data = this.chart.slice().reverse().map(x => ({
|
||||
count: this.type == 'local' ? x.users.local.diff : x.users.remote.diff
|
||||
}));
|
||||
|
||||
this.points = data.map((d, i) => `${i},${(1 - (d.count / peak)) * this.viewBoxY}`).join(' ');
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,11 @@
|
||||
<header>%i18n:@title%</header>
|
||||
<div class="card">
|
||||
<header>%i18n:@local%</header>
|
||||
<x-chart v-if="data" :data="data" type="local"/>
|
||||
<x-chart v-if="chart" :chart="chart" type="local"/>
|
||||
</div>
|
||||
<div class="card">
|
||||
<header>%i18n:@remote%</header>
|
||||
<x-chart v-if="data" :data="data" type="remote"/>
|
||||
<x-chart v-if="chart" :chart="chart" type="remote"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -20,15 +20,10 @@ export default Vue.extend({
|
||||
components: {
|
||||
XChart
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
(this as any).api('aggregation/users').then(res => {
|
||||
this.data = res;
|
||||
});
|
||||
props: {
|
||||
chart: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -11,8 +11,8 @@
|
||||
<main>
|
||||
<div v-show="page == 'dashboard'">
|
||||
<x-dashboard/>
|
||||
<x-users-chart/>
|
||||
<x-notes-chart/>
|
||||
<x-users-chart :chart="chart"/>
|
||||
<x-notes-chart :chart="chart"/>
|
||||
</div>
|
||||
<div v-if="page == 'users'">
|
||||
<x-suspend-user/>
|
||||
@ -48,9 +48,15 @@ export default Vue.extend({
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page: 'dashboard'
|
||||
page: 'dashboard',
|
||||
chart: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
(this as any).api('admin/chart').then(chart => {
|
||||
this.chart = chart;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
nav(page: string) {
|
||||
this.page = page;
|
||||
|
@ -1,10 +0,0 @@
|
||||
@import "../app"
|
||||
@import "../reset"
|
||||
|
||||
html
|
||||
color #456267
|
||||
background #fff
|
||||
|
||||
body
|
||||
margin 0
|
||||
padding 0
|
@ -1,209 +0,0 @@
|
||||
<mk-index>
|
||||
<h1>Misskey<i>Statistics</i></h1>
|
||||
<main v-if="!initializing">
|
||||
<mk-users stats={ stats }/>
|
||||
<mk-notes stats={ stats }/>
|
||||
</main>
|
||||
<footer><a href={ _URL_ }>{ _HOST_ }</a></footer>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
margin 0 auto
|
||||
padding 0 16px
|
||||
max-width 700px
|
||||
|
||||
> h1
|
||||
margin 0
|
||||
padding 24px 0 0 0
|
||||
font-size 24px
|
||||
font-weight normal
|
||||
|
||||
> i
|
||||
font-style normal
|
||||
color #f43b16
|
||||
|
||||
> main
|
||||
> *
|
||||
margin 24px 0
|
||||
padding-top 24px
|
||||
border-top solid 1px #eee
|
||||
|
||||
> h2
|
||||
margin 0 0 12px 0
|
||||
font-size 18px
|
||||
font-weight normal
|
||||
|
||||
> footer
|
||||
margin 24px 0
|
||||
text-align center
|
||||
|
||||
> a
|
||||
color #546567
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.mixin('api');
|
||||
|
||||
this.initializing = true;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.$root.$data.os.api('stats').then(stats => {
|
||||
this.update({
|
||||
initializing: false,
|
||||
stats
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</mk-index>
|
||||
|
||||
<mk-notes>
|
||||
<h2>%i18n:stats.notes-count% <b>{ stats.notesCount }</b></h2>
|
||||
<mk-notes-chart v-if="!initializing" data={ data }/>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.mixin('api');
|
||||
|
||||
this.initializing = true;
|
||||
this.stats = this.opts.stats;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.$root.$data.os.api('aggregation/notes', {
|
||||
limit: 365
|
||||
}).then(data => {
|
||||
this.update({
|
||||
initializing: false,
|
||||
data
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</mk-notes>
|
||||
|
||||
<mk-users>
|
||||
<h2>%i18n:stats.users-count% <b>{ stats.usersCount }</b></h2>
|
||||
<mk-users-chart v-if="!initializing" data={ data }/>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.mixin('api');
|
||||
|
||||
this.initializing = true;
|
||||
this.stats = this.opts.stats;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.$root.$data.os.api('aggregation/users', {
|
||||
limit: 365
|
||||
}).then(data => {
|
||||
this.update({
|
||||
initializing: false,
|
||||
data
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</mk-users>
|
||||
|
||||
<mk-notes-chart>
|
||||
<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none">
|
||||
<title>Black ... Total<br/>Blue ... Notes<br/>Red ... Replies<br/>Green ... Renotes</title>
|
||||
<polyline
|
||||
riot-points={ pointsNote }
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#41ddde"/>
|
||||
<polyline
|
||||
riot-points={ pointsReply }
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#f7796c"/>
|
||||
<polyline
|
||||
riot-points={ pointsRenote }
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#a1de41"/>
|
||||
<polyline
|
||||
riot-points={ pointsTotal }
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#555"
|
||||
stroke-dasharray="2 2"/>
|
||||
</svg>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
|
||||
> svg
|
||||
display block
|
||||
padding 1px
|
||||
width 100%
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.viewBoxX = 365;
|
||||
this.viewBoxY = 80;
|
||||
|
||||
this.data = this.opts.data.reverse();
|
||||
this.data.forEach(d => d.total = d.notes + d.replies + d.renotes);
|
||||
const peak = Math.max.apply(null, this.data.map(d => d.total));
|
||||
|
||||
this.on('mount', () => {
|
||||
this.render();
|
||||
});
|
||||
|
||||
this.render = () => {
|
||||
this.update({
|
||||
pointsNote: this.data.map((d, i) => `${i},${(1 - (d.notes / peak)) * this.viewBoxY}`).join(' '),
|
||||
pointsReply: this.data.map((d, i) => `${i},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' '),
|
||||
pointsRenote: this.data.map((d, i) => `${i},${(1 - (d.renotes / peak)) * this.viewBoxY}`).join(' '),
|
||||
pointsTotal: this.data.map((d, i) => `${i},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ')
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</mk-notes-chart>
|
||||
|
||||
<mk-users-chart>
|
||||
<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none">
|
||||
<polyline
|
||||
riot-points={ createdPoints }
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#1cde84"/>
|
||||
<polyline
|
||||
riot-points={ totalPoints }
|
||||
fill="none"
|
||||
stroke-width="1"
|
||||
stroke="#555"/>
|
||||
</svg>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
|
||||
> svg
|
||||
display block
|
||||
padding 1px
|
||||
width 100%
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.viewBoxX = 365;
|
||||
this.viewBoxY = 80;
|
||||
|
||||
this.data = this.opts.data.reverse();
|
||||
const totalPeak = Math.max.apply(null, this.data.map(d => d.total));
|
||||
const createdPeak = Math.max.apply(null, this.data.map(d => d.created));
|
||||
|
||||
this.on('mount', () => {
|
||||
this.render();
|
||||
});
|
||||
|
||||
this.render = () => {
|
||||
this.update({
|
||||
totalPoints: this.data.map((d, i) => `${i},${(1 - (d.total / totalPeak)) * this.viewBoxY}`).join(' '),
|
||||
createdPoints: this.data.map((d, i) => `${i},${(1 - (d.created / createdPeak)) * this.viewBoxY}`).join(' ')
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</mk-users-chart>
|
@ -1 +0,0 @@
|
||||
require('./index.tag');
|
@ -1,10 +0,0 @@
|
||||
@import "../app"
|
||||
@import "../reset"
|
||||
|
||||
html
|
||||
color #456267
|
||||
background #fff
|
||||
|
||||
body
|
||||
margin 0
|
||||
padding 0
|
@ -1,201 +0,0 @@
|
||||
<mk-index>
|
||||
<h1>Misskey<i>Status</i></h1>
|
||||
<p>%fa:info-circle%%i18n:status.all-systems-maybe-operational%</p>
|
||||
<main>
|
||||
<mk-cpu-usage connection={ connection }/>
|
||||
<mk-mem-usage connection={ connection }/>
|
||||
</main>
|
||||
<footer><a href={ _URL_ }>{ _HOST_ }</a></footer>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
margin 0 auto
|
||||
padding 0 16px
|
||||
max-width 700px
|
||||
|
||||
> h1
|
||||
margin 0
|
||||
padding 24px 0 16px 0
|
||||
font-size 24px
|
||||
font-weight normal
|
||||
|
||||
> [data-fa]
|
||||
font-style normal
|
||||
color #f43b16
|
||||
|
||||
> p
|
||||
display block
|
||||
margin 0
|
||||
padding 12px 16px
|
||||
background #eaf4ef
|
||||
//border solid 1px #99ccb2
|
||||
border-radius 4px
|
||||
|
||||
> [data-fa]
|
||||
margin-right 5px
|
||||
|
||||
> main
|
||||
> *
|
||||
margin 24px 0
|
||||
|
||||
> h2
|
||||
margin 0 0 12px 0
|
||||
font-size 18px
|
||||
font-weight normal
|
||||
|
||||
> footer
|
||||
margin 24px 0
|
||||
text-align center
|
||||
|
||||
> a
|
||||
color #546567
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
import Connection from '../../common/scripts/streaming/server-stream';
|
||||
|
||||
this.mixin('api');
|
||||
|
||||
this.initializing = true;
|
||||
this.connection = new Connection();
|
||||
|
||||
this.on('mount', () => {
|
||||
this.$root.$data.os.api('meta').then(meta => {
|
||||
this.update({
|
||||
initializing: false,
|
||||
meta
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.on('unmount', () => {
|
||||
this.connection.close();
|
||||
});
|
||||
|
||||
</script>
|
||||
</mk-index>
|
||||
|
||||
<mk-cpu-usage>
|
||||
<h2>CPU <b>{ percentage }%</b></h2>
|
||||
<mk-line-chart ref="chart"/>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.connection = this.opts.connection;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.connection.on('stats', this.onStats);
|
||||
});
|
||||
|
||||
this.on('unmount', () => {
|
||||
this.connection.off('stats', this.onStats);
|
||||
});
|
||||
|
||||
this.onStats = stats => {
|
||||
this.$refs.chart.addData(1 - stats.cpu_usage);
|
||||
|
||||
const percentage = (stats.cpu_usage * 100).toFixed(0);
|
||||
|
||||
this.update({
|
||||
percentage
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</mk-cpu-usage>
|
||||
|
||||
<mk-mem-usage>
|
||||
<h2>MEM <b>{ percentage }%</b></h2>
|
||||
<mk-line-chart ref="chart"/>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.connection = this.opts.connection;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.connection.on('stats', this.onStats);
|
||||
});
|
||||
|
||||
this.on('unmount', () => {
|
||||
this.connection.off('stats', this.onStats);
|
||||
});
|
||||
|
||||
this.onStats = stats => {
|
||||
stats.mem.used = stats.mem.total - stats.mem.free;
|
||||
this.$refs.chart.addData(1 - (stats.mem.used / stats.mem.total));
|
||||
|
||||
const percentage = (stats.mem.used / stats.mem.total * 100).toFixed(0);
|
||||
|
||||
this.update({
|
||||
percentage
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</mk-mem-usage>
|
||||
|
||||
<mk-line-chart>
|
||||
<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none">
|
||||
<defs>
|
||||
<linearGradient id={ gradientId } x1="0" x2="0" y1="1" y2="0">
|
||||
<stop offset="0%" stop-color="rgba(244, 59, 22, 0)"></stop>
|
||||
<stop offset="100%" stop-color="#f43b16"></stop>
|
||||
</linearGradient>
|
||||
<mask id={ maskId } x="0" y="0" riot-width={ viewBoxX } riot-height={ viewBoxY }>
|
||||
<polygon
|
||||
riot-points={ polygonPoints }
|
||||
fill="#fff"
|
||||
fill-opacity="0.5"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<line x1="0" y1="0" riot-x2={ viewBoxX } y2="0" stroke="rgba(255, 255, 255, 0.1)" stroke-width="0.25" stroke-dasharray="1"/>
|
||||
<line x1="0" y1="25%" riot-x2={ viewBoxX } y2="25%" stroke="rgba(255, 255, 255, 0.1)" stroke-width="0.25" stroke-dasharray="1"/>
|
||||
<line x1="0" y1="50%" riot-x2={ viewBoxX } y2="50%" stroke="rgba(255, 255, 255, 0.1)" stroke-width="0.25" stroke-dasharray="1"/>
|
||||
<line x1="0" y1="75%" riot-x2={ viewBoxX } y2="75%" stroke="rgba(255, 255, 255, 0.1)" stroke-width="0.25" stroke-dasharray="1"/>
|
||||
<line x1="0" y1="100%" riot-x2={ viewBoxX } y2="100%" stroke="rgba(255, 255, 255, 0.1)" stroke-width="0.25" stroke-dasharray="1"/>
|
||||
<rect
|
||||
x="-1" y="-1"
|
||||
riot-width={ viewBoxX + 2 } riot-height={ viewBoxY + 2 }
|
||||
style="stroke: none; fill: url(#{ gradientId }); mask: url(#{ maskId })"/>
|
||||
<polyline
|
||||
riot-points={ polylinePoints }
|
||||
fill="none"
|
||||
stroke="#f43b16"
|
||||
stroke-width="0.5"/>
|
||||
</svg>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
padding 16px
|
||||
border-radius 8px
|
||||
background #1c2531
|
||||
|
||||
> svg
|
||||
display block
|
||||
padding 1px
|
||||
width 100%
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
import uuid from 'uuid';
|
||||
|
||||
this.viewBoxX = 100;
|
||||
this.viewBoxY = 30;
|
||||
this.data = [];
|
||||
this.gradientId = uuid();
|
||||
this.maskId = uuid();
|
||||
|
||||
this.addData = data => {
|
||||
this.data.push(data);
|
||||
if (this.data.length > 100) this.data.shift();
|
||||
|
||||
const polylinePoints = this.data.map((d, i) => `${this.viewBoxX - ((this.data.length - 1) - i)},${d * this.viewBoxY}`).join(' ');
|
||||
const polygonPoints = `${this.viewBoxX - (this.data.length - 1)},${ this.viewBoxY } ${ polylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
|
||||
|
||||
this.update({
|
||||
polylinePoints,
|
||||
polygonPoints
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</mk-line-chart>
|
@ -1 +0,0 @@
|
||||
require('./index.tag');
|
Reference in New Issue
Block a user