feat(frontend): ユーザーリスト管理でユーザー数とロールポリシーの登録可能ユーザー数を表示するなど (#11231)

* feat(frontend): ユーザーリスト一覧で、ユーザー数とロールポリシーの登録可能ユーザー数を表示する

* ✌️

* fix

* fix

* wip

* loading

* fix
This commit is contained in:
tamaina 2023-07-15 13:53:09 +09:00 committed by GitHub
parent 54625914c5
commit c926a61e07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 12 deletions

View File

@ -14,7 +14,7 @@
<div v-if="items.length > 0" class="_gaps"> <div v-if="items.length > 0" class="_gaps">
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/my/lists/${ list.id }`"> <MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/my/lists/${ list.id }`">
<div style="margin-bottom: 4px;">{{ list.name }}</div> <div style="margin-bottom: 4px;">{{ list.name }} <span :class="$style.nUsers">({{ i18n.t('nUsers', { n: `${list.userIds.length}/${$i?.policies['userEachUserListsLimit']}` }) }})</span></div>
<MkAvatars :userIds="list.userIds" :limit="10"/> <MkAvatars :userIds="list.userIds" :limit="10"/>
</MkA> </MkA>
</div> </div>
@ -32,6 +32,7 @@ import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
import { userListsCache } from '@/cache'; import { userListsCache } from '@/cache';
import { infoImageUrl } from '@/instance'; import { infoImageUrl } from '@/instance';
import { $i } from '@/account';
const items = $computed(() => userListsCache.value.value ?? []); const items = $computed(() => userListsCache.value.value ?? []);
@ -66,10 +67,6 @@ const headerTabs = $computed(() => []);
definePageMetadata({ definePageMetadata({
title: i18n.ts.manageLists, title: i18n.ts.manageLists,
icon: 'ti ti-list', icon: 'ti ti-list',
action: {
icon: 'ti ti-plus',
handler: create,
},
}); });
onActivated(() => { onActivated(() => {
@ -90,4 +87,9 @@ onActivated(() => {
text-decoration: none; text-decoration: none;
} }
} }
.nUsers {
font-size: .9em;
opacity: .7;
}
</style> </style>

View File

@ -20,6 +20,7 @@
<MkFolder defaultOpen> <MkFolder defaultOpen>
<template #label>{{ i18n.ts.members }}</template> <template #label>{{ i18n.ts.members }}</template>
<template #caption>{{ i18n.t('nUsers', { n: `${list.userIds.length}/${$i?.policies['userEachUserListsLimit']}` }) }}</template>
<div class="_gaps_s"> <div class="_gaps_s">
<MkButton rounded primary style="margin: 0 auto;" @click="addUser()">{{ i18n.ts.addUser }}</MkButton> <MkButton rounded primary style="margin: 0 auto;" @click="addUser()">{{ i18n.ts.addUser }}</MkButton>
@ -29,6 +30,10 @@
</MkA> </MkA>
<button class="_button" :class="$style.remove" @click="removeUser(user, $event)"><i class="ti ti-x"></i></button> <button class="_button" :class="$style.remove" @click="removeUser(user, $event)"><i class="ti ti-x"></i></button>
</div> </div>
<MkButton v-if="!fetching && queueUserIds.length !== 0" v-appear="enableInfiniteScroll ? fetchMoreUsers : null" :class="$style.more" :style="{ cursor: 'pointer' }" primary rounded @click="fetchMoreUsers">
{{ i18n.ts.loadMore }}
</MkButton>
<MkLoading v-if="fetching" class="loading"/>
</div> </div>
</MkFolder> </MkFolder>
</div> </div>
@ -49,34 +54,57 @@ import MkSwitch from '@/components/MkSwitch.vue';
import MkFolder from '@/components/MkFolder.vue'; import MkFolder from '@/components/MkFolder.vue';
import MkInput from '@/components/MkInput.vue'; import MkInput from '@/components/MkInput.vue';
import { userListsCache } from '@/cache'; import { userListsCache } from '@/cache';
import { UserList, UserLite } from 'misskey-js/built/entities';
import { $i } from '@/account';
import { defaultStore } from '@/store';
const {
enableInfiniteScroll,
} = defaultStore.reactiveState;
const props = defineProps<{ const props = defineProps<{
listId: string; listId: string;
}>(); }>();
let list = $ref(null); const FETCH_USERS_LIMIT = 20;
let users = $ref([]);
let list = $ref<UserList | null>(null);
let users = $ref<UserLite[]>([]);
let queueUserIds = $ref<string[]>([]);
let fetching = $ref(true);
const isPublic = ref(false); const isPublic = ref(false);
const name = ref(''); const name = ref('');
function fetchList() { function fetchList() {
fetching = true;
os.api('users/lists/show', { os.api('users/lists/show', {
listId: props.listId, listId: props.listId,
}).then(_list => { }).then(_list => {
list = _list; list = _list;
name.value = list.name; name.value = list.name;
isPublic.value = list.isPublic; isPublic.value = list.isPublic;
queueUserIds = list.userIds;
os.api('users/show', { return fetchMoreUsers();
userIds: list.userIds,
}).then(_users => {
users = _users;
}); });
}
function fetchMoreUsers() {
if (!list) return;
if (fetching && users.length !== 0) return; // fetchingtrueusers
fetching = true;
os.api('users/show', {
userIds: queueUserIds.slice(0, FETCH_USERS_LIMIT),
}).then(_users => {
users = users.concat(_users);
queueUserIds = queueUserIds.slice(FETCH_USERS_LIMIT);
}).finally(() => {
fetching = false;
}); });
} }
function addUser() { function addUser() {
os.selectUser().then(user => { os.selectUser().then(user => {
if (!list) return;
os.apiWithDialog('users/lists/push', { os.apiWithDialog('users/lists/push', {
listId: list.id, listId: list.id,
userId: user.id, userId: user.id,
@ -92,6 +120,7 @@ async function removeUser(user, ev) {
icon: 'ti ti-x', icon: 'ti ti-x',
danger: true, danger: true,
action: async () => { action: async () => {
if (!list) return;
os.api('users/lists/pull', { os.api('users/lists/pull', {
listId: list.id, listId: list.id,
userId: user.id, userId: user.id,
@ -103,6 +132,7 @@ async function removeUser(user, ev) {
} }
async function deleteList() { async function deleteList() {
if (!list) return;
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
type: 'warning', type: 'warning',
text: i18n.t('removeAreYouSure', { x: list.name }), text: i18n.t('removeAreYouSure', { x: list.name }),
@ -117,6 +147,7 @@ async function deleteList() {
} }
async function updateSettings() { async function updateSettings() {
if (!list) return;
await os.apiWithDialog('users/lists/update', { await os.apiWithDialog('users/lists/update', {
listId: list.id, listId: list.id,
name: name.value, name: name.value,
@ -166,6 +197,11 @@ definePageMetadata(computed(() => list ? {
align-self: center; align-self: center;
} }
.more {
margin-left: auto;
margin-right: auto;
}
.footer { .footer {
-webkit-backdrop-filter: var(--blur, blur(15px)); -webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px)); backdrop-filter: var(--blur, blur(15px));