Skip to content

Commit 7dcfea1

Browse files
authored
feat: add feedback link to footer (#2447)
* add ability to activate users resolves #2254 * added test * PR feedback * guarding against null validation_contains field * fixing type for ParameterSchema resolves #2161 * added report link to footer resolves #1885 * added test * Footer story * fix broken test
1 parent 64b92ee commit 7dcfea1

File tree

5 files changed

+82
-32
lines changed

5 files changed

+82
-32
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!--- Provide a general summary of the issue in the Title above -->
2+
3+
## Expected Behavior
4+
5+
<!--- Tell us what should happen -->
6+
7+
## Current Behavior
8+
9+
<!--- Tell us what happens instead of the expected behavior -->
Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { FC } from "react"
1+
import { makeStyles } from "@material-ui/core/styles"
2+
import { useActor } from "@xstate/react"
3+
import { FC, useContext } from "react"
4+
import { XServiceContext } from "../../xServices/StateContext"
25
import { Footer } from "../Footer/Footer"
36
import { Navbar } from "../Navbar/Navbar"
47
import { RequireAuth } from "../RequireAuth/RequireAuth"
@@ -10,12 +13,30 @@ interface AuthAndFrameProps {
1013
/**
1114
* Wraps page in RequireAuth and renders it between Navbar and Footer
1215
*/
13-
export const AuthAndFrame: FC<AuthAndFrameProps> = ({ children }) => (
14-
<RequireAuth>
15-
<>
16-
<Navbar />
17-
{children}
18-
<Footer />
19-
</>
20-
</RequireAuth>
21-
)
16+
export const AuthAndFrame: FC<AuthAndFrameProps> = ({ children }) => {
17+
const styles = useStyles()
18+
const xServices = useContext(XServiceContext)
19+
20+
const [buildInfoState] = useActor(xServices.buildInfoXService)
21+
22+
return (
23+
<RequireAuth>
24+
<div className={styles.site}>
25+
<Navbar />
26+
<div className={styles.siteContent}>{children}</div>
27+
<Footer buildInfo={buildInfoState.context.buildInfo} />
28+
</div>
29+
</RequireAuth>
30+
)
31+
}
32+
33+
const useStyles = makeStyles(() => ({
34+
site: {
35+
display: "flex",
36+
minHeight: "100vh",
37+
flexDirection: "column",
38+
},
39+
siteContent: {
40+
flex: 1,
41+
},
42+
}))
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Story } from "@storybook/react"
2+
import { Footer, FooterProps } from "./Footer"
3+
4+
export default {
5+
title: "components/Footer",
6+
component: Footer,
7+
}
8+
9+
const Template: Story<FooterProps> = (args) => <Footer {...args} />
10+
11+
export const Example = Template.bind({})
12+
Example.args = {
13+
buildInfo: {
14+
external_url: "",
15+
version: "test-1.2.3",
16+
},
17+
}

site/src/components/Footer/Footer.test.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ import { Footer, Language } from "./Footer"
55
describe("Footer", () => {
66
it("renders content", async () => {
77
// When
8-
render(<Footer />)
8+
render(<Footer buildInfo={MockBuildInfo} />)
99

1010
// Then
1111
await screen.findByText("Copyright", { exact: false })
1212
await screen.findByText(Language.buildInfoText(MockBuildInfo))
13+
const reportBugLink = screen.getByText(Language.reportBugLink, { exact: false }).closest("a")
14+
if (!reportBugLink) {
15+
throw new Error("Bug report link not found in footer")
16+
}
17+
18+
expect(reportBugLink.getAttribute("href")).toBe(
19+
`https://github.com/coder/coder/issues/new?labels=bug,needs+grooming&title=Bug+in+${MockBuildInfo.version}:&template=external_bug_report.md`,
20+
)
1321
})
1422
})

site/src/components/Footer/Footer.tsx

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,34 @@
11
import Link from "@material-ui/core/Link"
22
import { makeStyles } from "@material-ui/core/styles"
3-
import Typography from "@material-ui/core/Typography"
4-
import { useActor } from "@xstate/react"
5-
import React, { useContext } from "react"
63
import * as TypesGen from "../../api/typesGenerated"
7-
import { XServiceContext } from "../../xServices/StateContext"
84

95
export const Language = {
106
buildInfoText: (buildInfo: TypesGen.BuildInfoResponse): string => {
117
return `Coder ${buildInfo.version}`
128
},
9+
copyrightText: `Copyright \u00a9 ${new Date().getFullYear()} Coder Technologies, Inc. All rights reserved.`,
10+
reportBugLink: "Report an issue",
1311
}
1412

15-
export const Footer: React.FC = ({ children }) => {
13+
export interface FooterProps {
14+
buildInfo?: TypesGen.BuildInfoResponse
15+
}
16+
17+
export const Footer: React.FC<FooterProps> = ({ buildInfo }) => {
1618
const styles = useFooterStyles()
17-
const xServices = useContext(XServiceContext)
18-
const [buildInfoState] = useActor(xServices.buildInfoXService)
19+
20+
const githubUrl = `https://github.com/coder/coder/issues/new?labels=bug,needs+grooming&title=Bug+in+${buildInfo?.version}:&template=external_bug_report.md`
1921

2022
return (
2123
<div className={styles.root}>
22-
{children}
23-
<div className={styles.copyRight}>
24-
<Typography color="textSecondary" variant="caption">
25-
{`Copyright \u00a9 ${new Date().getFullYear()} Coder Technologies, Inc. All rights reserved.`}
26-
</Typography>
27-
</div>
28-
{buildInfoState.context.buildInfo && (
24+
<Link className={styles.link} variant="caption" target="_blank" href={githubUrl}>
25+
&#129714;&nbsp;{Language.reportBugLink}
26+
</Link>
27+
<div className={styles.copyRight}>{Language.copyrightText}</div>
28+
{buildInfo && (
2929
<div className={styles.buildInfo}>
30-
<Link
31-
className={styles.link}
32-
variant="caption"
33-
target="_blank"
34-
href={buildInfoState.context.buildInfo.external_url}
35-
>
36-
{Language.buildInfoText(buildInfoState.context.buildInfo)}
30+
<Link className={styles.link} variant="caption" target="_blank" href={buildInfo.external_url}>
31+
{Language.buildInfoText(buildInfo)}
3732
</Link>
3833
</div>
3934
)}

0 commit comments

Comments
 (0)