Skip to content
Draft
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
165 changes: 161 additions & 4 deletions frontend/src/js/components/PageViewerOrFallback.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,183 @@
import { FC, useEffect, useState } from "react";
import React, { FC, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import authFetch from "../util/auth/authFetch";
import { useParams } from "react-router-dom";
import _ from "lodash";
import Viewer from "./viewer/Viewer";
import { PageViewer } from "./PageViewer/PageViewer";
import React from "react";
import { TextPreview } from "./viewer/TextPreview";
import { Preview } from "./viewer/Preview";
import { TablePreview } from "./viewer/TablePreview";
import PreviewSwitcher from "./viewer/PreviewSwitcher";
import DownloadButton from "./viewer/DownloadButton";
import { GiantState } from "../types/redux/GiantState";
import { Resource } from "../types/Resource";
import { setResourceView } from "../actions/urlParams/setViews";
import { getComments } from "../actions/resources/getComments";
import { setSelection } from "../actions/resources/setSelection";

const COMBINED_VIEW = "combined";

function isCombinedOrUnset(view: string | undefined): boolean {
return !view || view === COMBINED_VIEW;
}

function renderNoPreview() {
return (
<div className="viewer__no-text-preview">
<p>
Cannot display this document. It could still be processing or it could
be too large.
</p>
<DownloadButton />
</div>
);
}

const PageViewerContent: FC<{
uri: string;
totalPages: number;
view: string | undefined;
}> = ({ uri, totalPages, view }) => {
const dispatch = useDispatch();
const resource = useSelector<GiantState, Resource | null>(
(state) => state.resource,
);
const auth = useSelector((state: GiantState) => state.auth);
const preferences = useSelector((state: GiantState) => state.app.preferences);

if (isCombinedOrUnset(view)) {
return <PageViewer uri={uri} totalPages={totalPages} />;
}

if (!resource) {
return null;
}

if (view === "table") {
return <TablePreview text={resource.text.contents} />;
} else if (view === "preview") {
return <Preview resource={resource} />;
} else if (
view!.startsWith("ocr") ||
view!.startsWith("transcript") ||
view!.startsWith("vttTranscript")
) {
const highlightableText = _.get(resource, view!);
if (!highlightableText) {
return renderNoPreview();
}
return (
<TextPreview
uri={resource.uri}
currentUser={auth.token!.user}
text={highlightableText.contents}
searchHighlights={highlightableText.highlights}
view={view!}
comments={resource.comments}
selection={resource.selection}
preferences={preferences}
getComments={(u: string) => dispatch(getComments(u))}
setSelection={(s?: Selection) => dispatch(setSelection(s))}
/>
);
} else if (view === "text") {
if (!resource.text) {
return renderNoPreview();
}
return (
<TextPreview
uri={resource.uri}
currentUser={auth.token!.user}
text={resource.text.contents}
searchHighlights={resource.text.highlights}
view="text"
comments={resource.comments}
selection={resource.selection}
preferences={preferences}
getComments={(u: string) => dispatch(getComments(u))}
setSelection={(s?: Selection) => dispatch(setSelection(s))}
/>
);
}

return renderNoPreview();
};

export const PageViewerOrFallback: FC<{}> = () => {
const { uri } = useParams<{ uri: string }>();

const [totalPages, setTotalPages] = useState<number | null>(null);
const view = useSelector<GiantState, string | undefined>(
(state) => state.urlParams.view,
);
const resource = useSelector<GiantState, Resource | null>(
(state) => state.resource,
);
const dispatch = useDispatch();

useEffect(() => {
authFetch(`/api/pages2/${uri}/pageCount`)
.then((res) => res.json())
.then((obj) => setTotalPages(obj.pageCount));
}, [uri]);

// Default to "combined" when we have pages and no view is set.
useEffect(() => {
if (totalPages && totalPages > 0 && !view) {
dispatch(setResourceView(COMBINED_VIEW));
}
}, [totalPages, view, dispatch]);

if (totalPages === null) {
return null;
} else if (totalPages === 0) {
return <Viewer match={{ params: { uri } }} />;
} else {
return <PageViewer uri={uri} totalPages={totalPages} />;
const showTextContent = !isCombinedOrUnset(view);
return (
<div
style={{
display: "flex",
flexDirection: "column",
flexGrow: 1,
height: "calc(100vh - 50px)",
overflow: "hidden",
backgroundColor: "rgb(63, 63, 63)",
}}
>
<div
style={{
flexGrow: 1,
overflow: "auto",
display: "flex",
minHeight: 0,
}}
>
{showTextContent ? (
<div className="document" style={{ flexGrow: 1 }}>
<PageViewerContent
uri={uri}
totalPages={totalPages}
view={view}
/>
</div>
) : (
<PageViewerContent uri={uri} totalPages={totalPages} view={view} />
)}
</div>
{resource && (
<div className="document__status" style={{ flexShrink: 0 }}>
<span />
<span>
<PreviewSwitcher
view={view}
resource={resource}
totalPages={totalPages}
/>
</span>
</div>
)}
</div>
);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ export function buildSegments(resource: BasicResource): PathSegment[] {
}

function shrinkDisplay(display: string): string {
if (display.length > 15) {
return display.substring(0, 15) + "...";
if (display.length > 26) {
return display.substring(0, 26) + "...";
}

return display;
Expand Down
19 changes: 1 addition & 18 deletions frontend/src/js/components/viewer/DocumentMetadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,7 @@ export class DocumentMetadata extends React.Component {
};

renderTextViewLink() {
if (!window.location.href.includes("viewer/")) {
return null;
}

const url = new URL(window.location);
url.href = url.href.replace("viewer", "viewer-old");
url.searchParams.set("view", "text");

return (
<a
className="btn"
target="_blank"
rel="noopener noreferrer"
href={url.toString()}
>
View as text
</a>
);
return null;
}

render() {
Expand Down
29 changes: 28 additions & 1 deletion frontend/src/js/components/viewer/PreviewSwitcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,21 @@ import { bindActionCreators } from "redux";

import { setResourceView } from "../../actions/urlParams/setViews";

export function previewLabelForMimeTypes(mimeTypes) {
if (mimeTypes.some((m) => m.startsWith("video/"))) {
return "Video";
}
if (mimeTypes.some((m) => m.startsWith("audio/"))) {
return "Audio";
}
return "Preview";
}

class PreviewSwitcher extends React.Component {
static propTypes = {
resource: resourcePropType,
view: PropTypes.string,
totalPages: PropTypes.number,
setResourceView: PropTypes.func.isRequired,
};

Expand All @@ -23,6 +34,10 @@ class PreviewSwitcher extends React.Component {
return false;
}

if (this.props.view === "combined" && this.props.totalPages > 0) {
return true;
}

if (
this.props.view === "table" &&
(!resource.parents ||
Expand Down Expand Up @@ -59,6 +74,10 @@ class PreviewSwitcher extends React.Component {
return previewStatus !== "disabled";
}

previewLabel() {
return previewLabelForMimeTypes(this.props.resource?.mimeTypes ?? []);
}

componentDidUpdateOrMount() {
if (
this.props.resource &&
Expand Down Expand Up @@ -136,6 +155,14 @@ class PreviewSwitcher extends React.Component {
shortcut={keyboardShortcuts.showPreview}
func={this.showPreview}
/>
{this.props.totalPages > 0 && (
<PreviewLink
current={current}
text="Combined"
to="combined"
navigate={this.props.setResourceView}
/>
)}
{this.props.resource.text && !this.props.resource.transcript ? (
<PreviewLink
current={current}
Expand All @@ -161,7 +188,7 @@ class PreviewSwitcher extends React.Component {
{this.canPreview(this.props.resource.previewStatus) ? (
<PreviewLink
current={current}
text="Preview"
text={this.previewLabel()}
to="preview"
navigate={this.props.setResourceView}
/>
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/js/components/viewer/PreviewSwitcher.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { previewLabelForMimeTypes } from "./PreviewSwitcher";

describe("previewLabelForMimeTypes", () => {
test("returns 'Video' for video mime types", () => {
expect(previewLabelForMimeTypes(["video/mp4"])).toBe("Video");
expect(previewLabelForMimeTypes(["video/webm"])).toBe("Video");
expect(previewLabelForMimeTypes(["application/pdf", "video/mp4"])).toBe(
"Video",
);
});

test("returns 'Audio' for audio mime types", () => {
expect(previewLabelForMimeTypes(["audio/mpeg"])).toBe("Audio");
expect(previewLabelForMimeTypes(["audio/wav"])).toBe("Audio");
expect(previewLabelForMimeTypes(["application/pdf", "audio/ogg"])).toBe(
"Audio",
);
});

test("returns 'Preview' for non-media mime types", () => {
expect(previewLabelForMimeTypes(["application/pdf"])).toBe("Preview");
expect(previewLabelForMimeTypes(["image/png"])).toBe("Preview");
expect(previewLabelForMimeTypes([])).toBe("Preview");
});

test("prefers 'Video' over 'Audio' when both are present", () => {
expect(previewLabelForMimeTypes(["audio/mpeg", "video/mp4"])).toBe("Video");
});
});
4 changes: 0 additions & 4 deletions frontend/src/js/util/buildLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,5 @@ export default function buildLink(to, urlParams, overrides) {
params.details = urlParams.details;
}

if (!params.view && urlParams.view) {
params.view = urlParams.view;
}

return params ? `${encodedUri}?${objectToParamString(params)}` : encodedUri;
}
4 changes: 3 additions & 1 deletion frontend/src/stylesheets/components/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ $btnBoxShadowHeight: 2px;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: calc($baseSpacing / 2);

// Title with a button to the right
&--title {
Expand All @@ -94,7 +96,7 @@ $btnBoxShadowHeight: 2px;
}

& .btn:not(:last-child) {
margin-right: $baseSpacing;
margin-right: calc($baseSpacing / 2);
}

&--left {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

&__resource {
padding-right: 3px;
white-space: nowrap;

&:before {
white-space: normal;
Expand Down
Loading