Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions frontend/src/components/custom-tools/pdf-viewer/Highlight.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,30 @@
background-color: yellow;
opacity: 0.5;
}

.pdf-viewer-error {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
min-height: 400px;
background-color: #fafafa;
border-radius: 8px;
}

.pdf-viewer-error .ant-result {
padding: 32px 16px;
}

.pdf-viewer-error .ant-result-title {
color: #262626;
font-size: 18px;
font-weight: 500;
}

.pdf-viewer-error .ant-result-subtitle {
color: #8c8c8c;
font-size: 14px;
max-width: 400px;
margin: 0 auto;
}
88 changes: 83 additions & 5 deletions frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { FileExclamationOutlined, ReloadOutlined } from "@ant-design/icons";
import { Viewer, Worker } from "@react-pdf-viewer/core";
import { defaultLayoutPlugin } from "@react-pdf-viewer/default-layout";
import { highlightPlugin } from "@react-pdf-viewer/highlight";
import { pageNavigationPlugin } from "@react-pdf-viewer/page-navigation";
import { Button, Result } from "antd";
import PropTypes from "prop-types";
import { useEffect, useMemo, useRef } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";

import "@react-pdf-viewer/highlight/lib/styles/index.css";
import "./Highlight.css";
Expand All @@ -17,17 +19,77 @@
// Do nothing, no plugin will be loaded.
}

function PdfViewer({ fileUrl, highlightData, currentHighlightIndex }) {
function PdfLoadError({ error, onRetry, reportError }) {

Check warning on line 22 in frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'reportError' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=Zipstack_unstract&issues=AZzRwuzNgP2_TasEvwPr&open=AZzRwuzNgP2_TasEvwPr&pullRequest=1781

Check warning on line 22 in frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'onRetry' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=Zipstack_unstract&issues=AZzRwuzNgP2_TasEvwPq&open=AZzRwuzNgP2_TasEvwPq&pullRequest=1781

Check warning on line 22 in frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'error' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=Zipstack_unstract&issues=AZzRwuzNgP2_TasEvwPp&open=AZzRwuzNgP2_TasEvwPp&pullRequest=1781
useEffect(() => {
reportError(error);
}, [error, reportError]);

const errorMessage =
error?.message ||

Check warning on line 28 in frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'error.message' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=Zipstack_unstract&issues=AZzRwuzNgP2_TasEvwPs&open=AZzRwuzNgP2_TasEvwPs&pullRequest=1781
"Failed to load PDF document. The file may be corrupted or inaccessible.";

return (
<div className="pdf-viewer-error">
<Result
icon={<FileExclamationOutlined style={{ color: "#ff4d4f" }} />}
title="Failed to Load PDF"
subTitle={errorMessage}
extra={
<Button type="primary" icon={<ReloadOutlined />} onClick={onRetry}>
Retry
</Button>
}
/>
</div>
);
}

function PdfViewer({ fileUrl, highlightData, currentHighlightIndex, onError }) {
const newPlugin = defaultLayoutPlugin();
const pageNavigationPluginInstance = pageNavigationPlugin();
const { jumpToPage } = pageNavigationPluginInstance;
const parentRef = useRef(null);

// Retry key to force re-render when retrying
const [retryKey, setRetryKey] = useState(0);
const [loadError, setLoadError] = useState(null);

// Clear error state when fileUrl changes to prevent stale notifications
useEffect(() => {
setLoadError(null);
}, [fileUrl]);

const handleRetry = useCallback(() => {
setRetryKey((prev) => prev + 1);
setLoadError(null);
}, []);

// Notify parent of load errors via useEffect to avoid side effects during render
useEffect(() => {
if (loadError && onError) {
onError(loadError);
}
}, [loadError, onError]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
vishnuszipstack marked this conversation as resolved.

// Render error fallback for PDF load failures — pure render, no side effects
const renderError = useCallback(
(error) => (
<PdfLoadError
error={error}
onRetry={handleRetry}
reportError={setLoadError}
/>
),
[handleRetry],
);

function removeZerosAndDeleteIfAllZero(highlightData) {
if (Array.isArray(highlightData))
if (Array.isArray(highlightData)) {
return highlightData
?.filter((innerArray) => {
if (!Array.isArray(innerArray)) return false;
if (!Array.isArray(innerArray)) {
return false;
}
// Strip 5th element (confidence) if present, keep only first 4 elements
const coordsOnly =
innerArray.length >= 5 ? innerArray.slice(0, 4) : innerArray;
Expand All @@ -37,6 +99,7 @@
// Return only the first 4 elements (strip confidence)
return innerArray.length >= 5 ? innerArray.slice(0, 4) : innerArray;
});
}
}

const processHighlightData = highlightData
Expand Down Expand Up @@ -97,8 +160,21 @@
}
}, [highlightData, jumpToPage, currentHighlightIndex]); // Changed dependency to highlightData instead of processedHighlightData

// Show empty state when no URL is provided
if (!fileUrl) {
return (
<div ref={parentRef} className="doc-manager-body pdf-viewer-error">
<Result
icon={<FileExclamationOutlined style={{ color: "#faad14" }} />}
title="No PDF Available"
subTitle="The PDF document URL is not available. Please ensure the document has been processed correctly."
/>
</div>
);
}

return (
<div ref={parentRef} className="doc-manager-body">
<div ref={parentRef} className="doc-manager-body" key={retryKey}>
<Worker workerUrl={PDF_WORKER_URL}>
<Viewer
fileUrl={fileUrl}
Expand All @@ -107,6 +183,7 @@
pageNavigationPluginInstance,
highlightPluginInstance,
]}
renderError={renderError}
/>
</Worker>
</div>
Expand All @@ -117,6 +194,7 @@
fileUrl: PropTypes.any,
highlightData: PropTypes.array,
currentHighlightIndex: PropTypes.number,
onError: PropTypes.func,
};

export { PdfViewer };