wip
This commit is contained in:
		
							parent
							
								
									b4a874766e
								
							
						
					
					
						commit
						bc17a0b2cb
					
				
					 13 changed files with 618 additions and 539 deletions
				
			
		| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
export default (bytes, digits = 0) => {
 | 
			
		||||
	const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
 | 
			
		||||
	if (bytes == 0) return '0Byte';
 | 
			
		||||
	const i = Math.floor(Math.log(bytes) / Math.log(1024));
 | 
			
		||||
	return (bytes / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '') + sizes[i];
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,533 +0,0 @@
 | 
			
		|||
<mk-server-home-widget data-melt={ data.design == 2 }>
 | 
			
		||||
	<template v-if="data.design == 0">
 | 
			
		||||
		<p class="title">%fa:server%%i18n:desktop.tags.mk-server-home-widget.title%</p>
 | 
			
		||||
		<button @click="toggle" title="%i18n:desktop.tags.mk-server-home-widget.toggle%">%fa:sort%</button>
 | 
			
		||||
	</template>
 | 
			
		||||
	<p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 | 
			
		||||
	<mk-server-home-widget-cpu-and-memory-usage v-if="!initializing" show={ data.view == 0 } connection={ connection }/>
 | 
			
		||||
	<mk-server-home-widget-cpu v-if="!initializing" show={ data.view == 1 } connection={ connection } meta={ meta }/>
 | 
			
		||||
	<mk-server-home-widget-memory v-if="!initializing" show={ data.view == 2 } connection={ connection }/>
 | 
			
		||||
	<mk-server-home-widget-disk v-if="!initializing" show={ data.view == 3 } connection={ connection }/>
 | 
			
		||||
	<mk-server-home-widget-uptimes v-if="!initializing" show={ data.view == 4 } connection={ connection }/>
 | 
			
		||||
	<mk-server-home-widget-info v-if="!initializing" show={ data.view == 5 } connection={ connection } meta={ meta }/>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
			background #fff
 | 
			
		||||
			border solid 1px rgba(0, 0, 0, 0.075)
 | 
			
		||||
			border-radius 6px
 | 
			
		||||
 | 
			
		||||
			&[data-melt]
 | 
			
		||||
				background transparent !important
 | 
			
		||||
				border none !important
 | 
			
		||||
 | 
			
		||||
			> .title
 | 
			
		||||
				z-index 1
 | 
			
		||||
				margin 0
 | 
			
		||||
				padding 0 16px
 | 
			
		||||
				line-height 42px
 | 
			
		||||
				font-size 0.9em
 | 
			
		||||
				font-weight bold
 | 
			
		||||
				color #888
 | 
			
		||||
				box-shadow 0 1px rgba(0, 0, 0, 0.07)
 | 
			
		||||
 | 
			
		||||
				> [data-fa]
 | 
			
		||||
					margin-right 4px
 | 
			
		||||
 | 
			
		||||
			> button
 | 
			
		||||
				position absolute
 | 
			
		||||
				z-index 2
 | 
			
		||||
				top 0
 | 
			
		||||
				right 0
 | 
			
		||||
				padding 0
 | 
			
		||||
				width 42px
 | 
			
		||||
				font-size 0.9em
 | 
			
		||||
				line-height 42px
 | 
			
		||||
				color #ccc
 | 
			
		||||
 | 
			
		||||
				&:hover
 | 
			
		||||
					color #aaa
 | 
			
		||||
 | 
			
		||||
				&:active
 | 
			
		||||
					color #999
 | 
			
		||||
 | 
			
		||||
			> .initializing
 | 
			
		||||
				margin 0
 | 
			
		||||
				padding 16px
 | 
			
		||||
				text-align center
 | 
			
		||||
				color #aaa
 | 
			
		||||
 | 
			
		||||
				> [data-fa]
 | 
			
		||||
					margin-right 4px
 | 
			
		||||
 | 
			
		||||
	</style>
 | 
			
		||||
	<script lang="typescript">
 | 
			
		||||
		this.mixin('os');
 | 
			
		||||
 | 
			
		||||
		this.data = {
 | 
			
		||||
			view: 0,
 | 
			
		||||
			design: 0
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		this.mixin('widget');
 | 
			
		||||
 | 
			
		||||
		this.mixin('server-stream');
 | 
			
		||||
		this.connection = this.serverStream.getConnection();
 | 
			
		||||
		this.connectionId = this.serverStream.use();
 | 
			
		||||
 | 
			
		||||
		this.initializing = true;
 | 
			
		||||
 | 
			
		||||
		this.on('mount', () => {
 | 
			
		||||
			this.mios.getMeta().then(meta => {
 | 
			
		||||
				this.update({
 | 
			
		||||
					initializing: false,
 | 
			
		||||
					meta
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.on('unmount', () => {
 | 
			
		||||
			this.serverStream.dispose(this.connectionId);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.toggle = () => {
 | 
			
		||||
			this.data.view++;
 | 
			
		||||
			if (this.data.view == 6) this.data.view = 0;
 | 
			
		||||
 | 
			
		||||
			// Save widget state
 | 
			
		||||
			this.save();
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		this.func = () => {
 | 
			
		||||
			if (++this.data.design == 3) this.data.design = 0;
 | 
			
		||||
			this.save();
 | 
			
		||||
		};
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget>
 | 
			
		||||
 | 
			
		||||
<mk-server-home-widget-cpu-and-memory-usage>
 | 
			
		||||
	<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none">
 | 
			
		||||
		<defs>
 | 
			
		||||
			<linearGradient id={ cpuGradientId } x1="0" x2="0" y1="1" y2="0">
 | 
			
		||||
				<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="33%" stop-color="hsl(120, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="66%" stop-color="hsl(60, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
 | 
			
		||||
			</linearGradient>
 | 
			
		||||
			<mask id={ cpuMaskId } x="0" y="0" riot-width={ viewBoxX } riot-height={ viewBoxY }>
 | 
			
		||||
				<polygon
 | 
			
		||||
					riot-points={ cpuPolygonPoints }
 | 
			
		||||
					fill="#fff"
 | 
			
		||||
					fill-opacity="0.5"/>
 | 
			
		||||
				<polyline
 | 
			
		||||
					riot-points={ cpuPolylinePoints }
 | 
			
		||||
					fill="none"
 | 
			
		||||
					stroke="#fff"
 | 
			
		||||
					stroke-width="1"/>
 | 
			
		||||
			</mask>
 | 
			
		||||
		</defs>
 | 
			
		||||
		<rect
 | 
			
		||||
			x="-1" y="-1"
 | 
			
		||||
			riot-width={ viewBoxX + 2 } riot-height={ viewBoxY + 2 }
 | 
			
		||||
			style="stroke: none; fill: url(#{ cpuGradientId }); mask: url(#{ cpuMaskId })"/>
 | 
			
		||||
		<text x="1" y="5">CPU <tspan>{ cpuP }%</tspan></text>
 | 
			
		||||
	</svg>
 | 
			
		||||
	<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none">
 | 
			
		||||
		<defs>
 | 
			
		||||
			<linearGradient id={ memGradientId } x1="0" x2="0" y1="1" y2="0">
 | 
			
		||||
				<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="33%" stop-color="hsl(120, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="66%" stop-color="hsl(60, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
 | 
			
		||||
			</linearGradient>
 | 
			
		||||
			<mask id={ memMaskId } x="0" y="0" riot-width={ viewBoxX } riot-height={ viewBoxY }>
 | 
			
		||||
				<polygon
 | 
			
		||||
					riot-points={ memPolygonPoints }
 | 
			
		||||
					fill="#fff"
 | 
			
		||||
					fill-opacity="0.5"/>
 | 
			
		||||
				<polyline
 | 
			
		||||
					riot-points={ memPolylinePoints }
 | 
			
		||||
					fill="none"
 | 
			
		||||
					stroke="#fff"
 | 
			
		||||
					stroke-width="1"/>
 | 
			
		||||
			</mask>
 | 
			
		||||
		</defs>
 | 
			
		||||
		<rect
 | 
			
		||||
			x="-1" y="-1"
 | 
			
		||||
			riot-width={ viewBoxX + 2 } riot-height={ viewBoxY + 2 }
 | 
			
		||||
			style="stroke: none; fill: url(#{ memGradientId }); mask: url(#{ memMaskId })"/>
 | 
			
		||||
		<text x="1" y="5">MEM <tspan>{ memP }%</tspan></text>
 | 
			
		||||
	</svg>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
 | 
			
		||||
			> svg
 | 
			
		||||
				display block
 | 
			
		||||
				padding 10px
 | 
			
		||||
				width 50%
 | 
			
		||||
				float left
 | 
			
		||||
 | 
			
		||||
				&:first-child
 | 
			
		||||
					padding-right 5px
 | 
			
		||||
 | 
			
		||||
				&:last-child
 | 
			
		||||
					padding-left 5px
 | 
			
		||||
 | 
			
		||||
				> text
 | 
			
		||||
					font-size 5px
 | 
			
		||||
					fill rgba(0, 0, 0, 0.55)
 | 
			
		||||
 | 
			
		||||
					> tspan
 | 
			
		||||
						opacity 0.5
 | 
			
		||||
 | 
			
		||||
			&:after
 | 
			
		||||
				content ""
 | 
			
		||||
				display block
 | 
			
		||||
				clear both
 | 
			
		||||
	</style>
 | 
			
		||||
	<script lang="typescript">
 | 
			
		||||
		import uuid from 'uuid';
 | 
			
		||||
 | 
			
		||||
		this.viewBoxX = 50;
 | 
			
		||||
		this.viewBoxY = 30;
 | 
			
		||||
		this.stats = [];
 | 
			
		||||
		this.connection = this.opts.connection;
 | 
			
		||||
		this.cpuGradientId = uuid();
 | 
			
		||||
		this.cpuMaskId = uuid();
 | 
			
		||||
		this.memGradientId = uuid();
 | 
			
		||||
		this.memMaskId = uuid();
 | 
			
		||||
 | 
			
		||||
		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.stats.push(stats);
 | 
			
		||||
			if (this.stats.length > 50) this.stats.shift();
 | 
			
		||||
 | 
			
		||||
			const cpuPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - s.cpu_usage) * this.viewBoxY}`).join(' ');
 | 
			
		||||
			const memPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - (s.mem.used / s.mem.total)) * this.viewBoxY}`).join(' ');
 | 
			
		||||
 | 
			
		||||
			const cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ cpuPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
 | 
			
		||||
			const memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ memPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
 | 
			
		||||
 | 
			
		||||
			const cpuP = (stats.cpu_usage * 100).toFixed(0);
 | 
			
		||||
			const memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
 | 
			
		||||
 | 
			
		||||
			this.update({
 | 
			
		||||
				cpuPolylinePoints,
 | 
			
		||||
				memPolylinePoints,
 | 
			
		||||
				cpuPolygonPoints,
 | 
			
		||||
				memPolygonPoints,
 | 
			
		||||
				cpuP,
 | 
			
		||||
				memP
 | 
			
		||||
			});
 | 
			
		||||
		};
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget-cpu-and-memory-usage>
 | 
			
		||||
 | 
			
		||||
<mk-server-home-widget-cpu>
 | 
			
		||||
	<mk-server-home-widget-pie ref="pie"/>
 | 
			
		||||
	<div>
 | 
			
		||||
		<p>%fa:microchip%CPU</p>
 | 
			
		||||
		<p>{ cores } Cores</p>
 | 
			
		||||
		<p>{ model }</p>
 | 
			
		||||
	</div>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
 | 
			
		||||
			> mk-server-home-widget-pie
 | 
			
		||||
				padding 10px
 | 
			
		||||
				height 100px
 | 
			
		||||
				float left
 | 
			
		||||
 | 
			
		||||
			> div
 | 
			
		||||
				float left
 | 
			
		||||
				width calc(100% - 100px)
 | 
			
		||||
				padding 10px 10px 10px 0
 | 
			
		||||
 | 
			
		||||
				> p
 | 
			
		||||
					margin 0
 | 
			
		||||
					font-size 12px
 | 
			
		||||
					color #505050
 | 
			
		||||
 | 
			
		||||
					&:first-child
 | 
			
		||||
						font-weight bold
 | 
			
		||||
 | 
			
		||||
						> [data-fa]
 | 
			
		||||
							margin-right 4px
 | 
			
		||||
 | 
			
		||||
			&:after
 | 
			
		||||
				content ""
 | 
			
		||||
				display block
 | 
			
		||||
				clear both
 | 
			
		||||
 | 
			
		||||
	</style>
 | 
			
		||||
	<script lang="typescript">
 | 
			
		||||
		this.cores = this.opts.meta.cpu.cores;
 | 
			
		||||
		this.model = this.opts.meta.cpu.model;
 | 
			
		||||
		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.pie.render(stats.cpu_usage);
 | 
			
		||||
		};
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget-cpu>
 | 
			
		||||
 | 
			
		||||
<mk-server-home-widget-memory>
 | 
			
		||||
	<mk-server-home-widget-pie ref="pie"/>
 | 
			
		||||
	<div>
 | 
			
		||||
		<p>%fa:flask%Memory</p>
 | 
			
		||||
		<p>Total: { bytesToSize(total, 1) }</p>
 | 
			
		||||
		<p>Used: { bytesToSize(used, 1) }</p>
 | 
			
		||||
		<p>Free: { bytesToSize(free, 1) }</p>
 | 
			
		||||
	</div>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
 | 
			
		||||
			> mk-server-home-widget-pie
 | 
			
		||||
				padding 10px
 | 
			
		||||
				height 100px
 | 
			
		||||
				float left
 | 
			
		||||
 | 
			
		||||
			> div
 | 
			
		||||
				float left
 | 
			
		||||
				width calc(100% - 100px)
 | 
			
		||||
				padding 10px 10px 10px 0
 | 
			
		||||
 | 
			
		||||
				> p
 | 
			
		||||
					margin 0
 | 
			
		||||
					font-size 12px
 | 
			
		||||
					color #505050
 | 
			
		||||
 | 
			
		||||
					&:first-child
 | 
			
		||||
						font-weight bold
 | 
			
		||||
 | 
			
		||||
						> [data-fa]
 | 
			
		||||
							margin-right 4px
 | 
			
		||||
 | 
			
		||||
			&:after
 | 
			
		||||
				content ""
 | 
			
		||||
				display block
 | 
			
		||||
				clear both
 | 
			
		||||
 | 
			
		||||
	</style>
 | 
			
		||||
	<script lang="typescript">
 | 
			
		||||
		import bytesToSize from '../../../common/scripts/bytes-to-size';
 | 
			
		||||
 | 
			
		||||
		this.connection = this.opts.connection;
 | 
			
		||||
		this.bytesToSize = bytesToSize;
 | 
			
		||||
 | 
			
		||||
		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.pie.render(stats.mem.used / stats.mem.total);
 | 
			
		||||
 | 
			
		||||
			this.update({
 | 
			
		||||
				total: stats.mem.total,
 | 
			
		||||
				used: stats.mem.used,
 | 
			
		||||
				free: stats.mem.free
 | 
			
		||||
			});
 | 
			
		||||
		};
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget-memory>
 | 
			
		||||
 | 
			
		||||
<mk-server-home-widget-disk>
 | 
			
		||||
	<mk-server-home-widget-pie ref="pie"/>
 | 
			
		||||
	<div>
 | 
			
		||||
		<p>%fa:R hdd%Storage</p>
 | 
			
		||||
		<p>Total: { bytesToSize(total, 1) }</p>
 | 
			
		||||
		<p>Available: { bytesToSize(available, 1) }</p>
 | 
			
		||||
		<p>Used: { bytesToSize(used, 1) }</p>
 | 
			
		||||
	</div>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
 | 
			
		||||
			> mk-server-home-widget-pie
 | 
			
		||||
				padding 10px
 | 
			
		||||
				height 100px
 | 
			
		||||
				float left
 | 
			
		||||
 | 
			
		||||
			> div
 | 
			
		||||
				float left
 | 
			
		||||
				width calc(100% - 100px)
 | 
			
		||||
				padding 10px 10px 10px 0
 | 
			
		||||
 | 
			
		||||
				> p
 | 
			
		||||
					margin 0
 | 
			
		||||
					font-size 12px
 | 
			
		||||
					color #505050
 | 
			
		||||
 | 
			
		||||
					&:first-child
 | 
			
		||||
						font-weight bold
 | 
			
		||||
 | 
			
		||||
						> [data-fa]
 | 
			
		||||
							margin-right 4px
 | 
			
		||||
 | 
			
		||||
			&:after
 | 
			
		||||
				content ""
 | 
			
		||||
				display block
 | 
			
		||||
				clear both
 | 
			
		||||
 | 
			
		||||
	</style>
 | 
			
		||||
	<script lang="typescript">
 | 
			
		||||
		import bytesToSize from '../../../common/scripts/bytes-to-size';
 | 
			
		||||
 | 
			
		||||
		this.connection = this.opts.connection;
 | 
			
		||||
		this.bytesToSize = bytesToSize;
 | 
			
		||||
 | 
			
		||||
		this.on('mount', () => {
 | 
			
		||||
			this.connection.on('stats', this.onStats);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.on('unmount', () => {
 | 
			
		||||
			this.connection.off('stats', this.onStats);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.onStats = stats => {
 | 
			
		||||
			stats.disk.used = stats.disk.total - stats.disk.free;
 | 
			
		||||
 | 
			
		||||
			this.$refs.pie.render(stats.disk.used / stats.disk.total);
 | 
			
		||||
 | 
			
		||||
			this.update({
 | 
			
		||||
				total: stats.disk.total,
 | 
			
		||||
				used: stats.disk.used,
 | 
			
		||||
				available: stats.disk.available
 | 
			
		||||
			});
 | 
			
		||||
		};
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget-disk>
 | 
			
		||||
 | 
			
		||||
<mk-server-home-widget-uptimes>
 | 
			
		||||
	<p>Uptimes</p>
 | 
			
		||||
	<p>Process: { process ? process.toFixed(0) : '---' }s</p>
 | 
			
		||||
	<p>OS: { os ? os.toFixed(0) : '---' }s</p>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
			padding 10px 14px
 | 
			
		||||
 | 
			
		||||
			> p
 | 
			
		||||
				margin 0
 | 
			
		||||
				font-size 12px
 | 
			
		||||
				color #505050
 | 
			
		||||
 | 
			
		||||
				&:first-child
 | 
			
		||||
					font-weight bold
 | 
			
		||||
 | 
			
		||||
	</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.update({
 | 
			
		||||
				process: stats.process_uptime,
 | 
			
		||||
				os: stats.os_uptime
 | 
			
		||||
			});
 | 
			
		||||
		};
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget-uptimes>
 | 
			
		||||
 | 
			
		||||
<mk-server-home-widget-info>
 | 
			
		||||
	<p>Maintainer: <b>{ meta.maintainer }</b></p>
 | 
			
		||||
	<p>Machine: { meta.machine }</p>
 | 
			
		||||
	<p>Node: { meta.node }</p>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
			padding 10px 14px
 | 
			
		||||
 | 
			
		||||
			> p
 | 
			
		||||
				margin 0
 | 
			
		||||
				font-size 12px
 | 
			
		||||
				color #505050
 | 
			
		||||
 | 
			
		||||
	</style>
 | 
			
		||||
	<script lang="typescript">
 | 
			
		||||
		this.meta = this.opts.meta;
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget-info>
 | 
			
		||||
 | 
			
		||||
<mk-server-home-widget-pie>
 | 
			
		||||
	<svg viewBox="0 0 1 1" preserveAspectRatio="none">
 | 
			
		||||
		<circle
 | 
			
		||||
			riot-r={ r }
 | 
			
		||||
			cx="50%" cy="50%"
 | 
			
		||||
			fill="none"
 | 
			
		||||
			stroke-width="0.1"
 | 
			
		||||
			stroke="rgba(0, 0, 0, 0.05)"/>
 | 
			
		||||
		<circle
 | 
			
		||||
			riot-r={ r }
 | 
			
		||||
			cx="50%" cy="50%"
 | 
			
		||||
			riot-stroke-dasharray={ Math.PI * (r * 2) }
 | 
			
		||||
			riot-stroke-dashoffset={ strokeDashoffset }
 | 
			
		||||
			fill="none"
 | 
			
		||||
			stroke-width="0.1"
 | 
			
		||||
			riot-stroke={ color }/>
 | 
			
		||||
		<text x="50%" y="50%" dy="0.05" text-anchor="middle">{ (p * 100).toFixed(0) }%</text>
 | 
			
		||||
	</svg>
 | 
			
		||||
	<style lang="stylus" scoped>
 | 
			
		||||
		:scope
 | 
			
		||||
			display block
 | 
			
		||||
 | 
			
		||||
			> svg
 | 
			
		||||
				display block
 | 
			
		||||
				height 100%
 | 
			
		||||
 | 
			
		||||
				> circle
 | 
			
		||||
					transform-origin center
 | 
			
		||||
					transform rotate(-90deg)
 | 
			
		||||
					transition stroke-dashoffset 0.5s ease
 | 
			
		||||
 | 
			
		||||
				> text
 | 
			
		||||
					font-size 0.15px
 | 
			
		||||
					fill rgba(0, 0, 0, 0.6)
 | 
			
		||||
 | 
			
		||||
	</style>
 | 
			
		||||
	<script lang="typescript">
 | 
			
		||||
		this.r = 0.4;
 | 
			
		||||
 | 
			
		||||
		this.render = p => {
 | 
			
		||||
			const color = `hsl(${180 - (p * 180)}, 80%, 70%)`;
 | 
			
		||||
			const strokeDashoffset = (1 - p) * (Math.PI * (this.r * 2));
 | 
			
		||||
 | 
			
		||||
			this.update({
 | 
			
		||||
				p,
 | 
			
		||||
				color,
 | 
			
		||||
				strokeDashoffset
 | 
			
		||||
			});
 | 
			
		||||
		};
 | 
			
		||||
	</script>
 | 
			
		||||
</mk-server-home-widget-pie>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,127 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="cpu-memory">
 | 
			
		||||
	<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" preserveAspectRatio="none">
 | 
			
		||||
		<defs>
 | 
			
		||||
			<linearGradient :id="cpuGradientId" x1="0" x2="0" y1="1" y2="0">
 | 
			
		||||
				<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
 | 
			
		||||
			</linearGradient>
 | 
			
		||||
			<mask :id="cpuMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
 | 
			
		||||
				<polygon
 | 
			
		||||
					:points="cpuPolygonPoints"
 | 
			
		||||
					fill="#fff"
 | 
			
		||||
					fill-opacity="0.5"/>
 | 
			
		||||
				<polyline
 | 
			
		||||
					:points="cpuPolylinePoints"
 | 
			
		||||
					fill="none"
 | 
			
		||||
					stroke="#fff"
 | 
			
		||||
					stroke-width="1"/>
 | 
			
		||||
			</mask>
 | 
			
		||||
		</defs>
 | 
			
		||||
		<rect
 | 
			
		||||
			x="-1" y="-1"
 | 
			
		||||
			:width="viewBoxX + 2" :height="viewBoxY + 2"
 | 
			
		||||
			:style="`stroke: none; fill: url(#${ cpuGradientId }); mask: url(#${ cpuMaskId })`"/>
 | 
			
		||||
		<text x="1" y="5">CPU <tspan>{{ cpuP }}%</tspan></text>
 | 
			
		||||
	</svg>
 | 
			
		||||
	<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" preserveAspectRatio="none">
 | 
			
		||||
		<defs>
 | 
			
		||||
			<linearGradient :id="memGradientId" x1="0" x2="0" y1="1" y2="0">
 | 
			
		||||
				<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
 | 
			
		||||
				<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
 | 
			
		||||
			</linearGradient>
 | 
			
		||||
			<mask :id="memMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
 | 
			
		||||
				<polygon
 | 
			
		||||
					:points="memPolygonPoints"
 | 
			
		||||
					fill="#fff"
 | 
			
		||||
					fill-opacity="0.5"/>
 | 
			
		||||
				<polyline
 | 
			
		||||
					:points="memPolylinePoints"
 | 
			
		||||
					fill="none"
 | 
			
		||||
					stroke="#fff"
 | 
			
		||||
					stroke-width="1"/>
 | 
			
		||||
			</mask>
 | 
			
		||||
		</defs>
 | 
			
		||||
		<rect
 | 
			
		||||
			x="-1" y="-1"
 | 
			
		||||
			:width="viewBoxX + 2" :height="viewBoxY + 2"
 | 
			
		||||
			:style="`stroke: none; fill: url(#${ memGradientId }); mask: url(#${ memMaskId })`"/>
 | 
			
		||||
		<text x="1" y="5">MEM <tspan>{{ memP }}%</tspan></text>
 | 
			
		||||
	</svg>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import uuid from 'uuid';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: ['connection'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			viewBoxX: 50,
 | 
			
		||||
			viewBoxY: 30,
 | 
			
		||||
			stats: [],
 | 
			
		||||
			cpuGradientId: uuid(),
 | 
			
		||||
			cpuMaskId: uuid(),
 | 
			
		||||
			memGradientId: uuid(),
 | 
			
		||||
			memMaskId: uuid(),
 | 
			
		||||
			cpuPolylinePoints: '',
 | 
			
		||||
			memPolylinePoints: '',
 | 
			
		||||
			cpuPolygonPoints: '',
 | 
			
		||||
			memPolygonPoints: '',
 | 
			
		||||
			cpuP: '',
 | 
			
		||||
			memP: ''
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.connection.on('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	beforeDestroy() {
 | 
			
		||||
		this.connection.off('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			stats.mem.used = stats.mem.total - stats.mem.free;
 | 
			
		||||
			this.stats.push(stats);
 | 
			
		||||
			if (this.stats.length > 50) this.stats.shift();
 | 
			
		||||
 | 
			
		||||
			this.cpuPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - s.cpu_usage) * this.viewBoxY}`).join(' ');
 | 
			
		||||
			this.memPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - (s.mem.used / s.mem.total)) * this.viewBoxY}`).join(' ');
 | 
			
		||||
 | 
			
		||||
			this.cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.cpuPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
 | 
			
		||||
			this.memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ this.memPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
 | 
			
		||||
 | 
			
		||||
			this.cpuP = (stats.cpu_usage * 100).toFixed(0);
 | 
			
		||||
			this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.cpu-memory
 | 
			
		||||
	> svg
 | 
			
		||||
		display block
 | 
			
		||||
		padding 10px
 | 
			
		||||
		width 50%
 | 
			
		||||
		float left
 | 
			
		||||
 | 
			
		||||
		&:first-child
 | 
			
		||||
			padding-right 5px
 | 
			
		||||
 | 
			
		||||
		&:last-child
 | 
			
		||||
			padding-left 5px
 | 
			
		||||
 | 
			
		||||
		> text
 | 
			
		||||
			font-size 5px
 | 
			
		||||
			fill rgba(0, 0, 0, 0.55)
 | 
			
		||||
 | 
			
		||||
			> tspan
 | 
			
		||||
				opacity 0.5
 | 
			
		||||
 | 
			
		||||
	&:after
 | 
			
		||||
		content ""
 | 
			
		||||
		display block
 | 
			
		||||
		clear both
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										68
									
								
								src/web/app/desktop/views/components/widgets/server.cpu.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/web/app/desktop/views/components/widgets/server.cpu.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="cpu">
 | 
			
		||||
	<x-pie class="pie" :value="usage"/>
 | 
			
		||||
	<div>
 | 
			
		||||
		<p>%fa:microchip%CPU</p>
 | 
			
		||||
		<p>{{ cores }} Cores</p>
 | 
			
		||||
		<p>{{ model }}</p>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import XPie from './server.pie.vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	components: {
 | 
			
		||||
		'x-pie': XPie
 | 
			
		||||
	},
 | 
			
		||||
	props: ['connection', 'meta'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			usage: 0
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.connection.on('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	beforeDestroy() {
 | 
			
		||||
		this.connection.off('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			this.usage = stats.cpu_usage;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.cpu
 | 
			
		||||
	> .pie
 | 
			
		||||
		padding 10px
 | 
			
		||||
		height 100px
 | 
			
		||||
		float left
 | 
			
		||||
 | 
			
		||||
	> div
 | 
			
		||||
		float left
 | 
			
		||||
		width calc(100% - 100px)
 | 
			
		||||
		padding 10px 10px 10px 0
 | 
			
		||||
 | 
			
		||||
		> p
 | 
			
		||||
			margin 0
 | 
			
		||||
			font-size 12px
 | 
			
		||||
			color #505050
 | 
			
		||||
 | 
			
		||||
			&:first-child
 | 
			
		||||
				font-weight bold
 | 
			
		||||
 | 
			
		||||
				> [data-fa]
 | 
			
		||||
					margin-right 4px
 | 
			
		||||
 | 
			
		||||
	&:after
 | 
			
		||||
		content ""
 | 
			
		||||
		display block
 | 
			
		||||
		clear both
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										76
									
								
								src/web/app/desktop/views/components/widgets/server.disk.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/web/app/desktop/views/components/widgets/server.disk.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="disk">
 | 
			
		||||
	<x-pie class="pie" :value="usage"/>
 | 
			
		||||
	<div>
 | 
			
		||||
		<p>%fa:R hdd%Storage</p>
 | 
			
		||||
		<p>Total: {{ total | bytes(1) }}</p>
 | 
			
		||||
		<p>Available: {{ available | bytes(1) }}</p>
 | 
			
		||||
		<p>Used: {{ used | bytes(1) }}</p>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import XPie from './server.pie.vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	components: {
 | 
			
		||||
		'x-pie': XPie
 | 
			
		||||
	},
 | 
			
		||||
	props: ['connection'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			usage: 0,
 | 
			
		||||
			total: 0,
 | 
			
		||||
			used: 0,
 | 
			
		||||
			available: 0
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.connection.on('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	beforeDestroy() {
 | 
			
		||||
		this.connection.off('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			stats.disk.used = stats.disk.total - stats.disk.free;
 | 
			
		||||
			this.usage = stats.disk.used / stats.disk.total;
 | 
			
		||||
			this.total = stats.disk.total;
 | 
			
		||||
			this.used = stats.disk.used;
 | 
			
		||||
			this.available = stats.disk.available;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.disk
 | 
			
		||||
	> .pie
 | 
			
		||||
		padding 10px
 | 
			
		||||
		height 100px
 | 
			
		||||
		float left
 | 
			
		||||
 | 
			
		||||
	> div
 | 
			
		||||
		float left
 | 
			
		||||
		width calc(100% - 100px)
 | 
			
		||||
		padding 10px 10px 10px 0
 | 
			
		||||
 | 
			
		||||
		> p
 | 
			
		||||
			margin 0
 | 
			
		||||
			font-size 12px
 | 
			
		||||
			color #505050
 | 
			
		||||
 | 
			
		||||
			&:first-child
 | 
			
		||||
				font-weight bold
 | 
			
		||||
 | 
			
		||||
				> [data-fa]
 | 
			
		||||
					margin-right 4px
 | 
			
		||||
 | 
			
		||||
	&:after
 | 
			
		||||
		content ""
 | 
			
		||||
		display block
 | 
			
		||||
		clear both
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										25
									
								
								src/web/app/desktop/views/components/widgets/server.info.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/web/app/desktop/views/components/widgets/server.info.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="info">
 | 
			
		||||
	<p>Maintainer: <b>{{ meta.maintainer }}</b></p>
 | 
			
		||||
	<p>Machine: {{ meta.machine }}</p>
 | 
			
		||||
	<p>Node: {{ meta.node }}</p>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: ['meta']
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="info" scoped>
 | 
			
		||||
.uptimes
 | 
			
		||||
	padding 10px 14px
 | 
			
		||||
 | 
			
		||||
	> p
 | 
			
		||||
		margin 0
 | 
			
		||||
		font-size 12px
 | 
			
		||||
		color #505050
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="memory">
 | 
			
		||||
	<x-pie class="pie" :value="usage"/>
 | 
			
		||||
	<div>
 | 
			
		||||
		<p>%fa:flask%Memory</p>
 | 
			
		||||
		<p>Total: {{ total | bytes(1) }}</p>
 | 
			
		||||
		<p>Used: {{ used | bytes(1) }}</p>
 | 
			
		||||
		<p>Free: {{ free | bytes(1) }}</p>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import XPie from './server.pie.vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	components: {
 | 
			
		||||
		'x-pie': XPie
 | 
			
		||||
	},
 | 
			
		||||
	props: ['connection'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			usage: 0,
 | 
			
		||||
			total: 0,
 | 
			
		||||
			used: 0,
 | 
			
		||||
			free: 0
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.connection.on('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	beforeDestroy() {
 | 
			
		||||
		this.connection.off('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			stats.mem.used = stats.mem.total - stats.mem.free;
 | 
			
		||||
			this.usage = stats.mem.used / stats.mem.total;
 | 
			
		||||
			this.total = stats.mem.total;
 | 
			
		||||
			this.used = stats.mem.used;
 | 
			
		||||
			this.free = stats.mem.free;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.memory
 | 
			
		||||
	> .pie
 | 
			
		||||
		padding 10px
 | 
			
		||||
		height 100px
 | 
			
		||||
		float left
 | 
			
		||||
 | 
			
		||||
	> div
 | 
			
		||||
		float left
 | 
			
		||||
		width calc(100% - 100px)
 | 
			
		||||
		padding 10px 10px 10px 0
 | 
			
		||||
 | 
			
		||||
		> p
 | 
			
		||||
			margin 0
 | 
			
		||||
			font-size 12px
 | 
			
		||||
			color #505050
 | 
			
		||||
 | 
			
		||||
			&:first-child
 | 
			
		||||
				font-weight bold
 | 
			
		||||
 | 
			
		||||
				> [data-fa]
 | 
			
		||||
					margin-right 4px
 | 
			
		||||
 | 
			
		||||
	&:after
 | 
			
		||||
		content ""
 | 
			
		||||
		display block
 | 
			
		||||
		clear both
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										61
									
								
								src/web/app/desktop/views/components/widgets/server.pie.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/web/app/desktop/views/components/widgets/server.pie.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
<template>
 | 
			
		||||
<svg viewBox="0 0 1 1" preserveAspectRatio="none">
 | 
			
		||||
	<circle
 | 
			
		||||
		:r="r"
 | 
			
		||||
		cx="50%" cy="50%"
 | 
			
		||||
		fill="none"
 | 
			
		||||
		stroke-width="0.1"
 | 
			
		||||
		stroke="rgba(0, 0, 0, 0.05)"/>
 | 
			
		||||
	<circle
 | 
			
		||||
		:r="r"
 | 
			
		||||
		cx="50%" cy="50%"
 | 
			
		||||
		:stroke-dasharray="Math.PI * (r * 2)"
 | 
			
		||||
		:stroke-dashoffset="strokeDashoffset"
 | 
			
		||||
		fill="none"
 | 
			
		||||
		stroke-width="0.1"
 | 
			
		||||
		:stroke="color"/>
 | 
			
		||||
	<text x="50%" y="50%" dy="0.05" text-anchor="middle">{{ (p * 100).toFixed(0) }}%</text>
 | 
			
		||||
</svg>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: {
 | 
			
		||||
		value: {
 | 
			
		||||
			type: Number,
 | 
			
		||||
			required: true
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			r: 0.4
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		color(): string {
 | 
			
		||||
			return `hsl(${180 - (this.value * 180)}, 80%, 70%)`;
 | 
			
		||||
		},
 | 
			
		||||
		strokeDashoffset(): number {
 | 
			
		||||
			return (1 - this.value) * (Math.PI * (this.r * 2));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
svg
 | 
			
		||||
	display block
 | 
			
		||||
	height 100%
 | 
			
		||||
 | 
			
		||||
	> circle
 | 
			
		||||
		transform-origin center
 | 
			
		||||
		transform rotate(-90deg)
 | 
			
		||||
		transition stroke-dashoffset 0.5s ease
 | 
			
		||||
 | 
			
		||||
	> text
 | 
			
		||||
		font-size 0.15px
 | 
			
		||||
		fill rgba(0, 0, 0, 0.6)
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="uptimes">
 | 
			
		||||
	<p>Uptimes</p>
 | 
			
		||||
	<p>Process: {{ process ? process.toFixed(0) : '---' }}s</p>
 | 
			
		||||
	<p>OS: {{ os ? os.toFixed(0) : '---' }}s</p>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: ['connection'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			process: 0,
 | 
			
		||||
			os: 0
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.connection.on('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	beforeDestroy() {
 | 
			
		||||
		this.connection.off('stats', this.onStats);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			this.process = stats.process_uptime;
 | 
			
		||||
			this.os = stats.os_uptime;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.uptimes
 | 
			
		||||
	padding 10px 14px
 | 
			
		||||
 | 
			
		||||
	> p
 | 
			
		||||
		margin 0
 | 
			
		||||
		font-size 12px
 | 
			
		||||
		color #505050
 | 
			
		||||
 | 
			
		||||
		&:first-child
 | 
			
		||||
			font-weight bold
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										127
									
								
								src/web/app/desktop/views/components/widgets/server.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/web/app/desktop/views/components/widgets/server.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,127 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="mkw-server" :data-melt="props.design == 2">
 | 
			
		||||
	<template v-if="props.design == 0">
 | 
			
		||||
		<p class="title">%fa:server%%i18n:desktop.tags.mk-server-home-widget.title%</p>
 | 
			
		||||
		<button @click="toggle" title="%i18n:desktop.tags.mk-server-home-widget.toggle%">%fa:sort%</button>
 | 
			
		||||
	</template>
 | 
			
		||||
	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 | 
			
		||||
	<template v-if="!fetching">
 | 
			
		||||
		<x-cpu-memory v-show="props.view == 0" :connection="connection"/>
 | 
			
		||||
		<x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/>
 | 
			
		||||
		<x-memory v-show="props.view == 2" :connection="connection"/>
 | 
			
		||||
		<x-disk v-show="props.view == 3" :connection="connection"/>
 | 
			
		||||
		<x-uptimes v-show="props.view == 4" :connection="connection"/>
 | 
			
		||||
		<x-info v-show="props.view == 5" :connection="connection" :meta="meta"/>
 | 
			
		||||
	</template>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import define from '../../../../common/define-widget';
 | 
			
		||||
import XCpuMemory from './server.cpu-memory.vue';
 | 
			
		||||
import XCpu from './server.cpu.vue';
 | 
			
		||||
import XMemory from './server.memory.vue';
 | 
			
		||||
import XDisk from './server.disk.vue';
 | 
			
		||||
import XUptimes from './server.uptimes.vue';
 | 
			
		||||
import XInfo from './server.info.vue';
 | 
			
		||||
 | 
			
		||||
export default define({
 | 
			
		||||
	name: 'server',
 | 
			
		||||
	props: {
 | 
			
		||||
		design: 0,
 | 
			
		||||
		view: 0
 | 
			
		||||
	}
 | 
			
		||||
}).extend({
 | 
			
		||||
	components: {
 | 
			
		||||
		'x-cpu-and-memory': XCpuMemory,
 | 
			
		||||
		'x-cpu': XCpu,
 | 
			
		||||
		'x-memory': XMemory,
 | 
			
		||||
		'x-disk': XDisk,
 | 
			
		||||
		'x-uptimes': XUptimes,
 | 
			
		||||
		'x-info': XInfo
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			fetching: true,
 | 
			
		||||
			meta: null,
 | 
			
		||||
			connection: null,
 | 
			
		||||
			connectionId: null
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		(this as any).os.getMeta().then(meta => {
 | 
			
		||||
			this.meta = meta;
 | 
			
		||||
			this.fetching = false;
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.connection = (this as any).os.streams.serverStream.getConnection();
 | 
			
		||||
		this.connectionId = (this as any).os.streams.serverStream.use();
 | 
			
		||||
	},
 | 
			
		||||
	beforeDestroy() {
 | 
			
		||||
		(this as any).os.streams.serverStream.dispose(this.connectionId);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		toggle() {
 | 
			
		||||
			if (this.props.design == 5) {
 | 
			
		||||
				this.props.design = 0;
 | 
			
		||||
			} else {
 | 
			
		||||
				this.props.design++;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		func() {
 | 
			
		||||
			this.toggle();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.mkw-server
 | 
			
		||||
	background #fff
 | 
			
		||||
	border solid 1px rgba(0, 0, 0, 0.075)
 | 
			
		||||
	border-radius 6px
 | 
			
		||||
 | 
			
		||||
	&[data-melt]
 | 
			
		||||
		background transparent !important
 | 
			
		||||
		border none !important
 | 
			
		||||
 | 
			
		||||
	> .title
 | 
			
		||||
		z-index 1
 | 
			
		||||
		margin 0
 | 
			
		||||
		padding 0 16px
 | 
			
		||||
		line-height 42px
 | 
			
		||||
		font-size 0.9em
 | 
			
		||||
		font-weight bold
 | 
			
		||||
		color #888
 | 
			
		||||
		box-shadow 0 1px rgba(0, 0, 0, 0.07)
 | 
			
		||||
 | 
			
		||||
		> [data-fa]
 | 
			
		||||
			margin-right 4px
 | 
			
		||||
 | 
			
		||||
	> button
 | 
			
		||||
		position absolute
 | 
			
		||||
		z-index 2
 | 
			
		||||
		top 0
 | 
			
		||||
		right 0
 | 
			
		||||
		padding 0
 | 
			
		||||
		width 42px
 | 
			
		||||
		font-size 0.9em
 | 
			
		||||
		line-height 42px
 | 
			
		||||
		color #ccc
 | 
			
		||||
 | 
			
		||||
		&:hover
 | 
			
		||||
			color #aaa
 | 
			
		||||
 | 
			
		||||
		&:active
 | 
			
		||||
			color #999
 | 
			
		||||
 | 
			
		||||
	> .fetching
 | 
			
		||||
		margin 0
 | 
			
		||||
		padding 16px
 | 
			
		||||
		text-align center
 | 
			
		||||
		color #aaa
 | 
			
		||||
 | 
			
		||||
		> [data-fa]
 | 
			
		||||
			margin-right 4px
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										8
									
								
								src/web/app/filters/bytes.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/web/app/filters/bytes.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
Vue.filter('bytes', (v, digits = 0) => {
 | 
			
		||||
	const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
 | 
			
		||||
	if (v == 0) return '0Byte';
 | 
			
		||||
	const i = Math.floor(Math.log(v) / Math.log(1024));
 | 
			
		||||
	return (v / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '') + sizes[i];
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										1
									
								
								src/web/app/filters/index.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/web/app/filters/index.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
require('./bytes');
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,9 @@ require('./common/views/directives');
 | 
			
		|||
// Register global components
 | 
			
		||||
require('./common/views/components');
 | 
			
		||||
 | 
			
		||||
// Register global filters
 | 
			
		||||
require('./filters');
 | 
			
		||||
 | 
			
		||||
Vue.mixin({
 | 
			
		||||
	destroyed(this: any) {
 | 
			
		||||
		if (this.$el.parentNode) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue