連合しているインスタンスを一覧できるように

This commit is contained in:
syuilo 2019-02-07 18:11:20 +09:00
parent 7275bc6d3b
commit c3140f57b9
No known key found for this signature in database
GPG key ID: BDC4C49D06AB9D69
7 changed files with 277 additions and 55 deletions

View file

@ -1371,6 +1371,30 @@ admin/views/announcements.vue:
admin/views/hashtags.vue: admin/views/hashtags.vue:
hided-tags: "Hidden Tags" hided-tags: "Hidden Tags"
admin/views/federation.vue:
federation: "連合"
host: "ホスト"
notes: "投稿"
users: "ユーザー"
following: "フォロー中"
followers: "フォロワー"
status: "ステータス"
lookup: "照会"
instances: "インスタンス"
instance-not-registered: "そのインスタンスは登録されていません"
sort: "ソート"
sorts:
caughtAtAsc: "登録日時が古い順"
caughtAtDesc: "登録日時が新しい順"
notesAsc: "投稿が少ない順"
notesDesc: "投稿が多い順"
usersAsc: "ユーザーが少ない順"
usersDesc: "ユーザーが多い順"
followingAsc: "フォローが少ない順"
followingDesc: "フォローが多い順"
followersAsc: "フォロワーが少ない順"
followersDesc: "フォロワーが多い順"
desktop/views/pages/welcome.vue: desktop/views/pages/welcome.vue:
about: "詳しく..." about: "詳しく..."
gotit: "わかった" gotit: "わかった"

View file

