連合しているインスタンスを一覧できるように
This commit is contained in:
parent
7275bc6d3b
commit
c3140f57b9
|
@ -1371,6 +1371,30 @@ admin/views/announcements.vue:
|
|||
admin/views/hashtags.vue:
|
||||
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:
|
||||
about: "詳しく..."
|
||||
gotit: "わかった"
|
||||
|
|
|
@ -124,7 +124,7 @@ export default Vue.extend({
|
|||
this.meta = meta;
|
||||
});
|
||||
|
||||
this.$root.api('instances', {
|
||||
this.$root.api('federation/instances', {
|
||||
sort: '+notes'
|
||||
}).then(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('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('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('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>
|
||||
|
@ -48,6 +48,7 @@
|
|||
<div v-if="page == 'announcements'"><x-announcements/></div>
|
||||
<div v-if="page == 'hashtags'"><x-hashtags/></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>
|
||||
</main>
|
||||
|
@ -68,7 +69,9 @@ import XHashtags from "./hashtags.vue";
|
|||
import XUsers from "./users.vue";
|
||||
import XDrive from "./drive.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';
|
||||
|
||||
// Detect the user agent
|
||||
|
@ -88,6 +91,7 @@ export default Vue.extend({
|
|||
XUsers,
|
||||
XDrive,
|
||||
XAbuse,
|
||||
XFederation,
|
||||
},
|
||||
provide: {
|
||||
isMobile
|
||||
|
@ -101,7 +105,7 @@ export default Vue.extend({
|
|||
faGrin,
|
||||
faArrowLeft,
|
||||
faHeadset,
|
||||
faShareAlt,
|
||||
faGlobe,
|
||||
faExclamationCircle,
|
||||
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