Fix 404s in timeline and legacy-mode interlinks (#1305)
Summary: All links in SourceCred must use the `Link` component, providing either an external URL `href={…}` or an internal route `to={…}`. Any uses of a raw `<a>` element for internal routes will incur 404s when the application is hosted on a non-root path, as is currently the case on the production website. The change to `FileUploader` is not strictly necessary, as the link has no styled text and uses a `data:` URL, but there’s no reason not to. Fixes #1304. Test Plan: Build the static site: ``` scripts/build_static_site.sh --target cred --project sourcecred/example-github ``` Then run `python3 -m http.server` from the repository root directory—not the `cred/` subdirectory—and navigate to the timeline cred view: <http://localhost:8000/cred/timeline/sourcecred/example-github/> Observe that the “(legacy)” link now has the correct styling and correctly navigates to the legacy mode page when clicked: prior to this change, it would navigate to a URL without the proper `/cred/` path prefix, yielding a 404. On the legacy page, verify that the “timeline mode” link has the same properties. Then, visit <http://localhost:8000/cred/test/FileUploader/> and verify that the inspection test still passes. Added a regression test to catch further such errors. Note that reverting the code changes in this commit causes the test to fail, and that running it with `--verbose` prints the problematic files. wchargin-branch: fix-bad-routing-404s
This commit is contained in:
parent
0eeda22e0c
commit
acdcbc29ed
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
#
|
||||||
|
# Components must use the `Link` component from `webutil/Link.js` rather
|
||||||
|
# than raw `<a>` elements. The `Link` component properly handles
|
||||||
|
# client-side routing, as well as providing consistent styles.
|
||||||
|
#
|
||||||
|
# See <https://github.com/sourcecred/sourcecred/pull/1305> for an
|
||||||
|
# example of how to fix this error.
|
||||||
|
|
||||||
|
export GIT_CONFIG_NOSYSTEM=1
|
||||||
|
export GIT_ATTR_NOSYSTEM=1
|
||||||
|
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
test_description='check that bare <a> elements are never directly used'
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. ./sharness.sh
|
||||||
|
|
||||||
|
# shellcheck disable=SC1004
|
||||||
|
test_expect_success "application components must use <Link> instead of <a>" '
|
||||||
|
test_must_fail git grep -nF "</a>" \
|
||||||
|
":/src/*.js" \
|
||||||
|
":(exclude,top)*/__snapshots__/*" \
|
||||||
|
":(exclude,top)*/snapshots/*" \
|
||||||
|
":(exclude,top)src/webutil/Link.js" \
|
||||||
|
;
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
||||||
|
|
||||||
|
# vim: ft=sh
|
|
@ -10,6 +10,7 @@ import {
|
||||||
type TimelineCredParameters,
|
type TimelineCredParameters,
|
||||||
} from "../analysis/timeline/timelineCred";
|
} from "../analysis/timeline/timelineCred";
|
||||||
import {TimelineCredView} from "./TimelineCredView";
|
import {TimelineCredView} from "./TimelineCredView";
|
||||||
|
import Link from "../webutil/Link";
|
||||||
import {WeightConfig} from "./weights/WeightConfig";
|
import {WeightConfig} from "./weights/WeightConfig";
|
||||||
import {WeightsFileManager} from "./weights/WeightsFileManager";
|
import {WeightsFileManager} from "./weights/WeightsFileManager";
|
||||||
import {type NodeType} from "../analysis/types";
|
import {type NodeType} from "../analysis/types";
|
||||||
|
@ -121,7 +122,7 @@ export class TimelineExplorer extends React.Component<Props, State> {
|
||||||
<div style={{marginTop: 30, display: "flex"}}>
|
<div style={{marginTop: 30, display: "flex"}}>
|
||||||
<span style={{paddingLeft: 30}}>
|
<span style={{paddingLeft: 30}}>
|
||||||
cred for {this.props.projectId}
|
cred for {this.props.projectId}
|
||||||
<a href={`/prototype/${this.props.projectId}/`}>(legacy)</a>
|
<Link to={`/prototype/${this.props.projectId}/`}>(legacy)</Link>
|
||||||
</span>
|
</span>
|
||||||
<span style={{flexGrow: 1}} />
|
<span style={{flexGrow: 1}} />
|
||||||
{this.renderFilterSelect()}
|
{this.renderFilterSelect()}
|
||||||
|
|
|
@ -146,7 +146,7 @@ export function createApp(
|
||||||
<h2>SourceCred Legacy Mode</h2>
|
<h2>SourceCred Legacy Mode</h2>
|
||||||
<p>
|
<p>
|
||||||
Back to{" "}
|
Back to{" "}
|
||||||
<a href={`/timeline/${this.props.projectId}/`}>timeline mode</a>
|
<Link to={`/timeline/${this.props.projectId}/`}>timeline mode</Link>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ProjectDetail projectId={this.props.projectId} />
|
<ProjectDetail projectId={this.props.projectId} />
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import stringify from "json-stable-stringify";
|
import stringify from "json-stable-stringify";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {FileUploader} from "../../util/FileUploader";
|
import {FileUploader} from "../../util/FileUploader";
|
||||||
|
import Link from "../../webutil/Link";
|
||||||
import {MdFileDownload, MdFileUpload} from "react-icons/md";
|
import {MdFileDownload, MdFileUpload} from "react-icons/md";
|
||||||
import {type Weights, toJSON, fromJSON} from "../../analysis/weights";
|
import {type Weights, toJSON, fromJSON} from "../../analysis/weights";
|
||||||
|
|
||||||
|
@ -16,14 +17,14 @@ export class WeightsFileManager extends React.Component<Props> {
|
||||||
const onUpload = (json) => this.props.onWeightsChange(fromJSON(json));
|
const onUpload = (json) => this.props.onWeightsChange(fromJSON(json));
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<a
|
<Link
|
||||||
download="weights.json"
|
download="weights.json"
|
||||||
title="Download your weights.json"
|
title="Download your weights.json"
|
||||||
href={`data:text/json,${weightsJSON}`}
|
href={`data:text/json,${weightsJSON}`}
|
||||||
style={{color: "black"}}
|
style={{color: "black"}}
|
||||||
>
|
>
|
||||||
<MdFileDownload style={{margin: "2px"}} />
|
<MdFileDownload style={{margin: "2px"}} />
|
||||||
</a>
|
</Link>
|
||||||
<FileUploader title="Upload weights.json" onUpload={onUpload}>
|
<FileUploader title="Upload weights.json" onUpload={onUpload}>
|
||||||
<MdFileUpload style={{margin: "2px"}} />
|
<MdFileUpload style={{margin: "2px"}} />
|
||||||
</FileUploader>
|
</FileUploader>
|
||||||
|
|
Loading…
Reference in New Issue