@ -124,7 +124,7 @@ export default Vue.extend({
this.meta = meta; this.meta = meta;
}); });
this.$root.api('instances', { this.$root.api('federation/instances', {
sort: '+notes' sort: '+notes'
}).then(instances => { }).then(instances => {
for (const i of instances) { for (const i of instances) {

View file

@ -0,0 +1,141 @@
<template>
<div>
<ui-card>
<div slot="title"><fa :icon="faTerminal"/> {{ $t('federation') }}</div>
<section class="fit-top">
<ui-input class="target" v-model="target" type="text" @enter="showInstance">
<span>{{ $t('host') }}</span>
</ui-input>
<ui-button @click="showInstance"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
<div class="instance" v-if="instance">
{{ instance.host }}
</div>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="faUsers"/> {{ $t('instances') }}</div>
<section class="fit-top">
<ui-horizon-group inputs>
<ui-select v-model="sort">
<span slot="label">{{ $t('sort') }}</span>
<option value="-caughtAt">{{ $t('sorts.caughtAtAsc') }}</option>
<option value="+caughtAt">{{ $t('sorts.caughtAtDesc') }}</option>
<option value="-notes">{{ $t('sorts.notesAsc') }}</option>
<option value="+notes">{{ $t('sorts.notesDesc') }}</option>
<option value="-users">{{ $t('sorts.usersAsc') }}</option>
<option value="+users">{{ $t('sorts.usersDesc') }}</option>
<option value="-following">{{ $t('sorts.followingAsc') }}</option>
<option value="+following">{{ $t('sorts.followingDesc') }}</option>
<option value="-followers">{{ $t('sorts.followersAsc') }}</option>
<option value="+followers">{{ $t('sorts.followersDesc') }}</option>
</ui-select>
</ui-horizon-group>
<div class="instances">
<header>
<span>{{ $t('host') }}</span>
<span>{{ $t('notes') }}</span>
<span>{{ $t('users') }}</span>
<span>{{ $t('following') }}</span>
<span>{{ $t('followers') }}</span>
<span>{{ $t('status') }}</span>
</header>
<div v-for="instance in instances">
<span>{{ instance.host }}</span>
<span>{{ instance.notesCount | number }}</span>
<span>{{ instance.usersCount | number }}</span>
<span>{{ instance.followingCount | number }}</span>
<span>{{ instance.followersCount | number }}</span>
<span>{{ instance.latestStatus }}</span>
</div>
</div>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faGlobe, faTerminal, faSearch } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/federation.vue'),
data() {
return {
instance: null,
target: null,
sort: '+caughtAt',
limit: 50,
instances: [],
faGlobe, faTerminal, faSearch
};
},
watch: {
sort() {
this.instances = [];
this.fetchInstances();
},
},
mounted() {
this.fetchInstances();
},
methods: {
showInstance() {
this.$root.api('federation/show-instance', {
host: this.target
}).then(instance => {
if (instance == null) {
this.$root.dialog({
type: 'error',
text: this.$t('instance-not-registered')
});
} else {
this.instance = instance;
this.target = '';
}
});
},
fetchInstances() {
this.$root.api('federation/instances', {
sort: this.sort
}).then(instances => {
this.instances = instances;
});
}
}
});
</script>
<style lang="stylus" scoped>
.target
margin-bottom 16px !important
.instances
width 100%
> header
display flex
> *
color var(--text)
font-weight bold
> div
display flex
> * > *
flex 1
overflow auto
&:first-child
min-width 200px
</style>

View file

@ -24,7 +24,7 @@
<li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li> <li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li>
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li> <li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
<li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li> <li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li>
<!-- <li @click="nav('federation')" :class="{ active: page == 'federation' }"><fa :icon="faShareAlt" fixed-width/>{{ $t('federation') }}</li> --> <li @click="nav('federation')" :class="{ active: page == 'federation' }"><fa :icon="faGlobe" fixed-width/>{{ $t('federation') }}</li>
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="faGrin" fixed-width/>{{ $t('emoji') }}</li> <li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="faGrin" fixed-width/>{{ $t('emoji') }}</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</li> <li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</li>
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>{{ $t('hashtags') }}</li> <li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>{{ $t('hashtags') }}</li>
@ -48,6 +48,7 @@
<div v-if="page == 'announcements'"><x-announcements/></div> <div v-if="page == 'announcements'"><x-announcements/></div>
<div v-if="page == 'hashtags'"><x-hashtags/></div> <div v-if="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'drive'"><x-drive/></div> <div v-if="page == 'drive'"><x-drive/></div>
<div v-if="page == 'federation'"><x-federation/></div>
<div v-if="page == 'abuse'"><x-abuse/></div> <div v-if="page == 'abuse'"><x-abuse/></div>
</div> </div>
</main> </main>
@ -68,7 +69,9 @@ import XHashtags from "./hashtags.vue";
import XUsers from "./users.vue"; import XUsers from "./users.vue";
import XDrive from "./drive.vue"; import XDrive from "./drive.vue";
import XAbuse from "./abuse.vue"; import XAbuse from "./abuse.vue";
import { faHeadset, faArrowLeft, faShareAlt, faExclamationCircle, faTasks } from '@fortawesome/free-solid-svg-icons'; import XFederation from "./federation.vue";
import { faHeadset, faArrowLeft, faGlobe, faExclamationCircle, faTasks } from '@fortawesome/free-solid-svg-icons';
import { faGrin } from '@fortawesome/free-regular-svg-icons'; import { faGrin } from '@fortawesome/free-regular-svg-icons';
// Detect the user agent // Detect the user agent
@ -88,6 +91,7 @@ export default Vue.extend({
XUsers, XUsers,
XDrive, XDrive,
XAbuse, XAbuse,
XFederation,
}, },
provide: { provide: {
isMobile isMobile
@ -101,7 +105,7 @@ export default Vue.extend({
faGrin, faGrin,
faArrowLeft, faArrowLeft,
faHeadset, faHeadset,
faShareAlt, faGlobe,
faExclamationCircle, faExclamationCircle,
faTasks faTasks
}; };

View file

@ -0,0 +1,84 @@
import $ from 'cafy';
import define from '../../define';
import Instance from '../../../../models/instance';
export const meta = {
requireCredential: false,
params: {
limit: {
validator: $.num.optional.range(1, 100),
default: 30
},
offset: {
validator: $.num.optional.min(0),
default: 0
},
sort: {
validator: $.str.optional,
}
}
};
export default define(meta, (ps, me) => new Promise(async (res, rej) => {
let sort;
if (ps.sort) {
if (ps.sort == '+notes') {
sort = {
notesCount: -1
};
} else if (ps.sort == '-notes') {
sort = {
notesCount: 1
};
} else if (ps.sort == '+users') {
sort = {
usersCount: -1
};
} else if (ps.sort == '-users') {
sort = {
usersCount: 1
};
} else if (ps.sort == '+following') {
sort = {
followingCount: -1
};
} else if (ps.sort == '-following') {
sort = {
followingCount: 1
};
} else if (ps.sort == '+followers') {
sort = {
followersCount: -1
};
} else if (ps.sort == '-followers') {
sort = {
followersCount: 1
};
} else if (ps.sort == '+caughtAt') {
sort = {
caughtAt: -1
};
} else if (ps.sort == '-caughtAt') {
sort = {
caughtAt: 1
};
}
} else {
sort = {
_id: -1
};
}
const instances = await Instance
.find({}, {
limit: ps.limit,
sort: sort,
skip: ps.offset
});
res(instances);
}));

View file

@ -0,0 +1,20 @@
import $ from 'cafy';
import define from '../../define';
import Instance from '../../../../models/instance';
export const meta = {
requireCredential: false,
params: {
host: {
validator: $.str
}
}
};
export default define(meta, (ps, me) => new Promise(async (res, rej) => {
const instance = await Instance
.findOne({ host: ps.host });
res(instance);
}));

View file

@ -1,51 +0,0 @@
import $ from 'cafy';
import define from '../define';
import Instance from '../../../models/instance';
export const meta = {
requireCredential: false,
params: {
limit: {
validator: $.num.optional.range(1, 100),
default: 30
},
offset: {
validator: $.num.optional.min(0),
default: 0
},
sort: {
validator: $.str.optional.or('+notes|-notes'),
}
}
};
export default define(meta, (ps, me) => new Promise(async (res, rej) => {
let _sort;
if (ps.sort) {
if (ps.sort == '+notes') {
_sort = {
notesCount: -1
};
} else if (ps.sort == '-notes') {
_sort = {
notesCount: 1
};
}
} else {
_sort = {
_id: -1
};
}
const instances = await Instance
.find({}, {
limit: ps.limit,
sort: _sort,
skip: ps.offset
});
res(instances);
}));