-
Notifications
You must be signed in to change notification settings - Fork 118
H-6364: Temporal wiring + ingest UI redesign #8572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
lunelson
wants to merge
26
commits into
ln/h-6363-ingest-route
Choose a base branch
from
ln/h-6364-temporal-wiring
base: ln/h-6363-ingest-route
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 15 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
5945db4
H-6364: Add artifacts proxy rewrite for page images
lunelson 2aac90f
H-6364: Add SSE proxy API route for ingest events
lunelson 230fb07
H-6364: Align IngestRunView types with discovery contract
lunelson effc3af
H-6364: Continuous-scroll document viewer with scrollToPage
lunelson 64dbc96
H-6364: Entity cards with assertion windows in results panel
lunelson 112718f
H-6364: Two-panel inputs view with extraction mode toggle
lunelson 9c5a327
H-6364: Code review fixes across ingest module
lunelson 3172a57
H-6364: Fix temporal container healthcheck to not depend on namespace
lunelson 715dd07
H-6364: Align proxy routes with ingest-runs API rename
lunelson db963c4
H-6364: Human-readable progress labels for SSE streaming
lunelson 125e3f7
H-6364: Fix results panel β claims fallback, scroll containment, seleβ¦
lunelson 9185412
H-6364: Fix results layout β independent scroll containers
lunelson 28850fa
H-6364: Move 'New Upload' button to fixed footer below scroll panels
lunelson f8de5d4
H-6364: Add evidence panel header with document stats
lunelson bf1e9ea
H-6364: Fix ingest review issues
lunelson 8709ff3
H-6364: Tighten SSE proxy contract
lunelson e9aaaf6
feat: harden ingest recovery and claim grouping
lunelson 535ae85
feat: persist ingest run id in url
lunelson e73de5e
feat: rehydrate ingest runs from url
lunelson 84e99b1
feat: stabilize ingest progress and sidebar state
lunelson 2539f74
feat: clean up stale ingest run urls
lunelson 5b78edf
feat: stabilize ingest stream handling
lunelson 9c3bd2f
feat: narrow ingest run state variants
lunelson 899090d
feat: unify ingest page navigation policy
lunelson d8d3cbf
feat: add ingest page navigation regression tests
lunelson 188fe8d
feat: read ingest streams without event whitelists
lunelson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
apps/hash-frontend/src/pages/api/ingest/[runId]/events.api.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| /** | ||
| * SSE proxy for ingest run events. | ||
| * | ||
| * Next.js rewrites buffer responses, breaking SSE streaming. This API route | ||
| * manually proxies the EventSource connection to the Mastra API with proper | ||
| * streaming headers. | ||
| */ | ||
| import type { NextApiRequest, NextApiResponse } from "next"; | ||
|
|
||
| const MASTRA_API_ORIGIN = | ||
| process.env.MASTRA_API_ORIGIN ?? "http://localhost:4111"; | ||
|
|
||
| const getMastraApiOrigin = (): URL | null => { | ||
| try { | ||
| const url = new URL(MASTRA_API_ORIGIN); | ||
| if (url.protocol !== "http:" && url.protocol !== "https:") { | ||
| return null; | ||
| } | ||
| return url; | ||
| } catch { | ||
| return null; | ||
| } | ||
| }; | ||
|
|
||
| export default async function handler( | ||
| req: NextApiRequest, | ||
| res: NextApiResponse, | ||
| ) { | ||
| const { runId } = req.query; | ||
| const upstreamOrigin = getMastraApiOrigin(); | ||
|
|
||
| if (!upstreamOrigin) { | ||
| res.status(500).json({ error: "Invalid MASTRA_API_ORIGIN" }); | ||
| return; | ||
| } | ||
|
|
||
| if (typeof runId !== "string" || runId.trim().length === 0) { | ||
| res.status(400).json({ error: "Missing runId" }); | ||
| return; | ||
| } | ||
|
|
||
| const upstreamUrl = new URL( | ||
| `/ingest-runs/${encodeURIComponent(runId)}/events`, | ||
| upstreamOrigin, | ||
| ); | ||
|
|
||
| const headers: Record<string, string> = { | ||
| Accept: "text/event-stream", | ||
| }; | ||
|
|
||
| const lastEventId = req.headers["last-event-id"]; | ||
| if (typeof lastEventId === "string") { | ||
| headers["Last-Event-ID"] = lastEventId; | ||
| } | ||
|
|
||
| const after = req.query.after; | ||
| if (typeof after === "string") { | ||
| upstreamUrl.searchParams.set("after", after); | ||
| } | ||
|
|
||
| const abortController = new AbortController(); | ||
|
|
||
| try { | ||
| const upstream = await fetch(upstreamUrl, { | ||
| headers, | ||
| signal: abortController.signal, | ||
| }); | ||
|
|
||
| if (!upstream.ok || !upstream.body) { | ||
| res.status(upstream.status).json({ error: "Upstream error" }); | ||
| return; | ||
| } | ||
|
|
||
| res.writeHead(200, { | ||
| "Content-Type": "text/event-stream", | ||
| "Cache-Control": "no-cache, no-transform", | ||
| Connection: "keep-alive", | ||
| "X-Accel-Buffering": "no", | ||
| }); | ||
|
|
||
| const reader = upstream.body.getReader(); | ||
| const decoder = new TextDecoder(); | ||
|
|
||
| const pump = async () => { | ||
| // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- loop until stream ends | ||
| while (true) { | ||
| const { done, value } = await reader.read(); | ||
| if (done) { | ||
| break; | ||
| } | ||
| const chunk = decoder.decode(value, { stream: true }); | ||
| res.write(chunk); | ||
|
|
||
| } | ||
| res.end(); | ||
| }; | ||
|
|
||
| req.on("close", () => { | ||
|
lunelson marked this conversation as resolved.
Outdated
|
||
| abortController.abort(); | ||
| reader.cancel().catch(() => {}); | ||
| }); | ||
|
|
||
| await pump(); | ||
| } catch { | ||
| if (abortController.signal.aborted) { | ||
| if (!res.writableEnded) { | ||
| res.end(); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| if (!res.headersSent) { | ||
| res.status(502).json({ error: "Failed to connect to upstream" }); | ||
| return; | ||
| } | ||
|
|
||
| if (!res.writableEnded) { | ||
| res.end(); | ||
| } | ||
| } | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
apps/hash-frontend/src/pages/ingest.page/highlight-styles.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| /** Shared highlight color tokens for selection states across the ingest UI. */ | ||
| export const highlightColors = { | ||
| /** Border color for bbox overlays on page images. */ | ||
| bboxBorder: "rgba(59, 130, 246, 0.7)", | ||
| /** Background fill for bbox overlays on page images. */ | ||
| bboxFill: "rgba(59, 130, 246, 0.12)", | ||
| /** Background for selected list items (entity cards, assertion windows). */ | ||
| selectedBg: "rgba(59, 130, 246, 0.08)", | ||
| /** Background for hovered list items. */ | ||
| hoverBg: "rgba(59, 130, 246, 0.04)", | ||
| } as const; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.