| … | … | @@ -0,0 +1,117 @@ | |
| 53 | + | engine.addEventListener("error", () => | |
| 54 | + | setError("Could not load the text viewer. Close the file and try again."), | |
| 55 | + | ); | |
| 56 | + | engine.postMessage( | |
🟠 High files/LargeTextViewer.tsx:56
An empty text attachment is shown as a load error instead of the intended empty-file state: the worker fetches it with Range: bytes=0-..., which the server rejects with 416, and open treats that response as a failure. Have the worker fetch without a range for zero-length files or treat this response as empty.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/web/src/components/files/LargeTextViewer.tsx around line 56: |
| 2 | |
| 3 | An empty text attachment is shown as a load error instead of the intended empty-file state: the worker fetches it with `Range: bytes=0-...`, which the server rejects with `416`, and `open` treats that response as a failure. Have the worker fetch without a range for zero-length files or treat this response as empty. |
Note
Written by gpt-6.1-sol on behalf of Maria
Fixed in d9ce5f98aa. The worker treats only a 416 response with Content-Range: bytes */0 as an empty file; other range failures still report errors.
| … | … | @@ -1520,3 +1537,32 @@ export default function FilePreviewPanel({ | |
| 1547 | + | delimiter: "," | "\t" | null; | |
| 1548 | + | workspaceMutationId: string | null; | |
| 1549 | + | }) { | |
| 1550 | + | const assetUrl = useAssetUrlState(props.environmentId, { | |
🟠 High files/FilePreviewPanel.tsx:1550
After an editor or agent atomically replaces a truncated file, WorkspaceLargeTextPreview keeps using the old signed asset grant, so the preview fails to load until it is reopened or the URL cache refreshes. Changing the revision query parameter does not refresh the grant returned by useAssetUrlState; refresh the asset URL when workspaceMutationId changes, as the other workspace media previews do.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/web/src/components/files/FilePreviewPanel.tsx around line 1550: |
| 2 | |
| 3 | After an editor or agent atomically replaces a truncated file, `WorkspaceLargeTextPreview` keeps using the old signed asset grant, so the preview fails to load until it is reopened or the URL cache refreshes. Changing the `revision` query parameter does not refresh the grant returned by `useAssetUrlState`; refresh the asset URL when `workspaceMutationId` changes, as the other workspace media previews do. |
Note
Written by gpt-6.1-sol on behalf of Maria
Fixed in d9ce5f98aa. WorkspaceLargeTextPreview now refreshes its signed asset grant on workspace mutations using the same useWorkspaceMutationRefresh path as workspace media.
| … | … | @@ -331,10 +346,25 @@ export function AttachmentFilePreview(props: { | |
| 354 | + | void copyToClipboard(content.text, undefined); | |
| 355 | + | return; | |
| 356 | + | } | |
| 357 | + | void copyContents | |
🟡 Medium files/AttachmentFilePreview.tsx:357
Clicking Copy while LargeTextViewer is still loading silently does nothing because copyContents.current is unset and the optional call short-circuits. Check for the callback before invoking it and report that the viewer is still loading when it is unavailable.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/web/src/components/files/AttachmentFilePreview.tsx around line 357: |
| 2 | |
| 3 | Clicking Copy while `LargeTextViewer` is still loading silently does nothing because `copyContents.current` is unset and the optional call short-circuits. Check for the callback before invoking it and report that the viewer is still loading when it is unavailable. |
Note
Written by gpt-6.1-sol on behalf of Maria
Fixed in d9ce5f98aa. Copy now reports that the viewer is loading when its callback is unavailable, and still reports worker copy failures.
| … | … | @@ -312,38 +325,21 @@ export default function OfficeViewer(props: { | |
| 344 | - | <p className="p-6 text-center text-xs text-muted-foreground">This sheet is empty.</p> | |
| 345 | - | ) : null} | |
| 346 | - | </div> | |
| 330 | + | <VirtualTablePreview | |
🟡 Medium files/OfficeViewer.tsx:330
Sheets with rowCount === 0 no longer display “This sheet is empty,” leaving an empty preview that is indistinguishable from a blank or unloaded sheet. The previous empty-state fallback was removed, and VirtualTablePreview is now rendered unconditionally; restore the message for zero-row sheets.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/web/src/components/files/OfficeViewer.tsx around line 330: |
| 2 | |
| 3 | Sheets with `rowCount === 0` no longer display “This sheet is empty,” leaving an empty preview that is indistinguishable from a blank or unloaded sheet. The previous empty-state fallback was removed, and `VirtualTablePreview` is now rendered unconditionally; restore the message for zero-row sheets. |
Note
Written by gpt-6.1-sol on behalf of Maria
Fixed in d9ce5f98aa. Zero-row sheets show "This sheet is empty." again; verified with an empty XLSX in the app.
| … | … | @@ -0,0 +1,349 @@ | |
| 251 | + | // multi-million-line logs while retaining real row heights in the viewport. | |
| 252 | + | const maxFirst = Math.max(0, props.count - Math.floor(position.height / 29)); | |
| 253 | + | const scale = Math.max(1, scrollHeight - position.height) / Math.max(1, maxFirst * 29); | |
| 254 | + | const first = Math.min(maxFirst, Math.floor(position.top / scale / 29)); | |
🟠 High files/VirtualTablePreview.tsx:254
With more than 500,000 rows and wrap enabled, scrolling skips the remainder of wrapped lines, making that content unreadable. first maps scroll position using a fixed 29px per row, so each row transition moves the next row to the viewport top regardless of the actual wrapped row height; account for measured row heights or preserve the intra-row scroll offset.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/web/src/components/files/VirtualTablePreview.tsx around line 254: |
| 2 | |
| 3 | With more than 500,000 rows and `wrap` enabled, scrolling skips the remainder of wrapped lines, making that content unreadable. `first` maps scroll position using a fixed 29px per row, so each row transition moves the next row to the viewport top regardless of the actual wrapped row height; account for measured row heights or preserve the intra-row scroll offset. |
Note
Written by gpt-6.1-sol on behalf of Maria
Already addressed by 907526b33d. ScaledRows preserves the fractional intra-row offset using the measured row height, and wheel/key scrolling scales by that height rather than skipping wrapped content.
| … | … | @@ -0,0 +1,349 @@ | |
| 182 | + | const { loadPage, page } = props; | |
| 183 | + | useEffect(() => { | |
| 184 | + | if (!rows) loadPage?.(page); | |
| 185 | + | }, [rows, page, loadPage]); | |
🟠 High files/VirtualTablePreview.tsx:183
A partially returned page is treated as complete, so when the worker later adds rows, this page is never requested again and its missing tail stays blank. The effect only reloads when rows is undefined; also reload when rows.length is less than the page's expected row count based on props.count.
| 1 | useEffect(() => { |
| 2 | const expected = Math.min(PREVIEW_PAGE_ROWS, props.count - page * PREVIEW_PAGE_ROWS); |
| 3 | if (!rows || rows.length < expected) loadPage?.(page); |
| 4 | }, [rows, page, loadPage, props.count]); |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/web/src/components/files/VirtualTablePreview.tsx around lines 183-185: |
| 2 | |
| 3 | A partially returned page is treated as complete, so when the worker later adds rows, this page is never requested again and its missing tail stays blank. The effect only reloads when `rows` is undefined; also reload when `rows.length` is less than the page's expected row count based on `props.count`. |
Note
Written by gpt-6.1-sol on behalf of Maria
Fixed in d9ce5f98aa. RowPage reloads when the cached page has fewer rows than the indexed count requires; the existing browser test now covers a growing partial page.