インスタンス一覧ページ
This commit is contained in:
		
							parent
							
								
									742a005523
								
							
						
					
					
						commit
						9f9d7325fd
					
				
					 4 changed files with 146 additions and 61 deletions
				
			
		|  | @ -765,6 +765,8 @@ customCss: "カスタムCSS" | |||
| customCssWarn: "この設定は必ず知識のある方が行ってください。不適切な設定を行うとクライアントが正常に使用できなくなる恐れがあります。" | ||||
| global: "グローバル" | ||||
| squareAvatars: "アイコンを四角形で表示" | ||||
| sent: "送信" | ||||
| received: "受信" | ||||
| searchResult: "検索結果" | ||||
| 
 | ||||
| _docs:  | ||||
|  |  | |||
|  | @ -113,6 +113,11 @@ export const menuDef = { | |||
| 		icon: 'fas fa-satellite-dish', | ||||
| 		to: '/channels', | ||||
| 	}, | ||||
| 	federation: { | ||||
| 		title: 'federation', | ||||
| 		icon: 'fas fa-globe', | ||||
| 		to: '/federation', | ||||
| 	}, | ||||
| 	emojis: { | ||||
| 		title: 'emojis', | ||||
| 		icon: 'fas fa-laugh', | ||||
|  |  | |||
|  | @ -1,9 +1,12 @@ | |||
| <template> | ||||
| <div class="enuoauvw"> | ||||
| <div class="taeiyria"> | ||||
| 	<div class="query"> | ||||
| 		<MkInput v-model:value="host" :debounce="true"><span>{{ $ts.host }}</span></MkInput> | ||||
| 		<div class="inputs" style="display: flex;"> | ||||
| 			<MkSelect v-model:value="state" style="margin: 0; flex: 1;"> | ||||
| 		<MkInput v-model="host" :debounce="true" class="_inputNoTopMargin"> | ||||
| 			<template #prefix><i class="fas fa-search"></i></template> | ||||
| 			<template #label>{{ $ts.host }}</template> | ||||
| 		</MkInput> | ||||
| 		<div class="_inputSplit _inputNoBottomMargin"> | ||||
| 			<MkSelect v-model="state"> | ||||
| 				<template #label>{{ $ts.state }}</template> | ||||
| 				<option value="all">{{ $ts.all }}</option> | ||||
| 				<option value="federating">{{ $ts.federating }}</option> | ||||
|  | @ -13,7 +16,7 @@ | |||
| 				<option value="blocked">{{ $ts.blocked }}</option> | ||||
| 				<option value="notResponding">{{ $ts.notResponding }}</option> | ||||
| 			</MkSelect> | ||||
| 			<MkSelect v-model:value="sort" style="margin: 0; flex: 1;"> | ||||
| 			<MkSelect v-model="sort"> | ||||
| 				<template #label>{{ $ts.sort }}</template> | ||||
| 				<option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option> | ||||
| 				<option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option> | ||||
|  | @ -38,16 +41,53 @@ | |||
| 	</div> | ||||
| 
 | ||||
| 	<MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state"> | ||||
| 		<div class="ppgwaixt _block" v-for="instance in items" :key="instance.id" @click="info(instance)"> | ||||
| 			<div class="host"><i class="fas fa-circle indicator" :class="getStatus(instance)"></i><b>{{ instance.host }}</b></div> | ||||
| 			<div class="status"> | ||||
| 		<div class="dqokceoi"> | ||||
| 			<MkA class="instance" v-for="instance in items" :key="instance.id" :to="`/instance-info/${instance.host}`"> | ||||
| 				<div class="host"><img :src="instance.faviconUrl">{{ instance.host }}</div> | ||||
| 				<div class="table"> | ||||
| 					<div class="cell"> | ||||
| 						<div class="key">{{ $ts.registeredAt }}</div> | ||||
| 						<div class="value"><MkTime :time="instance.caughtAt"/></div> | ||||
| 					</div> | ||||
| 					<div class="cell"> | ||||
| 						<div class="key">{{ $ts.software }}</div> | ||||
| 						<div class="value">{{ instance.softwareName || `(${$ts.unknown})` }}</div> | ||||
| 					</div> | ||||
| 					<div class="cell"> | ||||
| 						<div class="key">{{ $ts.version }}</div> | ||||
| 						<div class="value">{{ instance.softwareVersion || `(${$ts.unknown})` }}</div> | ||||
| 					</div> | ||||
| 					<div class="cell"> | ||||
| 						<div class="key">{{ $ts.users }}</div> | ||||
| 						<div class="value">{{ instance.usersCount }}</div> | ||||
| 					</div> | ||||
| 					<div class="cell"> | ||||
| 						<div class="key">{{ $ts.notes }}</div> | ||||
| 						<div class="value">{{ instance.notesCount }}</div> | ||||
| 					</div> | ||||
| 					<div class="cell"> | ||||
| 						<div class="key">{{ $ts.sent }}</div> | ||||
| 						<div class="value"><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></div> | ||||
| 					</div> | ||||
| 					<div class="cell"> | ||||
| 						<div class="key">{{ $ts.received }}</div> | ||||
| 						<div class="value"><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></div> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<div class="footer"> | ||||
| 					<span class="status" :class="getStatus(instance)">{{ getStatus(instance) }}</span> | ||||
| 					<span class="pubSub"> | ||||
| 						<span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span> | ||||
| 						<span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span> | ||||
| 						<span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span> | ||||
| 						<span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span> | ||||
| 				<span class="lastCommunicatedAt"><i class="fas fa-exchange-alt icon"></i><MkTime :time="instance.lastCommunicatedAt"/></span> | ||||
| 				<span class="latestStatus"><i class="fas fa-traffic-light icon"></i>{{ instance.latestStatus || '-' }}</span> | ||||
| 					</span> | ||||
| 					<span class="right"> | ||||
| 						<span class="latestStatus">{{ instance.latestStatus || '-' }}</span> | ||||
| 						<span class="lastCommunicatedAt"><MkTime :time="instance.lastCommunicatedAt"/></span> | ||||
| 					</span> | ||||
| 				</div> | ||||
| 			</MkA> | ||||
| 		</div> | ||||
| 	</MkPagination> | ||||
| </div> | ||||
|  | @ -59,7 +99,6 @@ import MkButton from '@client/components/ui/button.vue'; | |||
| import MkInput from '@client/components/ui/input.vue'; | ||||
| import MkSelect from '@client/components/ui/select.vue'; | ||||
| import MkPagination from '@client/components/ui/pagination.vue'; | ||||
| import MkInstanceInfo from './instance.vue'; | ||||
| import * as os from '@client/os'; | ||||
| import * as symbols from '@client/symbols'; | ||||
| 
 | ||||
|  | @ -117,69 +156,108 @@ export default defineComponent({ | |||
| 
 | ||||
| 	methods: { | ||||
| 		getStatus(instance) { | ||||
| 			if (instance.isSuspended) return 'off'; | ||||
| 			if (instance.isNotResponding) return 'red'; | ||||
| 			return 'green'; | ||||
| 			if (instance.isSuspended) return 'suspended'; | ||||
| 			if (instance.isNotResponding) return 'error'; | ||||
| 			return 'alive'; | ||||
| 		}, | ||||
| 
 | ||||
| 		info(instance) { | ||||
| 			os.popup(MkInstanceInfo, { | ||||
| 				instance: instance | ||||
| 			}, {}, 'closed'); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .enuoauvw { | ||||
| .taeiyria { | ||||
| 	> .query { | ||||
| 		margin: var(--margin); | ||||
| 		background: var(--bg); | ||||
| 		padding: 16px; | ||||
| 		border-bottom: solid 0.5px var(--divider); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| .ppgwaixt { | ||||
| 	cursor: pointer; | ||||
| .dqokceoi { | ||||
| 	display: grid; | ||||
| 	grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); | ||||
| 	grid-gap: 12px; | ||||
| 	padding: 16px; | ||||
| 
 | ||||
| 	> .instance { | ||||
| 		padding: 16px; | ||||
| 		border: solid 1px var(--divider); | ||||
| 		border-radius: 6px; | ||||
| 
 | ||||
| 		&:hover { | ||||
| 		color: var(--accent); | ||||
| 			border: solid 1px var(--accent); | ||||
| 			text-decoration: none; | ||||
| 		} | ||||
| 
 | ||||
| 		> .host { | ||||
| 		> .indicator { | ||||
| 			font-weight: bold; | ||||
| 			white-space: nowrap; | ||||
| 			overflow: hidden; | ||||
| 			text-overflow: ellipsis; | ||||
| 
 | ||||
| 			> img { | ||||
| 				width: 18px; | ||||
| 				height: 18px; | ||||
| 				margin-right: 6px; | ||||
| 				vertical-align: middle; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		> .table { | ||||
| 			display: grid; | ||||
| 			grid-template-columns: repeat(auto-fill, minmax(60px, 1fr)); | ||||
| 			grid-gap: 6px; | ||||
| 			margin: 6px 0; | ||||
| 			font-size: 70%; | ||||
| 			vertical-align: baseline; | ||||
| 			margin-right: 4px; | ||||
| 
 | ||||
| 			&.green { | ||||
| 				color: #49c5ba; | ||||
| 			> .cell { | ||||
| 				> .key, > .value { | ||||
| 					white-space: nowrap; | ||||
| 					overflow: hidden; | ||||
| 					text-overflow: ellipsis; | ||||
| 				} | ||||
| 
 | ||||
| 			&.yellow { | ||||
| 				color: #c5a549; | ||||
| 				> .key { | ||||
| 					opacity: 0.7; | ||||
| 				} | ||||
| 
 | ||||
| 			&.red { | ||||
| 				color: #c54949; | ||||
| 			} | ||||
| 
 | ||||
| 			&.off { | ||||
| 				color: rgba(0, 0, 0, 0.5); | ||||
| 				> .value { | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	> .status { | ||||
| 		> .footer { | ||||
| 			display: flex; | ||||
| 			align-items: center; | ||||
| 		font-size: 90%; | ||||
| 
 | ||||
| 		> span { | ||||
| 			flex: 1; | ||||
| 			> .status { | ||||
| 				&.suspended { | ||||
| 					opacity: 0.5; | ||||
| 				} | ||||
| 
 | ||||
| 			> .icon { | ||||
| 				margin-right: 6px; | ||||
| 				&.error { | ||||
| 					color: var(--error); | ||||
| 				} | ||||
| 
 | ||||
| 				&.alive { | ||||
| 					color: var(--success); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			> .pubSub { | ||||
| 				margin-left: 8px; | ||||
| 			} | ||||
| 
 | ||||
| 			> .right { | ||||
| 				margin-left: auto; | ||||
| 				font-size: 0.9em; | ||||
| 
 | ||||
| 				> .latestStatus { | ||||
| 					border: solid 1px var(--divider); | ||||
| 					border-radius: 4px; | ||||
| 					margin: 0 8px; | ||||
| 					padding: 0 4px; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -100,7 +100,7 @@ export default defineComponent({ | |||
| 				case 'overview': return defineAsyncComponent(() => import('./overview.vue')); | ||||
| 				case 'users': return defineAsyncComponent(() => import('./users.vue')); | ||||
| 				case 'emojis': return defineAsyncComponent(() => import('./emojis.vue')); | ||||
| 				case 'federation': return defineAsyncComponent(() => import('./federation.vue')); | ||||
| 				case 'federation': return defineAsyncComponent(() => import('../federation.vue')); | ||||
| 				case 'queue': return defineAsyncComponent(() => import('./queue.vue')); | ||||
| 				case 'files': return defineAsyncComponent(() => import('./files.vue')); | ||||
| 				case 'announcements': return defineAsyncComponent(() => import('./announcements.vue')); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue