diff --git a/site/src/AppRouter.tsx b/site/src/AppRouter.tsx
index ce88dfc6c6e32..d979a37f4d616 100644
--- a/site/src/AppRouter.tsx
+++ b/site/src/AppRouter.tsx
@@ -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 = () => {
}>
} />
+ } />
} />
} />
diff --git a/site/src/components/TemplateLayout/TemplateLayout.tsx b/site/src/components/TemplateLayout/TemplateLayout.tsx
index f9b91da40556d..2dfd1569110a3 100644
--- a/site/src/components/TemplateLayout/TemplateLayout.tsx
+++ b/site/src/components/TemplateLayout/TemplateLayout.tsx
@@ -110,6 +110,18 @@ export const TemplateLayout: FC<{ children?: JSX.Element }> = ({
>
Summary
+
+ combineClasses([
+ styles.tabItem,
+ isActive ? styles.tabItemActive : undefined,
+ ])
+ }
+ >
+ Docs
+
{data.permissions.canUpdateTemplate && (
jest.fn())
+
+const TEMPLATE_NAME = "coder-ts"
+
+Object.defineProperty(window, "ResizeObserver", {
+ value: ResizeObserver,
+})
+
+const renderPage = () =>
+ renderWithAuth(
+
+
+ ,
+ {
+ route: `/templates/${TEMPLATE_NAME}/docs`,
+ path: "/templates/:template/docs",
+ },
+ )
+
+describe("TemplateSummaryPage", () => {
+ it("shows the template readme", async () => {
+ renderPage()
+ await screen.findByTestId("markdown")
+ })
+})
diff --git a/site/src/pages/TemplatePage/TemplateDocsPage/TemplateDocsPage.tsx b/site/src/pages/TemplatePage/TemplateDocsPage/TemplateDocsPage.tsx
new file mode 100644
index 0000000000000..d5e3670dcc4a0
--- /dev/null
+++ b/site/src/pages/TemplatePage/TemplateDocsPage/TemplateDocsPage.tsx
@@ -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 (
+ <>
+
+ {pageTitle(`${template.name} ยท Documentation`)}
+
+
+
+
README.md
+
+ {readme.body}
+
+
+ >
+ )
+}
+
+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",
+ },
+ }
+})
diff --git a/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPage.test.tsx b/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPage.test.tsx
index 7580f663bf3f9..05bacaa8fa5fd 100644
--- a/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPage.test.tsx
+++ b/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPage.test.tsx
@@ -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", () => {
diff --git a/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPageView.tsx b/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPageView.tsx
index 803692804ed60..47babcc06ade8 100644
--- a/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPageView.tsx
+++ b/site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPageView.tsx
@@ -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 = ({
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
}
const { daus, resources } = data
- const readme = frontMatter(activeVersion.readme)
const getStartedResources = (resources: WorkspaceResource[]) => {
return resources.filter(
@@ -45,13 +52,6 @@ export const TemplateSummaryPageView: FC = ({
{daus && }
-
-
-
README.md
-
- {readme.body}
-
-
)
}