Skip to content

Commit 3d923dc

Browse files
committed
fix(viewers): fix viewer opening files on subpaths
1 parent 016d946 commit 3d923dc

File tree

6 files changed

+76
-46
lines changed

6 files changed

+76
-46
lines changed

components/PlaintextViewer.tsx

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import fileSize from "filesize";
44

55
import { useEffect } from "react";
66

7+
import Head from "next/head";
78
import Prism from "prismjs";
89
import "prismjs/plugins/line-numbers/prism-line-numbers.js";
910
import "prismjs/plugins/line-numbers/prism-line-numbers.css";
@@ -41,37 +42,42 @@ export const PlaintextViewer = ({
4142
}, []);
4243

4344
return (
44-
<Paper sx={{ marginY: 2 }}>
45-
<Box
46-
alignItems="center"
47-
display="flex"
48-
paddingX={2}
49-
paddingY={1}
50-
sx={{
51-
bgcolor: (theme) => (theme.palette.mode === "light" ? "grey.200" : "grey.900"),
52-
boxShadow: 0,
53-
gap: 2,
54-
}}
55-
>
56-
<Box alignItems="center" display="flex" flex="1 1 auto" sx={{ gap: 1 }}>
57-
<Typography component="h1" fontFamily="monospace" sx={{ wordBreak: "break-all" }}>
58-
<b>{title}</b>
59-
</Typography>
60-
<Divider flexItem orientation="vertical" />
61-
<Typography>
62-
{numberOfLines} {linesText} of{" "}
63-
{originalContentLength ? fileSize(originalContentLength) : "unknown"}
64-
</Typography>
65-
{(compressed || truncated) && <Divider flexItem orientation="vertical" />}
66-
{compressed && <Chip label="Decompressed" size="small" variant="outlined" />}
67-
{truncated && <Chip label="Truncated" size="small" variant="outlined" />}
45+
<>
46+
<Head>
47+
<title>{title}</title>
48+
</Head>
49+
<Paper sx={{ marginY: 2 }}>
50+
<Box
51+
alignItems="center"
52+
display="flex"
53+
paddingX={2}
54+
paddingY={1}
55+
sx={{
56+
bgcolor: (theme) => (theme.palette.mode === "light" ? "grey.200" : "grey.900"),
57+
boxShadow: 0,
58+
gap: 2,
59+
}}
60+
>
61+
<Box alignItems="center" display="flex" flex="1 1 auto" sx={{ gap: 1 }}>
62+
<Typography component="h1" fontFamily="monospace" sx={{ wordBreak: "break-all" }}>
63+
<b>{title}</b>
64+
</Typography>
65+
<Divider flexItem orientation="vertical" />
66+
<Typography>
67+
{numberOfLines} {linesText} of{" "}
68+
{originalContentLength ? fileSize(originalContentLength) : "unknown"}
69+
</Typography>
70+
{(compressed || truncated) && <Divider flexItem orientation="vertical" />}
71+
{compressed && <Chip label="Decompressed" size="small" variant="outlined" />}
72+
{truncated && <Chip label="Truncated" size="small" variant="outlined" />}
73+
</Box>
6874
</Box>
69-
</Box>
70-
<Box paddingBottom={1} paddingX={1}>
71-
<Box className="line-numbers" component="pre">
72-
<code className="language-">{content}</code>
75+
<Box paddingBottom={1} paddingX={1}>
76+
<Box className="line-numbers" component="pre" sx={{ overflowX: "auto" }}>
77+
<code className="language-">{content}</code>
78+
</Box>
7379
</Box>
74-
</Box>
75-
</Paper>
80+
</Paper>
81+
</>
7682
);
7783
};

hooks/projectHooks.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ export type ProjectLocalStoragePayload = { projectId: ProjectId; version: number
1414
*/
1515
export const useCurrentProjectId = () => {
1616
const router = useRouter();
17+
const { query, pathname } = router;
1718

18-
const projectId = router.query.project as ProjectId;
19+
if (Array.isArray(query.project)) {
20+
throw new Error("Project is invalid");
21+
}
22+
const projectId = query.project;
1923

2024
const setCurrentProjectId = (newProjectId?: string, shallow?: true) => {
2125
writeToLocalStorage(PROJECT_LOCAL_STORAGE_KEY, {
@@ -28,25 +32,25 @@ export const useCurrentProjectId = () => {
2832
// A project has been selected
2933
router.push(
3034
{
31-
pathname: router.pathname,
35+
pathname,
3236
query: {
33-
...router.query,
37+
...query,
3438
project: newProjectId,
35-
path: projectId === newProjectId ? router.query.path : [],
39+
path: projectId === newProjectId ? query.path : [],
3640
},
3741
},
3842
undefined,
3943
{ shallow },
4044
);
4145
} else {
4246
// The project has been cleared
43-
const newQuery = { ...router.query };
47+
const newQuery = { ...query };
4448
delete newQuery.project;
4549
delete newQuery.path;
4650

4751
router.push(
4852
{
49-
pathname: router.pathname,
53+
pathname,
5054
query: newQuery,
5155
},
5256
undefined,

pages/project.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,30 @@ import { ProjectTable } from "../components/ProjectTable";
1616
import { ProjectFileUpload } from "../components/ProjectTable/ProjectFileUpload";
1717
import { ProjectAutocomplete } from "../components/userContext/ProjectAutocomplete";
1818
import { useCurrentProject } from "../hooks/projectHooks";
19+
import { pathFromQuery } from "../utils/paths";
1920
import { RoleRequired } from "../utils/RoleRequired";
2021
import { options } from "../utils/ssrQueryOptions";
2122

2223
export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
2324
const queryClient = new QueryClient();
2425

26+
if (
27+
query.path === undefined ||
28+
typeof query.file !== "string" ||
29+
typeof query.project !== "string"
30+
) {
31+
return { props: {} };
32+
}
33+
2534
try {
2635
const { accessToken } = await getAccessToken(req, res);
2736

2837
const projectId = query.project as string | undefined;
29-
const path = query.path as string[] | undefined;
38+
39+
const path = pathFromQuery(query.path);
3040

3141
if (projectId && accessToken) {
32-
const filesParam = { project_id: projectId, path: "/" + (path?.join("/") ?? "") };
42+
const filesParam = { project_id: projectId, path };
3343

3444
// Prefetch some data
3545
const queries = [

pages/project/file.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { withPageAuthRequired } from "@auth0/nextjs-auth0/dist/frontend";
2-
import { Container } from "@mui/material";
2+
import type { Theme } from "@mui/material";
3+
import { Container, useMediaQuery } from "@mui/material";
34
import type { GetServerSideProps } from "next";
45
import NextError from "next/error";
56
import { useRouter } from "next/router";
67

78
import { PlaintextViewer } from "../../components/PlaintextViewer";
89
import { API_ROUTES } from "../../constants/routes";
910
import { createErrorProps } from "../../utils/api/serverSidePropsError";
11+
import { pathFromQuery } from "../../utils/paths";
1012
import type { NotSuccessful, Successful } from "../../utils/plaintextViewerSSR";
1113
import { plaintextViewerSSR } from "../../utils/plaintextViewerSSR";
1214

@@ -19,13 +21,11 @@ export const getServerSideProps: GetServerSideProps<FileProps> = async ({ req, r
1921
let { path } = query;
2022
const { file, project } = query;
2123

22-
if (typeof path !== "string" || typeof file !== "string" || typeof project !== "string") {
23-
return createErrorProps(res, 500, "File or path are not valid");
24+
if (path === undefined || typeof file !== "string" || typeof project !== "string") {
25+
return createErrorProps(res, 500, "File, path or project are not valid");
2426
}
2527

26-
if (path === "") {
27-
path = "/";
28-
}
28+
path = pathFromQuery(path);
2929

3030
let compressed = false;
3131
if (file.endsWith(".gz") || file.endsWith(".gzip")) {
@@ -38,6 +38,8 @@ export const getServerSideProps: GetServerSideProps<FileProps> = async ({ req, r
3838
};
3939

4040
export const File = (props: FileProps) => {
41+
const biggerThanSm = useMediaQuery<Theme>((theme) => theme.breakpoints.up("sm"));
42+
4143
const { query } = useRouter();
4244

4345
const { file, project, path } = query;
@@ -51,7 +53,7 @@ export const File = (props: FileProps) => {
5153

5254
if (isSuccessful(props)) {
5355
return (
54-
<Container maxWidth="xl">
56+
<Container disableGutters={!biggerThanSm} maxWidth="xl">
5557
<PlaintextViewer {...props} compressed={compressed} title={title} />
5658
</Container>
5759
);

utils/paths.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const pathFromQuery = (query: string | string[]) => {
2+
if (query.length === 0) {
3+
return "/";
4+
} else if (typeof query === "string") {
5+
return "/" + query;
6+
}
7+
return "/" + query.join("/");
8+
};

utils/plaintextViewerSSR.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export const plaintextViewerSSR = async (
7878
const data = isJson ? await response.json() : null;
7979
const error = (data && (data as any).message) || response.status;
8080
captureException(error);
81-
return createErrorProps(res, response.status, response.statusText);
81+
return createErrorProps(res, error, response.statusText);
8282
}
8383

8484
// We use `node-fetch` which supports streaming unlike NextJS's fetch as of v12.2

0 commit comments

Comments
 (0)