From 24cc6a925dc15059ca28a237eb77421e44309cf8 Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 29 Jun 2023 19:53:46 -0700 Subject: [PATCH] feat: :sparkles: introduce local user select dialog Used for selecting group members and proxy account. Closes #7987, API change: users/search-by-username-and-host now takes `maxDaysSinceLastActive` parameter and doesn't have any active threshold anymore by default. --- .../users/search-by-username-and-host.ts | 17 +- .../components/MkUserSelectLocalDialog.vue | 223 ++++++++++++++++++ packages/client/src/os.ts | 19 ++ .../client/src/pages/admin/proxy-account.vue | 19 +- packages/client/src/pages/my-groups/group.vue | 4 +- 5 files changed, 273 insertions(+), 9 deletions(-) create mode 100644 packages/client/src/components/MkUserSelectLocalDialog.vue diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index eeccf69386..f34083233f 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -32,6 +32,12 @@ export const paramDef = { username: { type: "string", nullable: true }, host: { type: "string", nullable: true }, limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, + maxDaysSinceLastActive: { + type: "integer", + minimum: 1, + maximum: 1000, + default: 30, + }, detail: { type: "boolean", default: true }, }, anyOf: [{ required: ["username"] }, { required: ["host"] }], @@ -40,7 +46,9 @@ export const paramDef = { // TODO: avatar,bannerをJOINしたいけどエラーになる export default define(meta, paramDef, async (ps, me) => { - const activeThreshold = new Date(Date.now() - 1000 * 60 * 60 * 24 * 30); // 30日 + const activeThreshold = ps.maxDaysSinceLastActive + ? new Date(Date.now() - 1000 * 60 * 60 * 24 * ps.maxDaysSinceLastActive) + : null; if (ps.host) { const q = Users.createQueryBuilder("user") @@ -75,8 +83,10 @@ export default define(meta, paramDef, async (ps, me) => { .andWhere("user.isSuspended = FALSE") .andWhere("user.usernameLower LIKE :username", { username: `${sqlLikeEscape(ps.username.toLowerCase())}%`, - }) - .andWhere( + }); + + if (activeThreshold) { + query.andWhere( new Brackets((qb) => { qb.where("user.updatedAt IS NULL").orWhere( "user.updatedAt > :activeThreshold", @@ -84,6 +94,7 @@ export default define(meta, paramDef, async (ps, me) => { ); }), ); + } query.setParameters(followingQuery.getParameters()); diff --git a/packages/client/src/components/MkUserSelectLocalDialog.vue b/packages/client/src/components/MkUserSelectLocalDialog.vue new file mode 100644 index 0000000000..e74a63da27 --- /dev/null +++ b/packages/client/src/components/MkUserSelectLocalDialog.vue @@ -0,0 +1,223 @@ + + + + + diff --git a/packages/client/src/os.ts b/packages/client/src/os.ts index 32bb8f76b1..0802d8e345 100644 --- a/packages/client/src/os.ts +++ b/packages/client/src/os.ts @@ -631,6 +631,25 @@ export async function selectUser() { }); } +export async function selectLocalUser() { + return new Promise((resolve, reject) => { + popup( + defineAsyncComponent({ + loader: () => import("@/components/MkUserSelectLocalDialog.vue"), + loadingComponent: MkWaitingDialog, + delay: 1000, + }), + {}, + { + ok: (user) => { + resolve(user); + }, + }, + "closed", + ); + }); +} + export async function selectInstance(): Promise { return new Promise((resolve, reject) => { popup( diff --git a/packages/client/src/pages/admin/proxy-account.vue b/packages/client/src/pages/admin/proxy-account.vue index 87b3c684e2..7d72b0ac0f 100644 --- a/packages/client/src/pages/admin/proxy-account.vue +++ b/packages/client/src/pages/admin/proxy-account.vue @@ -20,12 +20,15 @@ }} - {{ i18n.ts.selectAccount }}{{ i18n.ts.selectAccount }} + {{ + i18n.ts.remove + }} @@ -34,7 +37,7 @@