From 186b26e103d5dc893a741ab9c5805b5dc81f14c0 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 25 Jul 2020 11:56:56 +0900
Subject: [PATCH] feat(client): Federation widget

Resolve #6544
---
 locales/ja-JP.yml                 |   1 +
 src/client/widgets/federation.vue | 111 ++++++++++++++++++++++++++++++
 src/client/widgets/index.ts       |   2 +
 3 files changed, 114 insertions(+)
 create mode 100644 src/client/widgets/federation.vue

diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index a073d789a2..ec767aafa9 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -732,6 +732,7 @@ _widgets:
   activity: "アクティビティ"
   photos: "フォト"
   digitalClock: "デジタル時計"
+  federation: "連合"
 
 _cw:
   hide: "隠す"
diff --git a/src/client/widgets/federation.vue b/src/client/widgets/federation.vue
new file mode 100644
index 0000000000..b99ef1b0aa
--- /dev/null
+++ b/src/client/widgets/federation.vue
@@ -0,0 +1,111 @@
+<template>
+<mk-container :show-header="props.showHeader">
+	<template #header><fa :icon="faGlobe"/>{{ $t('_widgets.federation') }}</template>
+
+	<div class="wbrkwalb">
+		<mk-loading v-if="fetching"/>
+		<transition-group tag="div" name="chart" class="instances" v-else>
+			<div v-for="instance in instances" :key="instance.id">
+				<div class="instance">
+					<a class="a" :href="'https://' + instance.host" target="_blank" :title="instance.host">#{{ instance.host }}</a>
+					<p>{{ instance.softwareName }} {{ instance.softwareVersion }}</p>
+				</div>
+				<x-chart class="chart" :src="stat.chart"/>
+			</div>
+		</transition-group>
+	</div>
+</mk-container>
+</template>
+
+<script lang="ts">
+import { faGlobe } from '@fortawesome/free-solid-svg-icons';
+import MkContainer from '../components/ui/container.vue';
+import define from './define';
+import XChart from './trends.chart.vue';
+
+export default define({
+	name: 'federation',
+	props: () => ({
+		showHeader: {
+			type: 'boolean',
+			default: true,
+		},
+	})
+}).extend({
+	components: {
+		MkContainer, XChart
+	},
+	data() {
+		return {
+			instances: [],
+			fetching: true,
+			faGlobe
+		};
+	},
+	mounted() {
+		this.fetch();
+		this.clock = setInterval(this.fetch, 1000 * 60);
+	},
+	beforeDestroy() {
+		clearInterval(this.clock);
+	},
+	methods: {
+		fetch() {
+			this.$root.api('federation/instances', {
+				sort: '+lastCommunicatedAt',
+				limit: 5
+			}).then(instances => {
+				this.instances = instances;
+				this.fetching = false;
+			});
+		}
+	}
+});
+</script>
+
+<style lang="scss" scoped>
+.wbrkwalb {
+	height: (62px + 1px) + (62px + 1px) + (62px + 1px) + (62px + 1px) + 62px;
+	overflow: hidden;
+
+	> .instances {
+		.chart-move {
+			transition: transform 1s ease;
+		}
+
+		> div {
+			display: flex;
+			align-items: center;
+			padding: 14px 16px;
+			border-bottom: solid 1px var(--divider);
+
+			> .instance {
+				flex: 1;
+				overflow: hidden;
+				font-size: 0.9em;
+				color: var(--fg);
+
+				> .a {
+					display: block;
+					width: 100%;
+					white-space: nowrap;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					line-height: 18px;
+				}
+
+				> p {
+					margin: 0;
+					font-size: 75%;
+					opacity: 0.7;
+					line-height: 16px;
+				}
+			}
+
+			> .chart {
+				height: 30px;
+			}
+		}
+	}
+}
+</style>
diff --git a/src/client/widgets/index.ts b/src/client/widgets/index.ts
index 2d27d27e58..743146193c 100644
--- a/src/client/widgets/index.ts
+++ b/src/client/widgets/index.ts
@@ -11,6 +11,7 @@ Vue.component('mkw-clock', () => import('./clock.vue').then(m => m.default));
 Vue.component('mkw-activity', () => import('./activity.vue').then(m => m.default));
 Vue.component('mkw-photos', () => import('./photos.vue').then(m => m.default));
 Vue.component('mkw-digitalClock', () => import('./digital-clock.vue').then(m => m.default));
+Vue.component('mkw-federation', () => import('./federation.vue').then(m => m.default));
 
 export const widgets = [
 	'memo',
@@ -23,4 +24,5 @@ export const widgets = [
 	'activity',
 	'photos',
 	'digitalClock',
+	'federation',
 ];