diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dc75e6f9..bc3e1a422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You should also include the user name that made the change. ### Improvements - Server: Add rate limit to i/notifications @tamaina -- Client: Improve files page of control panel @syuilo +- Client: Improve control panel @syuilo - Client: Show warning in control panel when there is an unresolved abuse report @syuilo - Improve player detection in URL preview @mei23 - Add Badge Image to Push Notification #8012 @tamaina diff --git a/packages/backend/src/server/api/endpoints/admin/drive/files.ts b/packages/backend/src/server/api/endpoints/admin/drive/files.ts index 119c4db19..ba32aac43 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/files.ts @@ -1,5 +1,5 @@ -import define from '../../../define.js'; import { DriveFiles } from '@/models/index.js'; +import define from '../../../define.js'; import { makePaginationQuery } from '../../../common/make-pagination-query.js'; export const meta = { @@ -25,8 +25,9 @@ export const paramDef = { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id', nullable: true }, type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) }, - origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: "local" }, + origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' }, hostname: { type: 'string', nullable: true, @@ -41,14 +42,18 @@ export const paramDef = { export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(DriveFiles.createQueryBuilder('file'), ps.sinceId, ps.untilId); - if (ps.origin === 'local') { - query.andWhere('file.userHost IS NULL'); - } else if (ps.origin === 'remote') { - query.andWhere('file.userHost IS NOT NULL'); - } + if (ps.userId) { + query.andWhere('file.userId = :userId', { userId: ps.userId }); + } else { + if (ps.origin === 'local') { + query.andWhere('file.userHost IS NULL'); + } else if (ps.origin === 'remote') { + query.andWhere('file.userHost IS NOT NULL'); + } - if (ps.hostname) { - query.andWhere('file.userHost = :hostname', { hostname: ps.hostname }); + if (ps.hostname) { + query.andWhere('file.userHost = :hostname', { hostname: ps.hostname }); + } } if (ps.type) { diff --git a/packages/client/src/components/file-list-for-admin.vue b/packages/client/src/components/file-list-for-admin.vue new file mode 100644 index 000000000..992b41a4f --- /dev/null +++ b/packages/client/src/components/file-list-for-admin.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/packages/client/src/pages/admin/files.vue b/packages/client/src/pages/admin/files.vue index 18bf4f9a8..1d037fc4e 100644 --- a/packages/client/src/pages/admin/files.vue +++ b/packages/client/src/pages/admin/files.vue @@ -16,32 +16,15 @@ -
+
+ + +
- - - +
@@ -56,9 +39,7 @@ import XHeader from './_header_.vue'; import MkButton from '@/components/ui/button.vue'; import MkInput from '@/components/form/input.vue'; import MkSelect from '@/components/form/select.vue'; -import MkPagination from '@/components/ui/pagination.vue'; -import MkContainer from '@/components/ui/container.vue'; -import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue'; +import MkFileListForAdmin from '@/components/file-list-for-admin.vue'; import bytes from '@/filters/bytes'; import * as os from '@/os'; import { i18n } from '@/i18n'; @@ -67,12 +48,14 @@ import { definePageMetadata } from '@/scripts/page-metadata'; let origin = $ref('local'); let type = $ref(null); let searchHost = $ref(''); +let userId = $ref(''); let viewMode = $ref('grid'); const pagination = { endpoint: 'admin/drive/files' as const, limit: 10, params: computed(() => ({ type: (type && type !== '') ? type : null, + userId: (userId && userId !== '') ? userId : null, origin: origin, hostname: (searchHost && searchHost !== '') ? searchHost : null, })), @@ -134,54 +117,5 @@ definePageMetadata(computed(() => ({ diff --git a/packages/client/src/pages/user-info.vue b/packages/client/src/pages/user-info.vue index cc187b9df..b4c4aedfc 100644 --- a/packages/client/src/pages/user-info.vue +++ b/packages/client/src/pages/user-info.vue @@ -76,6 +76,9 @@ +
+ +
@@ -105,6 +108,7 @@ import FormButton from '@/components/ui/button.vue'; import MkKeyValue from '@/components/key-value.vue'; import MkSelect from '@/components/form/select.vue'; import FormSuspense from '@/components/form/suspense.vue'; +import MkFileListForAdmin from '@/components/file-list-for-admin.vue'; import * as os from '@/os'; import number from '@/filters/number'; import bytes from '@/filters/bytes'; @@ -127,6 +131,13 @@ let ap = $ref(null); let moderator = $ref(false); let silenced = $ref(false); let suspended = $ref(false); +const filesPagination = { + endpoint: 'admin/drive/files' as const, + limit: 10, + params: computed(() => ({ + userId: props.userId, + })), +}; function createFetcher() { if (iAmModerator) { @@ -244,7 +255,11 @@ const headerTabs = $computed(() => [{ key: 'chart', title: i18n.ts.charts, icon: 'fas fa-chart-simple', -}, { +}, iAmModerator ? { + key: 'files', + title: i18n.ts.files, + icon: 'fas fa-cloud', +} : null, { key: 'ap', title: 'AP', icon: 'fas fa-share-alt', @@ -252,7 +267,7 @@ const headerTabs = $computed(() => [{ key: 'raw', title: 'Raw data', icon: 'fas fa-code', -}]); +}].filter(x => x != null)); definePageMetadata(computed(() => ({ title: user ? acct(user) : i18n.ts.userInfo,