Skip to content

feat: add feedback link to footer #2447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 17, 2022
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
9 changes: 9 additions & 0 deletions .github/ISSUE_TEMPLATE/external_bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!--- Provide a general summary of the issue in the Title above -->

## Expected Behavior

<!--- Tell us what should happen -->

## Current Behavior

<!--- Tell us what happens instead of the expected behavior -->
41 changes: 31 additions & 10 deletions site/src/components/AuthAndFrame/AuthAndFrame.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { FC } from "react"
import { makeStyles } from "@material-ui/core/styles"
import { useActor } from "@xstate/react"
import { FC, useContext } from "react"
import { XServiceContext } from "../../xServices/StateContext"
import { Footer } from "../Footer/Footer"
import { Navbar } from "../Navbar/Navbar"
import { RequireAuth } from "../RequireAuth/RequireAuth"
Expand All @@ -10,12 +13,30 @@ interface AuthAndFrameProps {
/**
* Wraps page in RequireAuth and renders it between Navbar and Footer
*/
export const AuthAndFrame: FC<AuthAndFrameProps> = ({ children }) => (
<RequireAuth>
<>
<Navbar />
{children}
<Footer />
</>
</RequireAuth>
)
export const AuthAndFrame: FC<AuthAndFrameProps> = ({ children }) => {
const styles = useStyles()
const xServices = useContext(XServiceContext)

const [buildInfoState] = useActor(xServices.buildInfoXService)

return (
<RequireAuth>
<div className={styles.site}>
<Navbar />
<div className={styles.siteContent}>{children}</div>
<Footer buildInfo={buildInfoState.context.buildInfo} />
</div>
</RequireAuth>
)
}

const useStyles = makeStyles(() => ({
site: {
display: "flex",
minHeight: "100vh",
flexDirection: "column",
},
siteContent: {
flex: 1,
},
}))
17 changes: 17 additions & 0 deletions site/src/components/Footer/Footer.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Story } from "@storybook/react"
import { Footer, FooterProps } from "./Footer"

export default {
title: "components/Footer",
component: Footer,
}

const Template: Story<FooterProps> = (args) => <Footer {...args} />

export const Example = Template.bind({})
Example.args = {
buildInfo: {
external_url: "",
version: "test-1.2.3",
},
}
10 changes: 9 additions & 1 deletion site/src/components/Footer/Footer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ import { Footer, Language } from "./Footer"
describe("Footer", () => {
it("renders content", async () => {
// When
render(<Footer />)
render(<Footer buildInfo={MockBuildInfo} />)

// Then
await screen.findByText("Copyright", { exact: false })
await screen.findByText(Language.buildInfoText(MockBuildInfo))
const reportBugLink = screen.getByText(Language.reportBugLink, { exact: false }).closest("a")
if (!reportBugLink) {
throw new Error("Bug report link not found in footer")
}

expect(reportBugLink.getAttribute("href")).toBe(
`https://github.com/coder/coder/issues/new?labels=bug,needs+grooming&title=Bug+in+${MockBuildInfo.version}:&template=external_bug_report.md`,
)
})
})
37 changes: 16 additions & 21 deletions site/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
import Link from "@material-ui/core/Link"
import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
import { useActor } from "@xstate/react"
import React, { useContext } from "react"
import * as TypesGen from "../../api/typesGenerated"
import { XServiceContext } from "../../xServices/StateContext"

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

export const Footer: React.FC = ({ children }) => {
export interface FooterProps {
buildInfo?: TypesGen.BuildInfoResponse
}

export const Footer: React.FC<FooterProps> = ({ buildInfo }) => {
const styles = useFooterStyles()
const xServices = useContext(XServiceContext)
const [buildInfoState] = useActor(xServices.buildInfoXService)

const githubUrl = `https://github.com/coder/coder/issues/new?labels=bug,needs+grooming&title=Bug+in+${buildInfo?.version}:&template=external_bug_report.md`

return (
<div className={styles.root}>
{children}
<div className={styles.copyRight}>
<Typography color="textSecondary" variant="caption">
{`Copyright \u00a9 ${new Date().getFullYear()} Coder Technologies, Inc. All rights reserved.`}
</Typography>
</div>
{buildInfoState.context.buildInfo && (
<Link className={styles.link} variant="caption" target="_blank" href={githubUrl}>
&#129714;&nbsp;{Language.reportBugLink}
</Link>
<div className={styles.copyRight}>{Language.copyrightText}</div>
{buildInfo && (
<div className={styles.buildInfo}>
<Link
className={styles.link}
variant="caption"
target="_blank"
href={buildInfoState.context.buildInfo.external_url}
>
{Language.buildInfoText(buildInfoState.context.buildInfo)}
<Link className={styles.link} variant="caption" target="_blank" href={buildInfo.external_url}>
{Language.buildInfoText(buildInfo)}
</Link>
</div>
)}
Expand Down