mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-27 06:00:21 +01:00
連合しているインスタンスを一覧できるように
This commit is contained in:
parent
7275bc6d3b
commit
c3140f57b9
7 changed files with 277 additions and 55 deletions
|
@ -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: "わかった"
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
141
src/client/app/admin/views/federation.vue
Normal file
141
src/client/app/admin/views/federation.vue
Normal 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>
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
84
src/server/api/endpoints/federation/instances.ts
Normal file
84
src/server/api/endpoints/federation/instances.ts
Normal 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);
|
||||||
|
}));
|
20
src/server/api/endpoints/federation/show-instance.ts
Normal file
20
src/server/api/endpoints/federation/show-instance.ts
Normal 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);
|
||||||
|
}));
|
|
@ -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);
|
|
||||||
}));
|
|
Loading…
Reference in a new issue