stats
This commit is contained in:
		
							parent
							
								
									2465b4aa7b
								
							
						
					
					
						commit
						dd1aa8c7d6
					
				
					 17 changed files with 462 additions and 2 deletions
				
			
		|  | @ -25,6 +25,7 @@ Note that Misskey uses following subdomains: | |||
| * **api**.*{primary domain}* | ||||
| * **auth**.*{primary domain}* | ||||
| * **about**.*{primary domain}* | ||||
| * **stats**.*{primary domain}* | ||||
| * **status**.*{primary domain}* | ||||
| * **dev**.*{primary domain}* | ||||
| * **file**.*{secondary domain}* | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ Misskeyは以下のサブドメインを使います: | |||
| * **api**.*{primary domain}* | ||||
| * **auth**.*{primary domain}* | ||||
| * **about**.*{primary domain}* | ||||
| * **stats**.*{primary domain}* | ||||
| * **status**.*{primary domain}* | ||||
| * **dev**.*{primary domain}* | ||||
| * **file**.*{secondary domain}* | ||||
|  |  | |||
|  | @ -427,6 +427,10 @@ mobile: | |||
|       known: "You know" | ||||
|       load-more: "More" | ||||
| 
 | ||||
| stats: | ||||
|   posts-count: "Number of all posts" | ||||
|   users-count: "Number of all users" | ||||
| 
 | ||||
| status: | ||||
|   all-systems-maybe-operational: "All systems maybe operational" | ||||
|   what-is-this-site: "" | ||||
|  |  | |||
|  | @ -428,6 +428,10 @@ mobile: | |||
|       known: "知り合い" | ||||
|       load-more: "もっと" | ||||
| 
 | ||||
| stats: | ||||
|   posts-count: "投稿の数" | ||||
|   users-count: "アカウントの数" | ||||
| 
 | ||||
