feat(frontend): update View PDF links to open in-browser viewer (sub-phase 2.5)
ResponsePanel and ChunkList View PDF links now open /pdf-viewer page instead of raw PDF download. Update ChunkList test mock from getChunkPdfUrl to getPdfViewerUrl. Add DOMMatrix polyfill to test setup for react-pdf/jsdom compatibility. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
67e411cdca
commit
a3028df4e1
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Trash2 } from 'lucide-react'
|
import { Trash2 } from 'lucide-react'
|
||||||
import type { ChunkInfo } from '../types'
|
import type { ChunkInfo } from '../types'
|
||||||
import { getChunkPdfUrl } from '../lib/api'
|
import { getPdfViewerUrl } from '../lib/api'
|
||||||
|
|
||||||
interface ChunkListProps {
|
interface ChunkListProps {
|
||||||
chunks: ChunkInfo[]
|
chunks: ChunkInfo[]
|
||||||
|
|
@ -67,7 +67,7 @@ export const ChunkList: React.FC<ChunkListProps> = ({
|
||||||
</div>
|
</div>
|
||||||
{chunk.chunk_file_path && (
|
{chunk.chunk_file_path && (
|
||||||
<a
|
<a
|
||||||
href={getChunkPdfUrl(chunk.chunk_file_path)}
|
href={getPdfViewerUrl(chunk.chunk_file_path, chunk.page_number ?? undefined)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="inline-flex items-center mt-1 text-xs text-blue-600 hover:text-blue-800 hover:underline"
|
className="inline-flex items-center mt-1 text-xs text-blue-600 hover:text-blue-800 hover:underline"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React, { useState } from 'react'
|
||||||
import { MessageSquare, AlertCircle, Copy, ChevronDown, ChevronRight } from 'lucide-react'
|
import { MessageSquare, AlertCircle, Copy, ChevronDown, ChevronRight } from 'lucide-react'
|
||||||
import ReactMarkdown from 'react-markdown'
|
import ReactMarkdown from 'react-markdown'
|
||||||
import type { SourceMetadata } from '../types'
|
import type { SourceMetadata } from '../types'
|
||||||
import { getChunkPdfUrl } from '../lib/api'
|
import { getPdfViewerUrl } from '../lib/api'
|
||||||
|
|
||||||
interface ResponsePanelProps {
|
interface ResponsePanelProps {
|
||||||
answer: string | null
|
answer: string | null
|
||||||
|
|
@ -148,7 +148,7 @@ export const ResponsePanel: React.FC<ResponsePanelProps> = ({
|
||||||
<div className="text-xs text-gray-400">Chunk {source.chunk_index}</div>
|
<div className="text-xs text-gray-400">Chunk {source.chunk_index}</div>
|
||||||
{source.chunk_file_path && (
|
{source.chunk_file_path && (
|
||||||
<a
|
<a
|
||||||
href={getChunkPdfUrl(source.chunk_file_path)}
|
href={getPdfViewerUrl(source.chunk_file_path, source.page_number ?? undefined, source.filename)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-xs text-blue-600 hover:text-blue-800 hover:underline"
|
className="text-xs text-blue-600 hover:text-blue-800 hover:underline"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ import { ChunkList } from '../../components/ChunkList'
|
||||||
import type { ChunkInfo } from '../../types'
|
import type { ChunkInfo } from '../../types'
|
||||||
|
|
||||||
vi.mock('../../lib/api', () => ({
|
vi.mock('../../lib/api', () => ({
|
||||||
getChunkPdfUrl: (path: string) => `http://localhost:8000/api/v1/chunks/${path}/pdf`,
|
getPdfViewerUrl: (filePath: string, page?: number) => {
|
||||||
|
const base = `/pdf-viewer?url=http://localhost:8000/api/v1/chunks/${filePath}/pdf`
|
||||||
|
return page !== undefined ? `${base}&page=${page}` : base
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const mockChunks: ChunkInfo[] = [
|
const mockChunks: ChunkInfo[] = [
|
||||||
|
|
@ -62,7 +65,7 @@ describe('ChunkList', () => {
|
||||||
|
|
||||||
const links = screen.getAllByTestId('view-chunk-pdf-link')
|
const links = screen.getAllByTestId('view-chunk-pdf-link')
|
||||||
expect(links).toHaveLength(2)
|
expect(links).toHaveLength(2)
|
||||||
expect(links[0]).toHaveAttribute('href', 'http://localhost:8000/api/v1/chunks/test_page_1.pdf/pdf')
|
expect(links[0]).toHaveAttribute('href', expect.stringContaining('/pdf-viewer?url='))
|
||||||
expect(links[0]).toHaveAttribute('target', '_blank')
|
expect(links[0]).toHaveAttribute('target', '_blank')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,21 @@ global.ResizeObserver = class ResizeObserver {
|
||||||
}
|
}
|
||||||
|
|
||||||
global.DOMRect = class DOMRect {
|
global.DOMRect = class DOMRect {
|
||||||
x = 0; y = 0; width = 0; height = 0; top = 0; right = 0; bottom = 0; left = 0
|
x: number; y: number; width: number; height: number; top: number; right: number; bottom: number; left: number
|
||||||
|
constructor(x = 0, y = 0, width = 0, height = 0) {
|
||||||
|
this.x = x; this.y = y; this.width = width; this.height = height
|
||||||
|
this.top = y; this.right = x + width; this.bottom = y + height; this.left = x
|
||||||
|
}
|
||||||
static fromRect() { return new DOMRect() }
|
static fromRect() { return new DOMRect() }
|
||||||
|
toJSON() { return { x: this.x, y: this.y, width: this.width, height: this.height, top: this.top, right: this.right, bottom: this.bottom, left: this.left } }
|
||||||
|
}
|
||||||
|
|
||||||
|
global.DOMMatrix = class DOMMatrix {
|
||||||
|
a = 1; b = 0; c = 0; d = 1; e = 0; f = 0
|
||||||
|
is2D = true
|
||||||
|
isIdentity = true
|
||||||
|
static fromMatrix() { return new DOMMatrix() }
|
||||||
|
multiply() { return new DOMMatrix() }
|
||||||
|
translate() { return new DOMMatrix() }
|
||||||
|
scale() { return new DOMMatrix() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue