From cd9e64c2e8e507718a7b07bec05f1bf934696dba Mon Sep 17 00:00:00 2001 From: Dotta Date: Fri, 5 Jun 2026 21:56:37 +0000 Subject: [PATCH] fix: address artifact review feedback Co-Authored-By: Paperclip --- server/src/services/company-artifacts.ts | 8 ++- server/src/services/company-search.ts | 2 +- ui/src/api/artifacts.ts | 64 ++++++------------------ ui/src/pages/IssueDetail.tsx | 2 +- 4 files changed, 20 insertions(+), 56 deletions(-) diff --git a/server/src/services/company-artifacts.ts b/server/src/services/company-artifacts.ts index e2d12592a7b..81c33deca45 100644 --- a/server/src/services/company-artifacts.ts +++ b/server/src/services/company-artifacts.ts @@ -1,5 +1,5 @@ import { buffer } from "node:stream/consumers"; -import { and, desc, eq, isNotNull, isNull, or, sql, type SQL } from "drizzle-orm"; +import { and, desc, eq, isNotNull, isNull, notInArray, or, sql, type SQL } from "drizzle-orm"; import { alias } from "drizzle-orm/pg-core"; import type { Db } from "@paperclipai/db"; import { @@ -18,8 +18,7 @@ import { attachmentArtifactWorkProductMetadataSchema, COMPANY_ARTIFACTS_MAX_LIMIT, companyArtifactsQuerySchema, - ISSUE_CONTINUATION_SUMMARY_DOCUMENT_KEY, - isSystemIssueDocumentKey, + SYSTEM_ISSUE_DOCUMENT_KEYS, type CompanyArtifact, type CompanyArtifactMediaKind, type CompanyArtifactsQuery, @@ -161,7 +160,7 @@ export function companyArtifactsService(db: Db, storage?: StorageService) { const documentConditions: SQL[] = [ eq(documents.companyId, companyId), or(isNotNull(documents.createdByAgentId), isNotNull(documents.updatedByAgentId))!, - sql`${issueDocuments.key} != ${ISSUE_CONTINUATION_SUMMARY_DOCUMENT_KEY}`, + notInArray(issueDocuments.key, SYSTEM_ISSUE_DOCUMENT_KEYS), ]; const documentCursor = cursorCondition(sql`${documents.updatedAt}`, documentArtifactId, cursor); if (documentCursor) documentConditions.push(documentCursor); @@ -202,7 +201,6 @@ export function companyArtifactsService(db: Db, storage?: StorageService) { .limit(fetchLimit); for (const row of documentRows) { - if (isSystemIssueDocumentKey(row.key)) continue; const identifier = row.issueIdentifier ?? row.issueId; artifacts.push({ id: row.artifactId, diff --git a/server/src/services/company-search.ts b/server/src/services/company-search.ts index b7c06670fe2..bfd95478620 100644 --- a/server/src/services/company-search.ts +++ b/server/src/services/company-search.ts @@ -324,7 +324,7 @@ function artifactResult(artifact: CompanyArtifact, normalizedQuery: string, toke return { id: artifact.id, type: "artifact", - score: score + 120, + score, title: artifact.title, href: artifact.href, matchedFields: ["artifact"], diff --git a/ui/src/api/artifacts.ts b/ui/src/api/artifacts.ts index bf2ba4dc1cf..78508305a9a 100644 --- a/ui/src/api/artifacts.ts +++ b/ui/src/api/artifacts.ts @@ -1,4 +1,16 @@ import { api } from "./client"; +import type { + CompanyArtifact, + CompanyArtifactMediaKind, + CompanyArtifactsResponse, +} from "@paperclipai/shared"; + +export type { + CompanyArtifact, + CompanyArtifactMediaKind as ArtifactMediaKind, + CompanyArtifactsResponse, + CompanyArtifactSource as ArtifactSource, +} from "@paperclipai/shared"; /** * Company-level Artifacts client (PAP-10359). @@ -10,57 +22,11 @@ import { api } from "./client"; * card-ready list so the UI never has to stitch issue-specific endpoints * together. * - * The `CompanyArtifact` shape below is the shared contract from the plan. The - * backend projection task (PAP-10358) is expected to expose the same fields - * (and may also publish them through `@paperclipai/shared`); keeping a local - * definition lets the frontend build and test against the contract - * independently. + * The `CompanyArtifact` shape is imported from `@paperclipai/shared` so the + * frontend and server stay synchronized as the contract evolves. */ -export type ArtifactSource = "document" | "attachment" | "work_product"; - -export type ArtifactMediaKind = "image" | "video" | "text" | "document" | "file" | "empty"; - -export interface CompanyArtifactIssue { - id: string; - identifier: string; - title: string; -} - -export interface CompanyArtifactProject { - id: string; - name: string; -} - -export interface CompanyArtifactAgent { - id: string; - name: string; -} - -export interface CompanyArtifact { - id: string; - source: ArtifactSource; - mediaKind: ArtifactMediaKind; - title: string; - previewText: string | null; - contentType: string | null; - contentPath: string | null; - openPath: string | null; - downloadPath: string | null; - issue: CompanyArtifactIssue; - project: CompanyArtifactProject | null; - createdByAgent: CompanyArtifactAgent | null; - updatedAt: string; - /** Board-relative or prefixed link to the artifact inside its issue context. */ - href: string; -} - -export interface CompanyArtifactsResponse { - artifacts: CompanyArtifact[]; - nextCursor: string | null; -} - -export type ArtifactKindFilter = ArtifactMediaKind | "all"; +export type ArtifactKindFilter = Exclude | "all"; export interface ListArtifactsParams { kind?: ArtifactKindFilter; diff --git a/ui/src/pages/IssueDetail.tsx b/ui/src/pages/IssueDetail.tsx index f21e189e477..a337a385164 100644 --- a/ui/src/pages/IssueDetail.tsx +++ b/ui/src/pages/IssueDetail.tsx @@ -2894,7 +2894,7 @@ export function IssueDetail() { } element.scrollIntoView({ behavior: "smooth", block: "center" }); element.classList.add("ring-2", "ring-primary/50", "transition-shadow"); - timer = setTimeout(() => element.classList.remove("ring-2", "ring-primary/50"), 3000); + timer = setTimeout(() => element.classList.remove("ring-2", "ring-primary/50", "transition-shadow"), 3000); }; tryScroll(); return () => {