mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
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:
27
docs/admin/open-in-coder.md
Normal file
27
docs/admin/open-in-coder.md
Normal 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
|
||||||
|
[](https://<deployment-url>/templates/<template-name>)
|
||||||
|
```
|
||||||
|
|
||||||
|
which renders like this:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
@ -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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# dogfood template
|
# dogfood template
|
||||||
|
|
||||||
|
[](https://dev.coder.com/templates/coder)
|
||||||
|
|
||||||
Ammar is this template's admin.
|
Ammar is this template's admin.
|
||||||
|
|
||||||
## Personalization
|
## Personalization
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
}),
|
}),
|
||||||
|
Reference in New Issue
Block a user