diff --git a/docs/admin/open-in-coder.md b/docs/admin/open-in-coder.md new file mode 100644 index 0000000000000..34da7aade090a --- /dev/null +++ b/docs/admin/open-in-coder.md @@ -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:///templates/) +``` + +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: +- : where your Coder deployment lives i.e. https://dev.coder.com +- : 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 diff --git a/docs/manifest.json b/docs/manifest.json index a0aa731d77d61..59678ea5b7690 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -188,6 +188,11 @@ "title": "Enterprise", "description": "Learn how to enable Enterprise features.", "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" } ] }, diff --git a/dogfood/README.md b/dogfood/README.md index 36db0cd4e1577..b07f2d7c74071 100644 --- a/dogfood/README.md +++ b/dogfood/README.md @@ -1,5 +1,7 @@ # dogfood template +[![Open in Coder](https://cdn.coder.com/embed-button.svg)](https://dev.coder.com/templates/coder) + Ammar is this template's admin. ## Personalization diff --git a/site/src/pages/TemplatePage/TemplatePage.tsx b/site/src/pages/TemplatePage/TemplatePage.tsx index 95141c53841f2..2b9baa94d6e2e 100644 --- a/site/src/pages/TemplatePage/TemplatePage.tsx +++ b/site/src/pages/TemplatePage/TemplatePage.tsx @@ -1,5 +1,8 @@ +import { makeStyles } from "@material-ui/core/styles" import { useMachine, useSelector } from "@xstate/react" 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 { Helmet } from "react-helmet-async" import { useTranslation } from "react-i18next" @@ -23,6 +26,7 @@ const useTemplateName = () => { } export const TemplatePage: FC> = () => { + const styles = useStyles() const organizationId = useOrganizationId() const { t } = useTranslation("templatePage") const templateName = useTemplateName() @@ -40,6 +44,7 @@ export const TemplatePage: FC> = () => { templateVersions, deleteTemplateError, templateDAUs, + getTemplateError, } = templateState.context const xServices = useContext(XServiceContext) const permissions = useSelector(xServices.authXService, selectPermissions) @@ -50,6 +55,16 @@ export const TemplatePage: FC> = () => { templateSend("DELETE") } + if (templateState.matches("error") && Boolean(getTemplateError)) { + return ( + +
+ +
+
+ ) + } + if (isLoading) { return } @@ -90,4 +105,10 @@ export const TemplatePage: FC> = () => { ) } +const useStyles = makeStyles((theme) => ({ + errorBox: { + padding: theme.spacing(3), + }, +})) + export default TemplatePage diff --git a/site/src/xServices/template/templateXService.ts b/site/src/xServices/template/templateXService.ts index 671cb9cf2d643..a3c1fa7b619c5 100644 --- a/site/src/xServices/template/templateXService.ts +++ b/site/src/xServices/template/templateXService.ts @@ -25,6 +25,7 @@ interface TemplateContext { templateVersions?: TemplateVersion[] templateDAUs: TemplateDAUsResponse deleteTemplateError?: Error | unknown + getTemplateError?: Error | unknown } type TemplateEvent = { type: "DELETE" } | { type: "CONFIRM_DELETE" } | { type: "CANCEL_DELETE" } @@ -71,6 +72,12 @@ export const templateMachine = target: "initialInfo", }, ], + onError: [ + { + actions: "assignGetTemplateError", + target: "error", + }, + ], }, }, initialInfo: { @@ -211,6 +218,9 @@ export const templateMachine = deleted: { type: "final", }, + error: { + type: "final", + }, }, }, { @@ -257,6 +267,9 @@ export const templateMachine = assignActiveTemplateVersion: assign({ activeTemplateVersion: (_, event) => event.data, }), + assignGetTemplateError: assign({ + getTemplateError: (_, event) => event.data, + }), assignTemplateResources: assign({ templateResources: (_, event) => event.data, }),