From 676d8707fedc8a7036d4a078eecd2962bf0e3db4 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Thu, 26 Feb 2026 23:13:01 -0600 Subject: [PATCH] fix(api): add sortBy, sortOrder, search, visibility to knowledge entry query DTO The File Manager frontend sends sortBy, sortOrder, search, and visibility query parameters but the API DTO rejected them with validation errors. Adds the missing fields to EntryQueryDto and wires them into the service's findAll method with proper Prisma query building. Co-Authored-By: Claude Opus 4.6 --- apps/api/src/knowledge/dto/entry-query.dto.ts | 22 +++++++++++++++++-- apps/api/src/knowledge/knowledge.service.ts | 22 ++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/apps/api/src/knowledge/dto/entry-query.dto.ts b/apps/api/src/knowledge/dto/entry-query.dto.ts index 5a5f97b..c455838 100644 --- a/apps/api/src/knowledge/dto/entry-query.dto.ts +++ b/apps/api/src/knowledge/dto/entry-query.dto.ts @@ -1,6 +1,6 @@ -import { IsOptional, IsEnum, IsString, IsInt, Min, Max } from "class-validator"; +import { IsOptional, IsEnum, IsString, IsInt, IsIn, Min, Max } from "class-validator"; import { Type } from "class-transformer"; -import { EntryStatus } from "@prisma/client"; +import { EntryStatus, Visibility } from "@prisma/client"; /** * DTO for querying knowledge entries (list endpoint) @@ -10,10 +10,28 @@ export class EntryQueryDto { @IsEnum(EntryStatus, { message: "status must be a valid EntryStatus" }) status?: EntryStatus; + @IsOptional() + @IsEnum(Visibility, { message: "visibility must be a valid Visibility" }) + visibility?: Visibility; + @IsOptional() @IsString({ message: "tag must be a string" }) tag?: string; + @IsOptional() + @IsString({ message: "search must be a string" }) + search?: string; + + @IsOptional() + @IsIn(["updatedAt", "createdAt", "title"], { + message: "sortBy must be updatedAt, createdAt, or title", + }) + sortBy?: "updatedAt" | "createdAt" | "title"; + + @IsOptional() + @IsIn(["asc", "desc"], { message: "sortOrder must be asc or desc" }) + sortOrder?: "asc" | "desc"; + @IsOptional() @Type(() => Number) @IsInt({ message: "page must be an integer" }) diff --git a/apps/api/src/knowledge/knowledge.service.ts b/apps/api/src/knowledge/knowledge.service.ts index f004d91..e1ef04c 100644 --- a/apps/api/src/knowledge/knowledge.service.ts +++ b/apps/api/src/knowledge/knowledge.service.ts @@ -48,6 +48,10 @@ export class KnowledgeService { where.status = query.status; } + if (query.visibility) { + where.visibility = query.visibility; + } + if (query.tag) { where.tags = { some: { @@ -58,6 +62,20 @@ export class KnowledgeService { }; } + if (query.search) { + where.OR = [ + { title: { contains: query.search, mode: "insensitive" } }, + { content: { contains: query.search, mode: "insensitive" } }, + ]; + } + + // Build orderBy + const sortField = query.sortBy ?? "updatedAt"; + const sortDirection = query.sortOrder ?? "desc"; + const orderBy: Prisma.KnowledgeEntryOrderByWithRelationInput = { + [sortField]: sortDirection, + }; + // Get total count const total = await this.prisma.knowledgeEntry.count({ where }); @@ -71,9 +89,7 @@ export class KnowledgeService { }, }, }, - orderBy: { - updatedAt: "desc", - }, + orderBy, skip, take: limit, });