feat: add open in coder docs, fix missing templates (#4124)

* docs: add open in coder

This adds new documentation for the "Open in Coder" button that admins
can use to get their developers up and running faster.

* fix: display error if template not found

Previously, we weren't handling a case where we tried to get a template
that returned a 404 from the backend.

Now we handle that case in our state machine and display the error
message from the API on the frontend.

* feat: support template query param in index

This adds support to navigate directly to a template from the index by
using the `?template=<name>` query  param.

* Revert "feat: support template query param in index"

This reverts commit bad7ffb677.

We decided to use the `/template/path` route instead.

* fixup!: docs: add open in coder

* docs: add open in coder to dogfood readme

* Update docs/admin/open-in-coder.md

Co-authored-by: Ben Potter <ben@coder.com>

* Update docs/admin/open-in-coder.md

Co-authored-by: Ben Potter <ben@coder.com>

* Update docs/admin/open-in-coder.md

Co-authored-by: Ben Potter <ben@coder.com>
This commit is contained in:
Joe Previte
2022-09-22 08:48:03 -07:00
committed by GitHub
parent 7ad4276224
commit 764600003b
5 changed files with 68 additions and 0 deletions

View File

@ -0,0 +1,27 @@
# Open in Coder Button
Add a Markdown button to your project's `README.md` to get your developers up and running with Coder with a few clicks.
A basic example looks like this:
```markdown
[![Open in Coder](https://cdn.coder.com/embed-button.svg)](https://<deployment-url>/templates/<template-name>)
```
which renders like this:
![Open in Coder](https://cdn.coder.com/embed-button.svg)
You can customize this to take developers directly to your team's template. Read on to learn more.
### Customization
The underlying link for this button consists of the following pieces:
- <deployment-url>: where your Coder deployment lives i.e. https://dev.coder.com
- <template-name>: name of template i.e. coder
### template name
A template to redirect your developers to after they authenticate on your deployment.
Example: https://dev.coder.com/templates/coder

View File

@ -188,6 +188,11 @@
"title": "Enterprise", "title": "Enterprise",
"description": "Learn how to enable Enterprise features.", "description": "Learn how to enable Enterprise features.",
"path": "./admin/enterprise.md" "path": "./admin/enterprise.md"
},
{
"title": "Open in Coder Button",
"description": "Learn how to create an 'Open in Coder' button.",
"path": "./admin/open-in-coder.md"
} }
] ]
}, },

View File

@ -1,5 +1,7 @@
# dogfood template # dogfood template
[![Open in Coder](https://cdn.coder.com/embed-button.svg)](https://dev.coder.com/templates/coder)
Ammar is this template's admin. Ammar is this template's admin.
## Personalization ## Personalization

View File

@ -1,5 +1,8 @@
import { makeStyles } from "@material-ui/core/styles"
import { useMachine, useSelector } from "@xstate/react" import { useMachine, useSelector } from "@xstate/react"
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog" import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"
import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
import { Margins } from "components/Margins/Margins"
import { FC, useContext } from "react" import { FC, useContext } from "react"
import { Helmet } from "react-helmet-async" import { Helmet } from "react-helmet-async"
import { Navigate, useParams } from "react-router-dom" import { Navigate, useParams } from "react-router-dom"
@ -22,6 +25,7 @@ const useTemplateName = () => {
} }
export const TemplatePage: FC<React.PropsWithChildren<unknown>> = () => { export const TemplatePage: FC<React.PropsWithChildren<unknown>> = () => {
const styles = useStyles()
const organizationId = useOrganizationId() const organizationId = useOrganizationId()
const templateName = useTemplateName() const templateName = useTemplateName()
const [templateState, templateSend] = useMachine(templateMachine, { const [templateState, templateSend] = useMachine(templateMachine, {
@ -38,6 +42,7 @@ export const TemplatePage: FC<React.PropsWithChildren<unknown>> = () => {
templateVersions, templateVersions,
deleteTemplateError, deleteTemplateError,
templateDAUs, templateDAUs,
getTemplateError,
} = templateState.context } = templateState.context
const xServices = useContext(XServiceContext) const xServices = useContext(XServiceContext)
const permissions = useSelector(xServices.authXService, selectPermissions) const permissions = useSelector(xServices.authXService, selectPermissions)
@ -48,6 +53,16 @@ export const TemplatePage: FC<React.PropsWithChildren<unknown>> = () => {
templateSend("DELETE") templateSend("DELETE")
} }
if (templateState.matches("error") && Boolean(getTemplateError)) {
return (
<Margins>
<div className={styles.errorBox}>
<ErrorSummary error={getTemplateError} />
</div>
</Margins>
)
}
if (isLoading) { if (isLoading) {
return <Loader /> return <Loader />
} }
@ -88,4 +103,10 @@ export const TemplatePage: FC<React.PropsWithChildren<unknown>> = () => {
) )
} }
const useStyles = makeStyles((theme) => ({
errorBox: {
padding: theme.spacing(3),
},
}))
export default TemplatePage export default TemplatePage

View File

@ -25,6 +25,7 @@ interface TemplateContext {
templateVersions?: TemplateVersion[] templateVersions?: TemplateVersion[]
templateDAUs: TemplateDAUsResponse templateDAUs: TemplateDAUsResponse
deleteTemplateError?: Error | unknown deleteTemplateError?: Error | unknown
getTemplateError?: Error | unknown
} }
type TemplateEvent = { type: "DELETE" } | { type: "CONFIRM_DELETE" } | { type: "CANCEL_DELETE" } type TemplateEvent = { type: "DELETE" } | { type: "CONFIRM_DELETE" } | { type: "CANCEL_DELETE" }
@ -71,6 +72,12 @@ export const templateMachine =
target: "initialInfo", target: "initialInfo",
}, },
], ],
onError: [
{
actions: "assignGetTemplateError",
target: "error",
},
],
}, },
}, },
initialInfo: { initialInfo: {
@ -211,6 +218,9 @@ export const templateMachine =
deleted: { deleted: {
type: "final", type: "final",
}, },
error: {
type: "final",
},
}, },
}, },
{ {
@ -257,6 +267,9 @@ export const templateMachine =
assignActiveTemplateVersion: assign({ assignActiveTemplateVersion: assign({
activeTemplateVersion: (_, event) => event.data, activeTemplateVersion: (_, event) => event.data,
}), }),
assignGetTemplateError: assign({
getTemplateError: (_, event) => event.data,
}),
assignTemplateResources: assign({ assignTemplateResources: assign({
templateResources: (_, event) => event.data, templateResources: (_, event) => event.data,
}), }),