From bbef2a953ebf2f7f063641e6764ec8571cd78b75 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 13 Aug 2023 21:02:25 +0900 Subject: [PATCH] enhance(frontend): tweak user moderation page --- .../frontend/src/components/MkAbuseReport.vue | 2 +- packages/frontend/src/pages/admin-file.vue | 2 +- .../pages/{user-info.vue => admin-user.vue} | 225 +++++++++--------- .../src/pages/admin/overview.moderators.vue | 2 +- .../src/pages/admin/overview.users.vue | 2 +- .../frontend/src/pages/admin/roles.role.vue | 2 +- packages/frontend/src/pages/admin/users.vue | 4 +- packages/frontend/src/pages/instance-info.vue | 2 +- .../src/pages/settings/mute-block.vue | 6 +- packages/frontend/src/router.ts | 7 +- .../frontend/src/scripts/get-user-menu.ts | 10 +- packages/frontend/src/scripts/lookup-user.ts | 2 +- 12 files changed, 127 insertions(+), 139 deletions(-) rename packages/frontend/src/pages/{user-info.vue => admin-user.vue} (70%) diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue index d46e5da064..cb97875bcd 100644 --- a/packages/frontend/src/components/MkAbuseReport.vue +++ b/packages/frontend/src/components/MkAbuseReport.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div class="bcekxzvu _margin _panel"> <div class="target"> - <MkA v-user-preview="report.targetUserId" class="info" :to="`/user-info/${report.targetUserId}`"> + <MkA v-user-preview="report.targetUserId" class="info" :to="`/admin/user/${report.targetUserId}`"> <MkAvatar class="avatar" :user="report.targetUser" indicator/> <div class="names"> <MkUserName class="name" :user="report.targetUser"/> diff --git a/packages/frontend/src/pages/admin-file.vue b/packages/frontend/src/pages/admin-file.vue index 2614b20c28..4083c02049 100644 --- a/packages/frontend/src/pages/admin-file.vue +++ b/packages/frontend/src/pages/admin-file.vue @@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #value><span class="_monospace"><MkTime :time="file.createdAt" mode="detail" style="display: block;"/></span></template> </MkKeyValue> </div> - <MkA v-if="file.user" class="user" :to="`/user-info/${file.user.id}`"> + <MkA v-if="file.user" class="user" :to="`/admin/user/${file.user.id}`"> <MkUserCardMini :user="file.user"/> </MkA> <div> diff --git a/packages/frontend/src/pages/user-info.vue b/packages/frontend/src/pages/admin-user.vue similarity index 70% rename from packages/frontend/src/pages/user-info.vue rename to packages/frontend/src/pages/admin-user.vue index 35cd116fad..1b79a14f55 100644 --- a/packages/frontend/src/pages/user-info.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -24,12 +24,6 @@ SPDX-License-Identifier: AGPL-3.0-only <MkInfo v-if="user.username.includes('.')">{{ i18n.ts.isSystemAccount }}</MkInfo> - <div v-if="user.url" class="_formLinksGrid"> - <FormLink :to="userPage(user)">Profile</FormLink> - <FormLink :to="user.url" :external="true">Profile (remote)</FormLink> - </div> - <FormLink v-else :to="userPage(user)">Profile</FormLink> - <FormLink v-if="user.host" :to="`/instance-info/${user.host}`">{{ i18n.ts.instanceInfo }}</FormLink> <div style="display: flex; flex-direction: column; gap: 1em;"> @@ -57,6 +51,11 @@ SPDX-License-Identifier: AGPL-3.0-only </MkKeyValue> </div> + <MkTextarea v-model="moderationNote" manualSave> + <template #label>Moderation note</template> + </MkTextarea> + + <!-- <FormSection> <template #label>ActivityPub</template> @@ -90,95 +89,85 @@ SPDX-License-Identifier: AGPL-3.0-only </MkFolder> </div> </FormSection> - </div> + --> - <div v-else-if="tab === 'moderation'" class="_gaps_m"> - <MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch> - - <div> - <MkButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton> - <MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton> - </div> - - <MkFolder> - <template #icon><i class="ti ti-license"></i></template> - <template #label>{{ i18n.ts._role.policies }}</template> + <FormSection> <div class="_gaps"> - <div v-for="policy in Object.keys(info.policies)" :key="policy"> - {{ policy }} ... {{ info.policies[policy] }} + <MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch> + + <div> + <MkButton v-if="user.host == null" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton> </div> - </div> - </MkFolder> - <MkFolder> - <template #icon><i class="ti ti-badges"></i></template> - <template #label>{{ i18n.ts.roles }}</template> - <div class="_gaps"> - <MkButton v-if="user.host == null && iAmModerator" primary rounded @click="assignRole"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton> - - <div v-for="role in info.roles" :key="role.id" :class="$style.roleItem"> - <div :class="$style.roleItemMain"> - <MkRolePreview :class="$style.role" :role="role" :forModeration="true"/> - <button class="_button" :class="$style.roleToggle" @click="toggleRoleItem(role)"><i class="ti ti-chevron-down"></i></button> - <button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="unassignRole(role, $event)"><i class="ti ti-x"></i></button> - <button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button> - </div> - <div v-if="expandedRoles.includes(role.id)" :class="$style.roleItemSub"> - <div>Assigned: <MkTime :time="info.roleAssigns.find(a => a.roleId === role.id).createdAt" mode="detail"/></div> - <div v-if="info.roleAssigns.find(a => a.roleId === role.id).expiresAt">Period: {{ new Date(info.roleAssigns.find(a => a.roleId === role.id).expiresAt).toLocaleString() }}</div> - <div v-else>Period: {{ i18n.ts.indefinitely }}</div> + <MkFolder> + <template #icon><i class="ti ti-license"></i></template> + <template #label>{{ i18n.ts._role.policies }}</template> + <div class="_gaps"> + <div v-for="policy in Object.keys(info.policies)" :key="policy"> + {{ policy }} ... {{ info.policies[policy] }} + </div> </div> - </div> - </div> - </MkFolder> + </MkFolder> - <MkFolder v-if="user.host == null && iAmModerator"> - <template #icon><i class="ti ti-speakerphone"></i></template> - <template #label>{{ i18n.ts.announcements }}</template> - <div class="_gaps"> - <MkButton primary rounded @click="createAnnouncement"><i class="ti ti-plus"></i> {{ i18n.ts.new }}</MkButton> - - <MkPagination :pagination="announcementsPagination"> - <template #default="{ items }"> - <div class="_gaps_s"> - <div v-for="announcement in items" :key="announcement.id" v-panel :class="$style.announcementItem" @click="editAnnouncement(announcement)"> - <span style="margin-right: 0.5em;"> - <i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i> - <i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i> - <i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i> - <i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i> - </span> - <span>{{ announcement.title }}</span> - <span v-if="announcement.reads > 0" style="margin-left: auto; opacity: 0.7;">{{ i18n.ts.messageRead }}</span> - </div> + <MkFolder> + <template #icon><i class="ti ti-password"></i></template> + <template #label>IP</template> + <MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo> + <MkInfo v-else>The date is the IP address was first acknowledged.</MkInfo> + <template v-if="iAmAdmin && ips"> + <div v-for="record in ips" :key="record.ip" class="_monospace" :class="$style.ip" style="margin: 1em 0;"> + <span class="date">{{ record.createdAt }}</span> + <span class="ip">{{ record.ip }}</span> </div> </template> - </MkPagination> + </MkFolder> + + <MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton> </div> - </MkFolder> - - <MkFolder> - <template #icon><i class="ti ti-password"></i></template> - <template #label>IP</template> - <MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo> - <MkInfo v-else>The date is the IP address was first acknowledged.</MkInfo> - <template v-if="iAmAdmin && ips"> - <div v-for="record in ips" :key="record.ip" class="_monospace" :class="$style.ip" style="margin: 1em 0;"> - <span class="date">{{ record.createdAt }}</span> - <span class="ip">{{ record.ip }}</span> + </FormSection> + </div> + + <div v-else-if="tab === 'roles'" class="_gaps"> + <MkButton v-if="user.host == null" primary rounded @click="assignRole"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton> + + <div v-for="role in info.roles" :key="role.id" :class="$style.roleItem"> + <div :class="$style.roleItemMain"> + <MkRolePreview :class="$style.role" :role="role" :forModeration="true"/> + <button class="_button" :class="$style.roleToggle" @click="toggleRoleItem(role)"><i class="ti ti-chevron-down"></i></button> + <button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="unassignRole(role, $event)"><i class="ti ti-x"></i></button> + <button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button> + </div> + <div v-if="expandedRoles.includes(role.id)" :class="$style.roleItemSub"> + <div>Assigned: <MkTime :time="info.roleAssigns.find(a => a.roleId === role.id).createdAt" mode="detail"/></div> + <div v-if="info.roleAssigns.find(a => a.roleId === role.id).expiresAt">Period: {{ new Date(info.roleAssigns.find(a => a.roleId === role.id).expiresAt).toLocaleString() }}</div> + <div v-else>Period: {{ i18n.ts.indefinitely }}</div> + </div> + </div> + </div> + + <div v-else-if="tab === 'announcements'" class="_gaps"> + <MkButton primary rounded @click="createAnnouncement"><i class="ti ti-plus"></i> {{ i18n.ts.new }}</MkButton> + + <MkPagination :pagination="announcementsPagination"> + <template #default="{ items }"> + <div class="_gaps_s"> + <div v-for="announcement in items" :key="announcement.id" v-panel :class="$style.announcementItem" @click="editAnnouncement(announcement)"> + <span style="margin-right: 0.5em;"> + <i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i> + <i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i> + <i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i> + <i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i> + </span> + <span>{{ announcement.title }}</span> + <span v-if="announcement.reads > 0" style="margin-left: auto; opacity: 0.7;">{{ i18n.ts.messageRead }}</span> + </div> </div> </template> - </MkFolder> - - <MkFolder> - <template #icon><i class="ti ti-cloud"></i></template> - <template #label>{{ i18n.ts.files }}</template> - <MkFileListForAdmin :pagination="filesPagination" viewMode="grid"/> - </MkFolder> + </MkPagination> + </div> - <MkTextarea v-model="moderationNote" manualSave> - <template #label>Moderation note</template> - </MkTextarea> + <div v-else-if="tab === 'drive'" class="_gaps"> + <MkFileListForAdmin :pagination="filesPagination" viewMode="grid"/> </div> <div v-else-if="tab === 'chart'" class="_gaps_m"> @@ -230,7 +219,7 @@ import { url } from '@/config'; import { userPage, acct } from '@/filters/user'; import { definePageMetadata } from '@/scripts/page-metadata'; import { i18n } from '@/i18n'; -import { iAmAdmin, iAmModerator, $i } from '@/account'; +import { iAmAdmin, $i } from '@/account'; import MkRolePreview from '@/components/MkRolePreview.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; @@ -269,34 +258,26 @@ const announcementsPagination = { let expandedRoles = $ref([]); function createFetcher() { - if (iAmModerator) { - return () => Promise.all([os.api('users/show', { - userId: props.userId, - }), os.api('admin/show-user', { - userId: props.userId, - }), iAmAdmin ? os.api('admin/get-user-ips', { - userId: props.userId, - }) : Promise.resolve(null)]).then(([_user, _info, _ips]) => { - user = _user; - info = _info; - ips = _ips; - moderator = info.isModerator; - silenced = info.isSilenced; - suspended = info.isSuspended; - moderationNote = info.moderationNote; - - watch($$(moderationNote), async () => { - await os.api('admin/update-user-note', { userId: user.id, text: moderationNote }); - await refreshUser(); - }); - }); - } else { - return () => os.api('users/show', { - userId: props.userId, - }).then((res) => { - user = res; + return () => Promise.all([os.api('users/show', { + userId: props.userId, + }), os.api('admin/show-user', { + userId: props.userId, + }), iAmAdmin ? os.api('admin/get-user-ips', { + userId: props.userId, + }) : Promise.resolve(null)]).then(([_user, _info, _ips]) => { + user = _user; + info = _info; + ips = _ips; + moderator = info.isModerator; + silenced = info.isSilenced; + suspended = info.isSuspended; + moderationNote = info.moderationNote; + + watch($$(moderationNote), async () => { + await os.api('admin/update-user-note', { userId: user.id, text: moderationNote }); + await refreshUser(); }); - } + }); } function refreshUser() { @@ -472,11 +453,19 @@ const headerTabs = $computed(() => [{ key: 'overview', title: i18n.ts.overview, icon: 'ti ti-info-circle', -}, iAmModerator ? { - key: 'moderation', - title: i18n.ts.moderation, - icon: 'ti ti-user-exclamation', -} : null, { +}, { + key: 'roles', + title: i18n.ts.roles, + icon: 'ti ti-badges', +}, { + key: 'announcements', + title: i18n.ts.announcements, + icon: 'ti ti-speakerphone', +}, { + key: 'drive', + title: i18n.ts.drive, + icon: 'ti ti-cloud', +}, { key: 'chart', title: i18n.ts.charts, icon: 'ti ti-chart-line', @@ -484,11 +473,11 @@ const headerTabs = $computed(() => [{ key: 'raw', title: 'Raw', icon: 'ti ti-code', -}].filter(x => x != null)); +}]); definePageMetadata(computed(() => ({ title: user ? acct(user) : i18n.ts.userInfo, - icon: 'ti ti-info-circle', + icon: 'ti ti-user-exclamation', }))); </script> diff --git a/packages/frontend/src/pages/admin/overview.moderators.vue b/packages/frontend/src/pages/admin/overview.moderators.vue index 6ed2e6d237..c448ec037d 100644 --- a/packages/frontend/src/pages/admin/overview.moderators.vue +++ b/packages/frontend/src/pages/admin/overview.moderators.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in"> <MkLoading v-if="fetching"/> <div v-else :class="$style.root" class="_panel"> - <MkA v-for="user in moderators" :key="user.id" class="user" :to="`/user-info/${user.id}`"> + <MkA v-for="user in moderators" :key="user.id" class="user" :to="`/admin/user/${user.id}`"> <MkAvatar :user="user" class="avatar" indicator/> </MkA> </div> diff --git a/packages/frontend/src/pages/admin/overview.users.vue b/packages/frontend/src/pages/admin/overview.users.vue index 6535fac720..a366293bf8 100644 --- a/packages/frontend/src/pages/admin/overview.users.vue +++ b/packages/frontend/src/pages/admin/overview.users.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in"> <MkLoading v-if="fetching"/> <div v-else class="users"> - <MkA v-for="(user, i) in newUsers" :key="user.id" :to="`/user-info/${user.id}`" class="user"> + <MkA v-for="(user, i) in newUsers" :key="user.id" :to="`/admin/user/${user.id}`" class="user"> <MkUserCardMini :user="user"/> </MkA> </div> diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue index 78513beee0..779fb6d51b 100644 --- a/packages/frontend/src/pages/admin/roles.role.vue +++ b/packages/frontend/src/pages/admin/roles.role.vue @@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_s"> <div v-for="item in items" :key="item.user.id" :class="[$style.userItem, { [$style.userItemOpend]: expandedItems.includes(item.id) }]"> <div :class="$style.userItemMain"> - <MkA :class="$style.userItemMainBody" :to="`/user-info/${item.user.id}`"> + <MkA :class="$style.userItemMainBody" :to="`/admin/user/${item.user.id}`"> <MkUserCardMini :user="item.user"/> </MkA> <button class="_button" :class="$style.userToggle" @click="toggleItem(item)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button> diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index f62ab47033..084d5c0ed0 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkPagination v-slot="{items}" ref="paginationComponent" :pagination="pagination"> <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="`/user-info/${user.id}`"> + <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"/> </MkA> </div> @@ -116,7 +116,7 @@ async function addUser() { } function show(user) { - os.pageWindow(`/user-info/${user.id}`); + os.pageWindow(`/admin/user/${user.id}`); } const headerActions = $computed(() => [{ diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index 24355c0556..143589bd8c 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -102,7 +102,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <div v-else-if="tab === 'users'" class="_gaps_m"> <MkPagination v-slot="{items}" :pagination="usersPagination" style="display: grid; grid-template-columns: repeat(auto-fill,minmax(270px,1fr)); grid-gap: 12px;"> - <MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" class="user" :to="`/user-info/${user.id}`"> + <MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" class="user" :to="`/admin/user/${user.id}`"> <MkUserCardMini :user="user"/> </MkA> </MkPagination> diff --git a/packages/frontend/src/pages/settings/mute-block.vue b/packages/frontend/src/pages/settings/mute-block.vue index dcfd8b1e2e..c35fc0e0e3 100644 --- a/packages/frontend/src/pages/settings/mute-block.vue +++ b/packages/frontend/src/pages/settings/mute-block.vue @@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_s"> <div v-for="item in items" :key="item.mutee.id" :class="[$style.userItem, { [$style.userItemOpend]: expandedRenoteMuteItems.includes(item.id) }]"> <div :class="$style.userItemMain"> - <MkA :class="$style.userItemMainBody" :to="`/user-info/${item.mutee.id}`"> + <MkA :class="$style.userItemMainBody" :to="userPage(item.mutee)"> <MkUserCardMini :user="item.mutee"/> </MkA> <button class="_button" :class="$style.userToggle" @click="toggleRenoteMuteItem(item)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button> @@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_s"> <div v-for="item in items" :key="item.mutee.id" :class="[$style.userItem, { [$style.userItemOpend]: expandedMuteItems.includes(item.id) }]"> <div :class="$style.userItemMain"> - <MkA :class="$style.userItemMainBody" :to="`/user-info/${item.mutee.id}`"> + <MkA :class="$style.userItemMainBody" :to="userPage(item.mutee)"> <MkUserCardMini :user="item.mutee"/> </MkA> <button class="_button" :class="$style.userToggle" @click="toggleMuteItem(item)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button> @@ -82,7 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_gaps_s"> <div v-for="item in items" :key="item.blockee.id" :class="[$style.userItem, { [$style.userItemOpend]: expandedBlockItems.includes(item.id) }]"> <div :class="$style.userItemMain"> - <MkA :class="$style.userItemMainBody" :to="`/user-info/${item.blockee.id}`"> + <MkA :class="$style.userItemMainBody" :to="userPage(item.blockee)"> <MkUserCardMini :user="item.blockee"/> </MkA> <button class="_button" :class="$style.userToggle" @click="toggleBlockItem(item)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button> diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index 0876e533d0..2e4494814a 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -42,10 +42,6 @@ export const routes = [{ }, { path: '/clips/:clipId', component: page(() => import('./pages/clip.vue')), -}, { - path: '/user-info/:userId', - component: page(() => import('./pages/user-info.vue')), - hash: 'initialTab', }, { path: '/instance-info/:host', component: page(() => import('./pages/instance-info.vue')), @@ -334,6 +330,9 @@ export const routes = [{ }, { path: '/registry', component: page(() => import('./pages/registry.vue')), +}, { + path: '/admin/user/:userId', + component: iAmModerator ? page(() => import('./pages/admin-user.vue')) : page(() => import('./pages/not-found.vue')), }, { path: '/admin/file/:fileId', component: iAmModerator ? page(() => import('./pages/admin-file.vue')) : page(() => import('./pages/not-found.vue')), diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts index 69a6f75c12..b9c726e134 100644 --- a/packages/frontend/src/scripts/get-user-menu.ts +++ b/packages/frontend/src/scripts/get-user-menu.ts @@ -133,13 +133,13 @@ export function getUserMenu(user: misskey.entities.UserDetailed, router: Router action: () => { copyToClipboard(`@${user.username}@${user.host ?? host}`); }, - }, { - icon: 'ti ti-info-circle', - text: i18n.ts.info, + }, ...(iAmModerator ? [{ + icon: 'ti ti-user-exclamation', + text: i18n.ts.moderation, action: () => { - router.push(`/user-info/${user.id}`); + router.push(`/admin/user/${user.id}`); }, - }, { + }] : []), { icon: 'ti ti-rss', text: i18n.ts.copyRSS, action: () => { diff --git a/packages/frontend/src/scripts/lookup-user.ts b/packages/frontend/src/scripts/lookup-user.ts index 83d7914fb1..75899adbaa 100644 --- a/packages/frontend/src/scripts/lookup-user.ts +++ b/packages/frontend/src/scripts/lookup-user.ts @@ -14,7 +14,7 @@ export async function lookupUser() { if (canceled) return; const show = (user) => { - os.pageWindow(`/user-info/${user.id}`); + os.pageWindow(`/admin/user/${user.id}`); }; const usernamePromise = os.api('users/show', Acct.parse(result)); -- GitLab