From c4e70efb61101ee6647bd4c4f4d7207f8400530a Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Sun, 7 Jul 2024 00:58:05 +0800 Subject: [PATCH] feat: add file filter chat files checkbox(use for remove unused chat files) --- pnpm-lock.yaml | 10 ++--- server/admin/package.json | 2 +- server/admin/src/client/fields.ts | 7 ++- server/admin/src/client/resources/file.tsx | 28 ++++++++++-- server/admin/src/server/router/api.ts | 51 +++++++++++++++++++++- server/models/file.ts | 1 + server/models/user/user.ts | 2 + 7 files changed, 89 insertions(+), 12 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6cc873ddffd..ac649e84751 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1653,8 +1653,8 @@ importers: specifier: workspace:^ version: link:../packages/sdk tushan: - specifier: ^0.3.4 - version: 0.3.4(prop-types@15.8.1)(ts-node@10.9.1) + specifier: ^0.3.9 + version: 0.3.9(prop-types@15.8.1)(ts-node@10.9.1) vite-express: specifier: 0.8.0 version: 0.8.0(patch_hash=u6touqej4dt3zxnslnszarl7vq)(express@4.18.2)(vite@4.2.0) @@ -33333,8 +33333,8 @@ packages: domino: 2.1.6 dev: false - /tushan@0.3.4(prop-types@15.8.1)(ts-node@10.9.1): - resolution: {integrity: sha512-y2z1wUaZTFO9MJj+sMJzn9xQ08VvdUwEWgVsRRiUKEaSkTOUHl2qqGDrE961X/gGnGcW/yHdzBYObwL44jUxiA==} + /tushan@0.3.9(prop-types@15.8.1)(ts-node@10.9.1): + resolution: {integrity: sha512-qKA6NdWkstPKYE0BaxLZFiPnWXCjpiO5voZxzqln2y0FRp1hG7Zb+gChBQWyrZulAmAVjBiABjOBajpuyu7bqw==} dependencies: '@arco-design/web-react': 2.51.0(@types/react@18.0.20)(react-dom@18.2.0)(react@18.2.0) '@tanstack/react-query': 4.33.0(react-dom@18.2.0)(react@18.2.0) @@ -33355,7 +33355,7 @@ packages: immer: 9.0.21 jsonexport: 3.2.0 lodash-es: 4.17.21 - postcss: 8.4.21 + postcss: 8.4.27 qs: 6.11.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) diff --git a/server/admin/package.json b/server/admin/package.json index 440c3875fd5..35829b41f71 100644 --- a/server/admin/package.json +++ b/server/admin/package.json @@ -29,7 +29,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "tailchat-server-sdk": "workspace:^", - "tushan": "^0.3.4", + "tushan": "^0.3.9", "vite-express": "0.8.0" }, "devDependencies": { diff --git a/server/admin/src/client/fields.ts b/server/admin/src/client/fields.ts index 99f8e18da10..f42a0075b77 100644 --- a/server/admin/src/client/fields.ts +++ b/server/admin/src/client/fields.ts @@ -159,6 +159,7 @@ export const fileFields = [ createFileSizeField('size', { list: { width: 120, + sort: true, }, }), createTextField('metaData.content-type'), @@ -170,7 +171,11 @@ export const fileFields = [ width: 80, }, }), - createDateTimeField('createdAt'), + createDateTimeField('createdAt', { + list: { + sort: true, + }, + }), ]; export const mailFields = [ diff --git a/server/admin/src/client/resources/file.tsx b/server/admin/src/client/resources/file.tsx index 0a2541d65b5..dc66d93052f 100644 --- a/server/admin/src/client/resources/file.tsx +++ b/server/admin/src/client/resources/file.tsx @@ -1,17 +1,26 @@ import filesize from 'filesize'; -import React from 'react'; +import React, { useState } from 'react'; import { createTextField, ListTable, useAsync, useTranslation, Typography, + styled, + Checkbox, } from 'tushan'; import { fileFields } from '../fields'; import { request } from '../request'; +const Row = styled.div` + display: flex; + gap: 20px; + justify-content: end; +`; + export const FileList: React.FC = React.memo(() => { const { t } = useTranslation(); + const [isOnlyChatFiles, setIsOnlyChatFiles] = useState(false); const { value: totalSize = 0 } = useAsync(async () => { const { data } = await request.get('/file/filesizeSum'); @@ -20,9 +29,19 @@ export const FileList: React.FC = React.memo(() => { return ( <> - - {t('custom.file.fileTotalSize')}: {filesize(totalSize)} - + + { + setIsOnlyChatFiles(!isOnlyChatFiles); + }} + > + Only show chat files + + + {t('custom.file.fileTotalSize')}: {filesize(totalSize)} + + { action={{ detail: true, delete: true }} batchAction={{ delete: true }} showSizeChanger={true} + meta={isOnlyChatFiles ? 'onlyChat' : undefined} /> ); diff --git a/server/admin/src/server/router/api.ts b/server/admin/src/server/router/api.ts index 59f9675db78..bbc2a3aea0f 100644 --- a/server/admin/src/server/router/api.ts +++ b/server/admin/src/server/router/api.ts @@ -10,10 +10,14 @@ import userModel from '../../../../models/user/user'; import messageModel from '../../../../models/chat/message'; import fileModel from '../../../../models/file'; import groupModel from '../../../../models/group/group'; -import { raExpressMongoose } from '../middleware/express-mongoose-ra-json-server'; +import { + raExpressMongoose, + virtualId, +} from '../middleware/express-mongoose-ra-json-server'; import { cacheRouter } from './cache'; import discoverModel from '../../../../plugins/com.msgbyte.discover/models/discover'; import { analyticsRouter } from './analytics'; +import _ from 'lodash'; const router = Router(); @@ -292,6 +296,51 @@ router.delete('/file/:id', auth(), async (req, res) => { router.use( '/file', auth(), + async (req, res, next) => { + const onlyChatFile = req.query.meta === 'onlyChat'; + + if (!onlyChatFile) { + return next(); + } + + // only return chatted file rather than all file + const result = await fileModel + .aggregate() + .lookup({ + from: 'users', + localField: 'url', + foreignField: 'avatar', + as: 'avatarMatchedUser', + }) + .match({ + 'avatarMatchedUser.0': { $exists: false }, + }) + .project({ + avatarMatchedUser: 0, + }) + .facet({ + metadata: [{ $count: 'total' }], + data: [ + { + $sort: { + [typeof req.query._sort === 'string' + ? req.query._sort === 'id' + ? '_id' + : req.query._sort + : '_id']: req.query._order === 'ASC' ? 1 : -1, + }, + }, + { $skip: Number(req.query._start) }, + { $limit: Number(req.query._end) - Number(req.query._start) }, + ], + }) + .exec(); + + const list = _.get(result, '0.data'); + const total = _.get(result, '0.metadata.0.total'); + + return res.set('X-Total-Count', total).json(virtualId(list)).end(); + }, raExpressMongoose(fileModel, { q: ['objectName'], allowedRegexFields: ['objectName'], diff --git a/server/models/file.ts b/server/models/file.ts index 3485ff07e40..b559625cbac 100644 --- a/server/models/file.ts +++ b/server/models/file.ts @@ -20,6 +20,7 @@ import { User } from './user/user'; }, }) @index({ bucketName: 1, objectName: 1 }) +@index({ url: 1 }) export class File extends TimeStamps implements Base { _id: Types.ObjectId; id: string; diff --git a/server/models/user/user.ts b/server/models/user/user.ts index 334e3a3f663..09e27ab5f6b 100644 --- a/server/models/user/user.ts +++ b/server/models/user/user.ts @@ -5,6 +5,7 @@ import { ReturnModelType, modelOptions, Severity, + index, } from '@typegoose/typegoose'; import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'; import type { Types } from 'mongoose'; @@ -32,6 +33,7 @@ export interface UserLoginRes extends User { allowMixed: Severity.ALLOW, }, }) +@index({ avatar: 1 }) export class User extends TimeStamps implements Base { _id: Types.ObjectId; id: string;