diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2025-06-29 15:11:25 +0900 |
|---|---|---|
| committer | syuilo <4439005+syuilo@users.noreply.github.com> | 2025-06-29 15:11:25 +0900 |
| commit | f1deb89e348eb8f1a39b51e33a0ae33d59529feb (patch) | |
| tree | 2e92a7a21a1bf377719e1b125a9ac44bc14a529e /packages/frontend/src/pages/admin | |
| parent | feat(backend): クリップ内でノートを検索できるように (diff) | |
| download | misskey-f1deb89e348eb8f1a39b51e33a0ae33d59529feb.tar.gz misskey-f1deb89e348eb8f1a39b51e33a0ae33d59529feb.tar.bz2 misskey-f1deb89e348eb8f1a39b51e33a0ae33d59529feb.zip | |
refactor(frontend): improve pagination implementation
Diffstat (limited to 'packages/frontend/src/pages/admin')
| -rw-r--r-- | packages/frontend/src/pages/admin/abuses.vue | 18 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/federation.vue | 12 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/files.vue | 15 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/invites.vue | 23 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/modlog.vue | 40 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/roles.role.vue | 12 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/users.vue | 17 |
7 files changed, 58 insertions, 79 deletions
diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index 4dbb573ceb..ab462229a7 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -41,13 +41,13 @@ SPDX-License-Identifier: AGPL-3.0-only <MkInput v-model="searchUsername" style="margin: 0; flex: 1;" type="text" :spellcheck="false"> <span>{{ i18n.ts.username }}</span> </MkInput> - <MkInput v-model="searchHost" style="margin: 0; flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params().origin === 'local'"> + <MkInput v-model="searchHost" style="margin: 0; flex: 1;" type="text" :spellcheck="false" :disabled="paginator.computedParams.value.origin === 'local'"> <span>{{ i18n.ts.host }}</span> </MkInput> </div> --> - <MkPagination v-slot="{items}" ref="reports" :pagination="pagination"> + <MkPagination v-slot="{items}" :paginator="paginator"> <div class="_gaps"> <XAbuseReport v-for="report in items" :key="report.id" :report="report" @resolved="resolved"/> </div> @@ -58,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, useTemplateRef, ref } from 'vue'; +import { computed, ref, markRaw } from 'vue'; import MkSelect from '@/components/MkSelect.vue'; import MkPagination from '@/components/MkPagination.vue'; import XAbuseReport from '@/components/MkAbuseReport.vue'; @@ -66,8 +66,7 @@ import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import MkButton from '@/components/MkButton.vue'; import { store } from '@/store.js'; - -const reports = useTemplateRef('reports'); +import { Paginator } from '@/utility/paginator.js'; const state = ref('unresolved'); const reporterOrigin = ref('combined'); @@ -75,18 +74,17 @@ const targetUserOrigin = ref('combined'); const searchUsername = ref(''); const searchHost = ref(''); -const pagination = { - endpoint: 'admin/abuse-user-reports' as const, +const paginator = markRaw(new Paginator('admin/abuse-user-reports', { limit: 10, - params: computed(() => ({ + computedParams: computed(() => ({ state: state.value, reporterOrigin: reporterOrigin.value, targetUserOrigin: targetUserOrigin.value, })), -}; +})); function resolved(reportId) { - reports.value?.paginator.removeItem(reportId); + paginator.removeItem(reportId); } const headerActions = computed(() => []); diff --git a/packages/frontend/src/pages/admin/federation.vue b/packages/frontend/src/pages/admin/federation.vue index 73b25277b3..ddc3ff7b79 100644 --- a/packages/frontend/src/pages/admin/federation.vue +++ b/packages/frontend/src/pages/admin/federation.vue @@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only </FormSplit> </div> - <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination"> + <MkPagination v-slot="{items}" :key="host + state" :paginator="paginator"> <div :class="$style.instances"> <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" :class="$style.instance" :to="`/instance-info/${instance.host}`"> <MkInstanceCardMini :instance="instance"/> @@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import * as Misskey from 'misskey-js'; -import { computed, ref } from 'vue'; +import { computed, markRaw, ref } from 'vue'; import MkInput from '@/components/MkInput.vue'; import MkSelect from '@/components/MkSelect.vue'; import MkPagination from '@/components/MkPagination.vue'; @@ -64,15 +64,15 @@ import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue'; import FormSplit from '@/components/form/split.vue'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; +import { Paginator } from '@/utility/paginator.js'; const host = ref(''); const state = ref('federating'); const sort = ref('+pubSub'); -const pagination = { - endpoint: 'federation/instances' as const, +const paginator = markRaw(new Paginator('federation/instances', { limit: 10, offsetMode: true, - params: computed(() => ({ + computedParams: computed(() => ({ sort: sort.value, host: host.value !== '' ? host.value : null, ...( @@ -85,7 +85,7 @@ const pagination = { state.value === 'notResponding' ? { notResponding: true } : {}), })), -}; +})); function getStatus(instance: Misskey.entities.FederationInstance) { switch (instance.suspensionState) { diff --git a/packages/frontend/src/pages/admin/files.vue b/packages/frontend/src/pages/admin/files.vue index 4ea5756284..0f3a90b458 100644 --- a/packages/frontend/src/pages/admin/files.vue +++ b/packages/frontend/src/pages/admin/files.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only <option value="local">{{ i18n.ts.local }}</option> <option value="remote">{{ i18n.ts.remote }}</option> </MkSelect> - <MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="pagination.params.origin === 'local'"> + <MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="paginator.computedParams.value.origin === 'local'"> <template #label>{{ i18n.ts.host }}</template> </MkInput> </div> @@ -26,14 +26,14 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>MIME type</template> </MkInput> </div> - <MkFileListForAdmin :pagination="pagination" :viewMode="viewMode"/> + <MkFileListForAdmin :paginator="paginator" :viewMode="viewMode"/> </div> </div> </PageWithHeader> </template> <script lang="ts" setup> -import { computed, ref } from 'vue'; +import { computed, markRaw, ref } from 'vue'; import * as Misskey from 'misskey-js'; import MkInput from '@/components/MkInput.vue'; import MkSelect from '@/components/MkSelect.vue'; @@ -42,23 +42,22 @@ import * as os from '@/os.js'; import { lookupFile } from '@/utility/admin-lookup.js'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; -import type { PagingCtx } from '@/composables/use-pagination.js'; +import { Paginator } from '@/utility/paginator.js'; const origin = ref<Misskey.entities.AdminDriveFilesRequest['origin']>('local'); const type = ref<string | null>(null); const searchHost = ref(''); const userId = ref(''); const viewMode = ref<'grid' | 'list'>('grid'); -const pagination = { - endpoint: 'admin/drive/files' as const, +const paginator = markRaw(new Paginator('admin/drive/files', { limit: 10, - params: computed(() => ({ + computedParams: computed(() => ({ type: (type.value && type.value !== '') ? type.value : null, userId: (userId.value && userId.value !== '') ? userId.value : null, origin: origin.value, hostname: (searchHost.value && searchHost.value !== '') ? searchHost.value : null, })), -} satisfies PagingCtx<'admin/drive/files'>; +})); function clear() { os.confirm({ diff --git a/packages/frontend/src/pages/admin/invites.vue b/packages/frontend/src/pages/admin/invites.vue index f1584fc864..e1b4890513 100644 --- a/packages/frontend/src/pages/admin/invites.vue +++ b/packages/frontend/src/pages/admin/invites.vue @@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkInput v-if="!noExpirationDate" v-model="expiresAt" type="datetime-local"> <template #label>{{ i18n.ts.expirationDate }}</template> </MkInput> - <MkInput v-model="createCount" type="number" min="1"> + <MkInput v-model="createCount" type="number" :min="1"> <template #label>{{ i18n.ts.createCount }}</template> </MkInput> <MkButton primary rounded @click="createWithOptions">{{ i18n.ts.create }}</MkButton> @@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only <option value="-usedAt">{{ i18n.ts.usedAt }} ({{ i18n.ts.descendingOrder }})</option> </MkSelect> </div> - <MkPagination ref="pagingComponent" :pagination="pagination"> + <MkPagination :paginator="paginator"> <template #default="{ items }"> <div class="_gaps_s"> <MkInviteCode v-for="item in items" :key="item.id" :invite="(item as any)" :onDeleted="deleted" moderator/> @@ -54,8 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, ref, useTemplateRef } from 'vue'; -import type { PagingCtx } from '@/composables/use-pagination.js'; +import { computed, markRaw, ref, useTemplateRef } from 'vue'; import { i18n } from '@/i18n.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; @@ -67,21 +66,19 @@ import MkSwitch from '@/components/MkSwitch.vue'; import MkPagination from '@/components/MkPagination.vue'; import MkInviteCode from '@/components/MkInviteCode.vue'; import { definePage } from '@/page.js'; - -const pagingComponent = useTemplateRef('pagingComponent'); +import { Paginator } from '@/utility/paginator.js'; const type = ref('all'); const sort = ref('+createdAt'); -const pagination: PagingCtx = { - endpoint: 'admin/invite/list' as const, +const paginator = markRaw(new Paginator('admin/invite/list', { limit: 10, - params: computed(() => ({ + computedParams: computed(() => ({ type: type.value, sort: sort.value, })), offsetMode: true, -}; +})); const expiresAt = ref(''); const noExpirationDate = ref(true); @@ -100,13 +97,11 @@ async function createWithOptions() { text: tickets.map(x => x.code).join('\n'), }); - tickets.forEach(ticket => pagingComponent.value?.paginator.prepend(ticket)); + tickets.forEach(ticket => paginator.prepend(ticket)); } function deleted(id: string) { - if (pagingComponent.value) { - pagingComponent.value.paginator.removeItem(id); - } + paginator.removeItem(id); } const headerActions = computed(() => []); diff --git a/packages/frontend/src/pages/admin/modlog.vue b/packages/frontend/src/pages/admin/modlog.vue index 76b313026b..6a6102749e 100644 --- a/packages/frontend/src/pages/admin/modlog.vue +++ b/packages/frontend/src/pages/admin/modlog.vue @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only <PageWithHeader :actions="headerActions" :tabs="headerTabs"> <div class="_spacer" style="--MI_SPACER-w: 900px;"> <div class="_gaps"> - <MkPaginationControl v-model:order="order" v-model:date="date" v-model:q="q" canSearch canFilter @reload="paginator.reload()"> + <MkPaginationControl :paginator="paginator" canFilter> <MkSelect v-model="type" style="margin: 0; flex: 1;"> <template #label>{{ i18n.ts.type }}</template> <option :value="null">{{ i18n.ts.all }}</option> @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, useTemplateRef, ref, watch } from 'vue'; +import { computed, ref, markRaw, onMounted } from 'vue'; import * as Misskey from 'misskey-js'; import XModLog from './modlog.ModLog.vue'; import MkSelect from '@/components/MkSelect.vue'; @@ -54,37 +54,25 @@ import MkTl from '@/components/MkTl.vue'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { prefer } from '@/preferences.js'; -import { usePagination } from '@/composables/use-pagination.js'; import MkPullToRefresh from '@/components/MkPullToRefresh.vue'; import MkButton from '@/components/MkButton.vue'; import MkPaginationControl from '@/components/MkPaginationControl.vue'; +import { Paginator } from '@/utility/paginator.js'; -const order = ref<'newest' | 'oldest'>('newest'); -const date = ref<number | null>(null); const type = ref<string | null>(null); const moderatorId = ref(''); -const q = ref<string | null>(null); -const paginator = usePagination({ - ctx: { - endpoint: 'admin/show-moderation-logs', - limit: 20, - canFetchDetection: 'limit', - params: computed(() => ({ - type: type.value, - userId: moderatorId.value === '' ? null : moderatorId.value, - search: q.value, - })), - }, -}); +const paginator = markRaw(new Paginator('admin/show-moderation-logs', { + limit: 20, + canFetchDetection: 'limit', + canSearch: true, + computedParams: computed(() => ({ + type: type.value, + userId: moderatorId.value === '' ? null : moderatorId.value, + })), +})); -watch([order, date], () => { - paginator.updateCtxPartial({ - order: order.value, - initialDirection: order.value === 'oldest' ? 'newer' : 'older', - initialDate: date.value, - }); -}, { immediate: false }); +paginator.init(); const timeline = computed(() => { return paginator.items.value.map(x => ({ @@ -95,7 +83,7 @@ const timeline = computed(() => { }); function fetchMore() { - if (order.value === 'oldest') { + if (paginator.order.value === 'oldest') { paginator.fetchNewer(); } else { paginator.fetchOlder(); diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue index 61d72777b8..64b6231398 100644 --- a/packages/frontend/src/pages/admin/roles.role.vue +++ b/packages/frontend/src/pages/admin/roles.role.vue @@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps"> <MkButton primary rounded @click="assign"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton> - <MkPagination :pagination="usersPagination"> + <MkPagination :paginator="usersPaginator"> <template #empty><MkResult type="empty" :text="i18n.ts.noUsers"/></template> <template #default="{ items }"> @@ -54,7 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, reactive, ref } from 'vue'; +import { computed, markRaw, reactive, ref } from 'vue'; import XEditor from './roles.editor.vue'; import MkFolder from '@/components/MkFolder.vue'; import * as os from '@/os.js'; @@ -66,6 +66,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkInfo from '@/components/MkInfo.vue'; import MkPagination from '@/components/MkPagination.vue'; import { useRouter } from '@/router.js'; +import { Paginator } from '@/utility/paginator.js'; const router = useRouter(); @@ -73,13 +74,12 @@ const props = defineProps<{ id?: string; }>(); -const usersPagination = { - endpoint: 'admin/roles/users' as const, +const usersPaginator = markRaw(new Paginator('admin/roles/users', { limit: 20, - params: computed(() => ({ + computedParams: computed(() => ({ roleId: props.id, })), -}; +})); const expandedItems = ref([]); diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index 56cf8876f0..581eb7eb97 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -38,13 +38,13 @@ SPDX-License-Identifier: AGPL-3.0-only <template #prefix>@</template> <template #label>{{ i18n.ts.username }}</template> </MkInput> - <MkInput v-model="searchHost" style="flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params.origin === 'local'"> + <MkInput v-model="searchHost" style="flex: 1;" type="text" :spellcheck="false" :disabled="paginator.computedParams.value.origin === 'local'"> <template #prefix>@</template> <template #label>{{ i18n.ts.host }}</template> </MkInput> </div> - <MkPagination v-slot="{items}" ref="paginationComponent" :pagination="pagination"> + <MkPagination v-slot="{items}" :paginator="paginator"> <div :class="$style.users"> <MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" :class="$style.user" :to="`/admin/user/${user.id}`"> <MkUserCardMini :user="user"/> @@ -57,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, useTemplateRef, ref, watchEffect } from 'vue'; +import { computed, markRaw, ref, watchEffect } from 'vue'; import { defaultMemoryStorage } from '@/memory-storage'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; @@ -69,6 +69,7 @@ import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import { dateString } from '@/filters/date.js'; +import { Paginator } from '@/utility/paginator.js'; type SearchQuery = { sort?: string; @@ -78,7 +79,6 @@ type SearchQuery = { hostname?: string; }; -const paginationComponent = useTemplateRef('paginationComponent'); const storedQuery = JSON.parse(defaultMemoryStorage.getItem('admin-users-query') ?? '{}') as SearchQuery; const sort = ref(storedQuery.sort ?? '+createdAt'); @@ -86,10 +86,9 @@ const state = ref(storedQuery.state ?? 'all'); const origin = ref(storedQuery.origin ?? 'local'); const searchUsername = ref(storedQuery.username ?? ''); const searchHost = ref(storedQuery.hostname ?? ''); -const pagination = { - endpoint: 'admin/show-users' as const, +const paginator = markRaw(new Paginator('admin/show-users', { limit: 10, - params: computed(() => ({ + computedParams: computed(() => ({ sort: sort.value, state: state.value, origin: origin.value, @@ -97,7 +96,7 @@ const pagination = { hostname: searchHost.value, })), offsetMode: true, -}; +})); function searchUser() { os.selectUser({ includeSelf: true }).then(user => { @@ -121,7 +120,7 @@ async function addUser() { username: username, password: password, }).then(res => { - paginationComponent.value?.paginator.reload(); + paginator.reload(); }); } |