feat(site): move template's readme to its own tab (#6863)

* feat(site): display template's readme first on template page

* chore: prettier

* move readme to a new docs tab

* test

* prettier

* fix tests

* prettier
This commit is contained in:
Rodrigo Maia
2023-04-03 15:18:28 -03:00
committed by GitHub
parent 95e578ba10
commit a1371dbd60
6 changed files with 114 additions and 16 deletions

View File

@ -132,9 +132,15 @@ const WorkspaceSettingsPage = lazy(
const CreateTokenPage = lazy(
() => import("./pages/CreateTokenPage/CreateTokenPage"),
)
const TemplateDocsPage = lazy(
() => import("./pages/TemplatePage/TemplateDocsPage/TemplateDocsPage"),
)
const TemplateFilesPage = lazy(
() => import("./pages/TemplatePage/TemplateFilesPage/TemplateFilesPage"),
)
const TemplateVersionsPage = lazy(
() =>
import("./pages/TemplatePage/TemplateVersionsPage/TemplateVersionsPage"),
@ -174,6 +180,7 @@ export const AppRouter: FC = () => {
<Route path=":template">
<Route element={<TemplateLayout />}>
<Route index element={<TemplateSummaryPage />} />
<Route path="docs" element={<TemplateDocsPage />} />
<Route path="files" element={<TemplateFilesPage />} />
<Route path="versions" element={<TemplateVersionsPage />} />
</Route>

View File

@ -110,6 +110,18 @@ export const TemplateLayout: FC<{ children?: JSX.Element }> = ({
>
Summary
</NavLink>
<NavLink
end
to={`/templates/${templateName}/docs`}
className={({ isActive }) =>
combineClasses([
styles.tabItem,
isActive ? styles.tabItemActive : undefined,
])
}
>
Docs
</NavLink>
{data.permissions.canUpdateTemplate && (
<NavLink
to={`/templates/${templateName}/files`}

View File

@ -0,0 +1,31 @@
import { screen } from "@testing-library/react"
import { TemplateLayout } from "components/TemplateLayout/TemplateLayout"
import { ResizeObserver } from "resize-observer"
import { renderWithAuth } from "testHelpers/renderHelpers"
import TemplateDocsPage from "./TemplateDocsPage"
jest.mock("remark-gfm", () => jest.fn())
const TEMPLATE_NAME = "coder-ts"
Object.defineProperty(window, "ResizeObserver", {
value: ResizeObserver,
})
const renderPage = () =>
renderWithAuth(
<TemplateLayout>
<TemplateDocsPage />
</TemplateLayout>,
{
route: `/templates/${TEMPLATE_NAME}/docs`,
path: "/templates/:template/docs",
},
)
describe("TemplateSummaryPage", () => {
it("shows the template readme", async () => {
renderPage()
await screen.findByTestId("markdown")
})
})

View File

@ -0,0 +1,51 @@
import { makeStyles } from "@material-ui/core/styles"
import { MemoizedMarkdown } from "components/Markdown/Markdown"
import { useTemplateLayoutContext } from "components/TemplateLayout/TemplateLayout"
import frontMatter from "front-matter"
import { Helmet } from "react-helmet-async"
import { pageTitle } from "util/page"
export default function TemplateDocsPage() {
const { template, activeVersion } = useTemplateLayoutContext()
const styles = useStyles()
const readme = frontMatter(activeVersion.readme)
return (
<>
<Helmet>
<title>{pageTitle(`${template.name} · Documentation`)}</title>
</Helmet>
<div className={styles.markdownSection} id="readme">
<div className={styles.readmeLabel}>README.md</div>
<div className={styles.markdownWrapper}>
<MemoizedMarkdown>{readme.body}</MemoizedMarkdown>
</div>
</div>
</>
)
}
export const useStyles = makeStyles((theme) => {
return {
markdownSection: {
background: theme.palette.background.paper,
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadius,
},
readmeLabel: {
color: theme.palette.text.secondary,
fontWeight: 600,
padding: theme.spacing(2, 3),
borderBottom: `1px solid ${theme.palette.divider}`,
},
markdownWrapper: {
padding: theme.spacing(0, 3, 5),
maxWidth: 800,
margin: "auto",
},
}
})

View File

@ -4,7 +4,6 @@ import { rest } from "msw"
import { ResizeObserver } from "resize-observer"
import {
MockTemplate,
MockWorkspaceResource,
MockTemplateVersion,
MockMemberPermissions,
} from "testHelpers/entities"
@ -31,15 +30,13 @@ const renderPage = () =>
)
describe("TemplateSummaryPage", () => {
it("shows the template name, readme and resources", async () => {
it("shows the template name and resources", async () => {
// Mocking the dayjs module within the createDayString file
const mock = jest.spyOn(CreateDayString, "createDayString")
mock.mockImplementation(() => "a minute ago")
renderPage()
await screen.findByText(MockTemplate.display_name)
await screen.findByTestId("markdown")
screen.getByText(MockWorkspaceResource.name)
screen.queryAllByText(`${MockTemplateVersion.name}`).length
})
it("does not allow a member to delete a template", () => {

View File

@ -5,14 +5,13 @@ import {
WorkspaceResource,
} from "api/typesGenerated"
import { Loader } from "components/Loader/Loader"
import { MemoizedMarkdown } from "components/Markdown/Markdown"
import { Stack } from "components/Stack/Stack"
import { TemplateResourcesTable } from "components/TemplateResourcesTable/TemplateResourcesTable"
import { TemplateStats } from "components/TemplateStats/TemplateStats"
import frontMatter from "front-matter"
import { FC } from "react"
import { FC, useEffect } from "react"
import { DAUChart } from "../../../components/DAUChart/DAUChart"
import { TemplateSummaryData } from "./data"
import { useLocation, useNavigate } from "react-router-dom"
export interface TemplateSummaryPageViewProps {
data?: TemplateSummaryData
@ -25,14 +24,22 @@ export const TemplateSummaryPageView: FC<TemplateSummaryPageViewProps> = ({
template,
activeVersion,
}) => {
const styles = useStyles()
const navigate = useNavigate()
const location = useLocation()
useEffect(() => {
if (location.hash === "#readme") {
// We moved the readme to the docs page, but we known that some users
// have bookmarked the readme or linked it elsewhere. Redirect them to the docs page.
navigate(`/templates/${template.name}/docs`, { replace: true })
}
}, [template, navigate, location])
if (!data) {
return <Loader />
}
const { daus, resources } = data
const readme = frontMatter(activeVersion.readme)
const getStartedResources = (resources: WorkspaceResource[]) => {
return resources.filter(
@ -45,13 +52,6 @@ export const TemplateSummaryPageView: FC<TemplateSummaryPageViewProps> = ({
<TemplateStats template={template} activeVersion={activeVersion} />
{daus && <DAUChart daus={daus} />}
<TemplateResourcesTable resources={getStartedResources(resources)} />
<div className={styles.markdownSection} id="readme">
<div className={styles.readmeLabel}>README.md</div>
<div className={styles.markdownWrapper}>
<MemoizedMarkdown>{readme.body}</MemoizedMarkdown>
</div>
</div>
</Stack>
)
}