feat(mentor-workspace): inline document preview matching applicant docs pattern
- Eye toggle expands the row below to embed FilePreview from @/components/shared/file-viewer (PDF iframe, image, video, Office docs) - Download button uses explicit Content-Disposition: attachment via a new `disposition` input on workspaceGetFileDownloadUrl - getPresignedUrl learns `inline: true` and optional `response-content-type` override so PDFs/images don't get force-downloaded by MinIO's default - Eye button only renders for previewable mime types Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2307,16 +2307,21 @@ export const mentorRouter = router({
|
||||
* Issue a short-lived presigned GET URL to download a workspace file.
|
||||
*/
|
||||
workspaceGetFileDownloadUrl: protectedProcedure
|
||||
.input(z.object({ mentorFileId: z.string() }))
|
||||
.input(z.object({
|
||||
mentorFileId: z.string(),
|
||||
disposition: z.enum(['inline', 'attachment']).default('attachment'),
|
||||
}))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const file = await ctx.prisma.mentorFile.findUnique({
|
||||
where: { id: input.mentorFileId },
|
||||
select: { bucket: true, objectKey: true, fileName: true, projectId: true },
|
||||
select: { bucket: true, objectKey: true, fileName: true, mimeType: true, projectId: true },
|
||||
})
|
||||
if (!file) throw new TRPCError({ code: 'NOT_FOUND', message: 'File not found' })
|
||||
await assertProjectWorkspaceAccess(ctx.prisma, ctx.user.id, file.projectId)
|
||||
const url = await getPresignedUrl(file.bucket, file.objectKey, 'GET', 900,
|
||||
{ downloadFileName: file.fileName })
|
||||
input.disposition === 'inline'
|
||||
? { inline: true, contentType: file.mimeType }
|
||||
: { downloadFileName: file.fileName })
|
||||
return { url }
|
||||
}),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user