| status: | ||||
|   all-systems-maybe-operational: "すべてのシステムがたぶん正常に作動しています" | ||||
|   what-is-this-site: "" | ||||
|  |  | |||
|  | @ -69,6 +69,9 @@ const endpoints: Endpoint[] = [ | |||
| 	{ | ||||
| 		name: 'meta' | ||||
| 	}, | ||||
| 	{ | ||||
| 		name: 'stats' | ||||
| 	}, | ||||
| 	{ | ||||
| 		name: 'username/available' | ||||
| 	}, | ||||
|  | @ -109,6 +112,12 @@ const endpoints: Endpoint[] = [ | |||
| 		withCredential: true, | ||||
| 		secure: true | ||||
| 	}, | ||||
| 	{ | ||||
| 		name: 'aggregation/posts', | ||||
| 	}, | ||||
| 	{ | ||||
| 		name: 'aggregation/users', | ||||
| 	}, | ||||
| 	{ | ||||
| 		name: 'aggregation/users/activity', | ||||
| 	}, | ||||
|  |  | |||
							
								
								
									
										95
									
								
								src/api/endpoints/aggregation/posts.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/api/endpoints/aggregation/posts.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| /** | ||||
|  * Module dependencies | ||||
|  */ | ||||
| import $ from 'cafy'; | ||||
| import Post from '../../models/post'; | ||||
| 
 | ||||
| /** | ||||
|  * Aggregate posts | ||||
|  * | ||||
|  * @param {any} params | ||||
|  * @return {Promise<any>} | ||||
|  */ | ||||
| module.exports = params => new Promise(async (res, rej) => { | ||||
| 	// Get 'limit' parameter
 | ||||
| 	const [limit = 365, limitErr] = $(params.limit).optional.number().range(1, 365).$; | ||||
| 	if (limitErr) return rej('invalid limit param'); | ||||
| 
 | ||||
| 	const datas = await Post | ||||
| 		.aggregate([ | ||||
| 			{ $project: { | ||||
| 				repost_id: '$repost_id', | ||||
| 				reply_to_id: '$reply_to_id', | ||||
| 				created_at: { $add: ['$created_at', 9 * 60 * 60 * 1000] } // Convert into JST
 | ||||
| 			}}, | ||||
| 			{ $project: { | ||||
| 				date: { | ||||
| 					year: { $year: '$created_at' }, | ||||
| 					month: { $month: '$created_at' }, | ||||
| 					day: { $dayOfMonth: '$created_at' } | ||||
| 				}, | ||||
| 				type: { | ||||
| 					$cond: { | ||||
| 						if: { $ne: ['$repost_id', null] }, | ||||
| 						then: 'repost', | ||||
| 						else: { | ||||
| 							$cond: { | ||||
| 								if: { $ne: ['$reply_to_id', null] }, | ||||
| 								then: 'reply', | ||||
| 								else: 'post' | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				}} | ||||
| 			}, | ||||
| 			{ $group: { _id: { | ||||
| 				date: '$date', | ||||
| 				type: '$type' | ||||
| 			}, count: { $sum: 1 } } }, | ||||
| 			{ $group: { | ||||
| 				_id: '$_id.date', | ||||
| 				data: { $addToSet: { | ||||
| 					type: '$_id.type', | ||||
| 					count: '$count' | ||||
| 				}} | ||||
| 			} } | ||||
| 		]); | ||||
| 
 | ||||
| 	datas.forEach(data => { | ||||
| 		data.date = data._id; | ||||
| 		delete data._id; | ||||
| 
 | ||||
| 		data.posts = (data.data.filter(x => x.type == 'post')[0] || { count: 0 }).count; | ||||
| 		data.reposts = (data.data.filter(x => x.type == 'repost')[0] || { count: 0 }).count; | ||||
| 		data.replies = (data.data.filter(x => x.type == 'reply')[0] || { count: 0 }).count; | ||||
| 
 | ||||
| 		delete data.data; | ||||
| 	}); | ||||
| 
 | ||||
| 	const graph = []; | ||||
| 
 | ||||
| 	for (let i = 0; i < limit; i++) { | ||||
| 		const day = new Date(new Date().setDate(new Date().getDate() - i)); | ||||
| 
 | ||||
| 		const data = datas.filter(d => | ||||
| 			d.date.year == day.getFullYear() && d.date.month == day.getMonth() + 1 && d.date.day == day.getDate() | ||||
| 		)[0]; | ||||
| 
 | ||||
| 		if (data) { | ||||
| 			graph.push(data); | ||||
| 		} else { | ||||
| 			graph.push({ | ||||
| 				date: { | ||||
| 					year: day.getFullYear(), | ||||
| 					month: day.getMonth() + 1, // In JavaScript, month is zero-based.
 | ||||
| 					day: day.getDate() | ||||
| 				}, | ||||
| 				posts: 0, | ||||
| 				reposts: 0, | ||||
| 				replies: 0 | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	res(graph); | ||||
| }); | ||||
							
								
								
									
										59
									
								
								src/api/endpoints/aggregation/users.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/api/endpoints/aggregation/users.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| /** | ||||
|  * Module dependencies | ||||
|  */ | ||||
| import $ from 'cafy'; | ||||
| import User from '../../models/user'; | ||||
| 
 | ||||
| /** | ||||
|  * Aggregate users | ||||
|  * | ||||
|  * @param {any} params | ||||
|  * @return {Promise<any>} | ||||
|  */ | ||||
| module.exports = params => new Promise(async (res, rej) => { | ||||
| 	// Get 'limit' parameter
 | ||||
| 	const [limit = 365, limitErr] = $(params.limit).optional.number().range(1, 365).$; | ||||
| 	if (limitErr) return rej('invalid limit param'); | ||||
| 
 | ||||
| 	const startTime = new Date(new Date().setMonth(new Date().getMonth() - 1)); | ||||
| 
 | ||||
| 	const users = await User | ||||
| 		.find({ | ||||
| 			$or: [ | ||||
| 				{ deleted_at: { $exists: false } }, | ||||
| 				{ deleted_at: { $gt: startTime } } | ||||
| 			] | ||||
| 		}, { | ||||
| 			_id: false, | ||||
| 			created_at: true, | ||||
| 			deleted_at: true | ||||
| 		}, { | ||||
| 			sort: { created_at: -1 } | ||||
| 		}); | ||||
| 
 | ||||
| 	const graph = []; | ||||
| 
 | ||||
| 	for (let i = 0; i < limit; i++) { | ||||
| 		let day = new Date(new Date().setDate(new Date().getDate() - i)); | ||||
| 		day = new Date(day.setMilliseconds(999)); | ||||
| 		day = new Date(day.setSeconds(59)); | ||||
| 		day = new Date(day.setMinutes(59)); | ||||
| 		day = new Date(day.setHours(23)); | ||||
| 		// day = day.getTime();
 | ||||
| 
 | ||||
| 		const count = users.filter(f => | ||||
| 			f.created_at < day && (f.deleted_at == null || f.deleted_at > day) | ||||
| 		).length; | ||||
| 
 | ||||
| 		graph.push({ | ||||
| 			date: { | ||||
| 				year: day.getFullYear(), | ||||
| 				month: day.getMonth() + 1, // In JavaScript, month is zero-based.
 | ||||
| 				day: day.getDate() | ||||
| 			}, | ||||
| 			count: count | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	res(graph); | ||||
| }); | ||||
							
								
								
									
										48
									
								
								src/api/endpoints/stats.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/api/endpoints/stats.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| /** | ||||
|  * Module dependencies | ||||
|  */ | ||||
| import Post from '../models/post'; | ||||
| import User from '../models/user'; | ||||
| 
 | ||||
| /** | ||||
|  * @swagger | ||||
|  * /stats: | ||||
|  *   post: | ||||
|  *     summary: Show the misskey's statistics | ||||
|  *     responses: | ||||
|  *       200: | ||||
|  *         description: Success | ||||
|  *         schema: | ||||
|  *           type: object | ||||
|  *           properties: | ||||
|  *             posts_count: | ||||
|  *               description: count of all posts of misskey | ||||
|  *               type: number | ||||
|  *             users_count: | ||||
|  *               description: count of all users of misskey | ||||
|  *               type: number | ||||
|  * | ||||
|  *       default: | ||||
|  *         description: Failed | ||||
|  *         schema: | ||||
|  *           $ref: "#/definitions/Error" | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Show the misskey's statistics | ||||
|  * | ||||
|  * @param {any} params | ||||
|  * @return {Promise<any>} | ||||
|  */ | ||||
| module.exports = params => new Promise(async (res, rej) => { | ||||
| 	const postsCount = await Post | ||||
| 		.count(); | ||||
| 
 | ||||
| 	const usersCount = await User | ||||
| 		.count(); | ||||
| 
 | ||||
| 	res({ | ||||
| 		posts_count: postsCount, | ||||
| 		users_count: usersCount | ||||
| 	}); | ||||
| }); | ||||
|  | @ -81,6 +81,7 @@ type Mixin = { | |||
| 	api_url: string; | ||||
| 	auth_url: string; | ||||
| 	about_url: string; | ||||
| 	stats_url: string; | ||||
| 	status_url: string; | ||||
| 	dev_url: string; | ||||
| 	drive_url: string; | ||||
|  | @ -116,6 +117,7 @@ export default function load() { | |||
| 	mixin.auth_url = `${mixin.scheme}://auth.${mixin.host}`; | ||||
| 	mixin.dev_url = `${mixin.scheme}://dev.${mixin.host}`; | ||||
| 	mixin.about_url = `${mixin.scheme}://about.${mixin.host}`; | ||||
| 	mixin.stats_url = `${mixin.scheme}://stats.${mixin.host}`; | ||||
| 	mixin.status_url = `${mixin.scheme}://status.${mixin.host}`; | ||||
| 	mixin.drive_url = `${mixin.secondary_scheme}://file.${mixin.secondary_host}`; | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ const url = `${scheme}//${host}`; | |||
| const apiUrl = `${scheme}//api.${host}`; | ||||
| const devUrl = `${scheme}//dev.${host}`; | ||||
| const aboutUrl = `${scheme}//about.${host}`; | ||||
| const statsUrl = `${scheme}//stats.${host}`; | ||||
| const statusUrl = `${scheme}//status.${host}`; | ||||
| 
 | ||||
| export default { | ||||
|  | @ -17,5 +18,6 @@ export default { | |||
| 	apiUrl, | ||||
| 	devUrl, | ||||
| 	aboutUrl, | ||||
| 	statsUrl, | ||||
| 	statusUrl | ||||
| }; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| <mk-nav-home-widget><a href={ CONFIG.aboutUrl }>Misskeyについて</a><i>・</i><a href={ CONFIG.statusUrl }>ステータス</a><i>・</i><a href="http://zawazawa.jp/misskey/">Wiki</a><i>・</i><a href="https://github.com/syuilo/misskey">リポジトリ</a><i>・</i><a href={ CONFIG.devUrl }>開発者</a><i>・</i><a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on <i class="fa fa-twitter"></i></a> | ||||
| <mk-nav-home-widget><a href={ CONFIG.aboutUrl }>Misskeyについて</a><i>・</i><a href={ CONFIG.statsUrl }>統計</a><i>・</i><a href={ CONFIG.statusUrl }>ステータス</a><i>・</i><a href="http://zawazawa.jp/misskey/">Wiki</a><i>・</i><a href="https://github.com/syuilo/misskey">リポジトリ</a><i>・</i><a href={ CONFIG.devUrl }>開発者</a><i>・</i><a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on <i class="fa fa-twitter"></i></a> | ||||
| 	<style> | ||||
| 		:scope | ||||
| 			display block | ||||
|  |  | |||
							
								
								
									
										23
									
								
								src/web/app/stats/script.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/web/app/stats/script.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| /** | ||||
|  * Stats | ||||
|  */ | ||||
| 
 | ||||
| // Style
 | ||||
| import './style.styl'; | ||||
| 
 | ||||
| import * as riot from 'riot'; | ||||
| require('./tags'); | ||||
| import init from '../init'; | ||||
| 
 | ||||
| document.title = 'Misskey Statistics'; | ||||
| 
 | ||||
| /** | ||||
|  * init | ||||
|  */ | ||||
| init(me => { | ||||
| 	mount(document.createElement('mk-index')); | ||||
| }); | ||||
| 
 | ||||
| function mount(content) { | ||||
| 	riot.mount(document.getElementById('app').appendChild(content)); | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/web/app/stats/style.styl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/web/app/stats/style.styl
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| @import "../base" | ||||
| 
 | ||||
| html | ||||
| 	color #456267 | ||||
| 	background #fff | ||||
| 
 | ||||
| body | ||||
| 	margin 0 | ||||
| 	padding 0 | ||||
							
								
								
									
										1
									
								
								src/web/app/stats/tags/index.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/web/app/stats/tags/index.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| require('./index.tag'); | ||||
							
								
								
									
										202
									
								
								src/web/app/stats/tags/index.tag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								src/web/app/stats/tags/index.tag
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,202 @@ | |||
| <mk-index> | ||||
| 	<h1>Misskey<i>Statistics</i></h1> | ||||
| 	<main if={ !initializing }> | ||||
| 		<mk-users stats={ stats }/> | ||||
| 		<mk-posts stats={ stats }/> | ||||
| 	</main> | ||||
| 	<footer><a href={ CONFIG.url }>{ CONFIG.host }</a></footer> | ||||
| 	<style> | ||||
| 		: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> | ||||
| 		this.mixin('api'); | ||||
| 
 | ||||
| 		this.initializing = true; | ||||
| 
 | ||||
| 		this.on('mount', () => { | ||||
| 			this.api('stats').then(stats => { | ||||
| 				this.update({ | ||||
| 					initializing: false, | ||||
| 					stats | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 	</script> | ||||
| </mk-index> | ||||
| 
 | ||||
| <mk-posts> | ||||
| 	<h2>%i18n:stats.posts-count% <b>{ stats.posts_count }</b></h2> | ||||
| 	<mk-posts-chart if={ !initializing } data={ data }/> | ||||
| 	<style> | ||||
| 		:scope | ||||
| 			display block | ||||
| 	</style> | ||||
| 	<script> | ||||
| 		this.mixin('api'); | ||||
| 
 | ||||
| 		this.initializing = true; | ||||
| 		this.stats = this.opts.stats; | ||||
| 
 | ||||
| 		this.on('mount', () => { | ||||
| 			this.api('aggregation/posts', { | ||||
| 				limit: 365 | ||||
| 			}).then(data => { | ||||
| 				this.update({ | ||||
| 					initializing: false, | ||||
| 					data | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 	</script> | ||||
| </mk-posts> | ||||
| 
 | ||||
| <mk-users> | ||||
| 	<h2>%i18n:stats.users-count% <b>{ stats.users_count }</b></h2> | ||||
| 	<mk-users-chart if={ !initializing } data={ data }/> | ||||
| 	<style> | ||||
| 		:scope | ||||
| 			display block | ||||
| 	</style> | ||||
| 	<script> | ||||
| 		this.mixin('api'); | ||||
| 
 | ||||
| 		this.initializing = true; | ||||
| 		this.stats = this.opts.stats; | ||||
| 
 | ||||
| 		this.on('mount', () => { | ||||
| 			this.api('aggregation/users', { | ||||
| 				limit: 365 | ||||
| 			}).then(data => { | ||||
| 				this.update({ | ||||
| 					initializing: false, | ||||
| 					data | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 	</script> | ||||
| </mk-users> | ||||
| 
 | ||||
| <mk-posts-chart> | ||||
| 	<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none"> | ||||
| 		<title>Black ... Total<br/>Blue ... Posts<br/>Red ... Replies<br/>Green ... Reposts</title> | ||||
| 		<polyline | ||||
| 			riot-points={ pointsPost } | ||||
| 			fill="none" | ||||
| 			stroke-width="1" | ||||
| 			stroke="#41ddde"/> | ||||
| 		<polyline | ||||
| 			riot-points={ pointsReply } | ||||
| 			fill="none" | ||||
| 			stroke-width="1" | ||||
| 			stroke="#f7796c"/> | ||||
| 		<polyline | ||||
| 			riot-points={ pointsRepost } | ||||
| 			fill="none" | ||||
| 			stroke-width="1" | ||||
| 			stroke="#a1de41"/> | ||||
| 		<polyline | ||||
| 			riot-points={ pointsTotal } | ||||
| 			fill="none" | ||||
| 			stroke-width="1" | ||||
| 			stroke="#555" | ||||
| 			stroke-dasharray="2 2"/> | ||||
| 	</svg> | ||||
| 	<style> | ||||
| 		:scope | ||||
| 			display block | ||||
| 
 | ||||
| 			> svg | ||||
| 				display block | ||||
| 				padding 1px | ||||
| 				width 100% | ||||
| 	</style> | ||||
| 	<script> | ||||
| 		this.viewBoxX = 365; | ||||
| 		this.viewBoxY = 60; | ||||
| 
 | ||||
| 		this.data = this.opts.data.reverse(); | ||||
| 		this.data.forEach(d => d.total = d.posts + d.replies + d.reposts); | ||||
| 		const peak = Math.max.apply(null, this.data.map(d => d.total)); | ||||
| 
 | ||||
| 		this.on('mount', () => { | ||||
| 			this.render(); | ||||
| 		}); | ||||
| 
 | ||||
| 		this.render = () => { | ||||
| 			this.update({ | ||||
| 				pointsPost: this.data.map((d, i) => `${i},${(1 - (d.posts / peak)) * this.viewBoxY}`).join(' '), | ||||
| 				pointsReply: this.data.map((d, i) => `${i},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' '), | ||||
| 				pointsRepost: this.data.map((d, i) => `${i},${(1 - (d.reposts / peak)) * this.viewBoxY}`).join(' '), | ||||
| 				pointsTotal: this.data.map((d, i) => `${i},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ') | ||||
| 			}); | ||||
| 		}; | ||||
| 	</script> | ||||
| </mk-posts-chart> | ||||
| 
 | ||||
| <mk-users-chart> | ||||
| 	<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none"> | ||||
| 		<polyline | ||||
| 			riot-points={ points } | ||||
| 			fill="none" | ||||
| 			stroke-width="1" | ||||
| 			stroke="#555"/> | ||||
| 	</svg> | ||||
| 	<style> | ||||
| 		:scope | ||||
| 			display block | ||||
| 
 | ||||
| 			> svg | ||||
| 				display block | ||||
| 				padding 1px | ||||
| 				width 100% | ||||
| 	</style> | ||||
| 	<script> | ||||
| 		this.viewBoxX = 365; | ||||
| 		this.viewBoxY = 60; | ||||
| 
 | ||||
| 		this.data = this.opts.data.reverse(); | ||||
| 		const peak = Math.max.apply(null, this.data.map(d => d.count)); | ||||
| 
 | ||||
| 		this.on('mount', () => { | ||||
| 			this.render(); | ||||
| 		}); | ||||
| 
 | ||||
| 		this.render = () => { | ||||
| 			this.update({ | ||||
| 				points: this.data.map((d, i) => `${i},${(1 - (d.count / peak)) * this.viewBoxY}`).join(' ') | ||||
| 			}); | ||||
| 		}; | ||||
| 	</script> | ||||
| </mk-users-chart> | ||||
|  | @ -56,7 +56,6 @@ | |||
| 		this.mixin('api'); | ||||
| 
 | ||||
| 		this.initializing = true; | ||||
| 		this.view = 0; | ||||
| 		this.connection = new Connection(); | ||||
| 
 | ||||
| 		this.on('mount', () => { | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ module.exports = langs.map(([lang, locale]) => { | |||
| 	const entry = { | ||||
| 		desktop: './src/web/app/desktop/script.js', | ||||
| 		mobile: './src/web/app/mobile/script.js', | ||||
| 		stats: './src/web/app/stats/script.js', | ||||
| 		status: './src/web/app/status/script.js', | ||||
| 		dev: './src/web/app/dev/script.js', | ||||
| 		auth: './src/web/app/auth/script.js' | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue