From 811872fb306bf8f8cf7c28df5a14ea9ff75bf787 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Thu, 8 Feb 2024 17:51:13 +0000 Subject: [PATCH 01/14] Add scratch as starter template --- docs/cli/templates_init.md | 6 +-- examples/examples.gen.json | 9 ++++ examples/examples.go | 1 + examples/templates/scratch/README.md | 12 ++++++ examples/templates/scratch/main.tf | 64 ++++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 examples/templates/scratch/README.md create mode 100644 examples/templates/scratch/main.tf diff --git a/docs/cli/templates_init.md b/docs/cli/templates_init.md index 06b4c849f4698..0e20a7acaada6 100644 --- a/docs/cli/templates_init.md +++ b/docs/cli/templates_init.md @@ -14,8 +14,8 @@ coder templates init [flags] [directory] ### --id -| | | -| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Type | enum[aws-devcontainer\|aws-linux\|aws-windows\|azure-linux\|do-linux\|docker\|gcp-devcontainer\|gcp-linux\|gcp-vm-container\|gcp-windows\|kubernetes\|nomad-docker] | +| | | +| ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Type | enum[aws-devcontainer\|aws-linux\|aws-windows\|azure-linux\|do-linux\|docker\|gcp-devcontainer\|gcp-linux\|gcp-vm-container\|gcp-windows\|kubernetes\|nomad-docker\|scratch] | Specify a given example template by ID. diff --git a/examples/examples.gen.json b/examples/examples.gen.json index 270357a31077f..f8f80b1e6f5ad 100644 --- a/examples/examples.gen.json +++ b/examples/examples.gen.json @@ -156,5 +156,14 @@ "container" ], "markdown": "\n# Remote Development on Nomad\n\nProvision Nomad Jobs as [Coder workspaces](https://coder.com/docs/v2/latest/workspaces) with this example template. This example shows how to use Nomad service tasks to be used as a development environment using docker and host csi volumes.\n\n\u003c!-- TODO: Add screenshot --\u003e\n\n\u003e **Note**\n\u003e This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case.\n\n## Prerequisites\n\n- [Nomad](https://www.nomadproject.io/downloads)\n- [Docker](https://docs.docker.com/get-docker/)\n\n## Setup\n\n### 1. Start the CSI Host Volume Plugin\n\nThe CSI Host Volume plugin is used to mount host volumes into Nomad tasks. This is useful for development environments where you want to mount persistent volumes into your container workspace.\n\n1. Login to the Nomad server using SSH.\n\n2. Append the following stanza to your Nomad server configuration file and restart the nomad service.\n\n ```hcl\n plugin \"docker\" {\n config {\n allow_privileged = true\n }\n }\n ```\n\n ```shell\n sudo systemctl restart nomad\n ```\n\n3. Create a file `hostpath.nomad` with following content:\n\n ```hcl\n job \"hostpath-csi-plugin\" {\n datacenters = [\"dc1\"]\n type = \"system\"\n\n group \"csi\" {\n task \"plugin\" {\n driver = \"docker\"\n\n config {\n image = \"registry.k8s.io/sig-storage/hostpathplugin:v1.10.0\"\n\n args = [\n \"--drivername=csi-hostpath\",\n \"--v=5\",\n \"--endpoint=${CSI_ENDPOINT}\",\n \"--nodeid=node-${NOMAD_ALLOC_INDEX}\",\n ]\n\n privileged = true\n }\n\n csi_plugin {\n id = \"hostpath\"\n type = \"monolith\"\n mount_dir = \"/csi\"\n }\n\n resources {\n cpu = 256\n memory = 128\n }\n }\n }\n }\n ```\n\n4. Run the job:\n\n ```shell\n nomad job run hostpath.nomad\n ```\n\n### 2. Setup the Nomad Template\n\n1. Create the template by running the following command:\n\n ```shell\n coder template init nomad-docker\n cd nomad-docker\n coder template push\n ```\n\n2. Set up Nomad server address and optional authentication:\n\n3. Create a new workspace and start developing.\n" + }, + { + "id": "scratch", + "url": "", + "name": "Scratch", + "description": "A minimal Scaffolding for a Coder Template", + "icon": "/emojis/1f4e6.png", + "tags": [], + "markdown": "\n# A minimal Scaffolding for a Coder Template\n\nUse this starter template as a basis to create your own unique template from scratch.\n" } ] diff --git a/examples/examples.go b/examples/examples.go index 9672f52781dc2..af2dc80bc6016 100644 --- a/examples/examples.go +++ b/examples/examples.go @@ -35,6 +35,7 @@ var ( //go:embed templates/gcp-windows //go:embed templates/kubernetes //go:embed templates/nomad-docker + //go:embed templates/scratch files embed.FS exampleBasePath = "https://github.com/coder/coder/tree/main/examples/templates/" diff --git a/examples/templates/scratch/README.md b/examples/templates/scratch/README.md new file mode 100644 index 0000000000000..5752c22cf949c --- /dev/null +++ b/examples/templates/scratch/README.md @@ -0,0 +1,12 @@ +--- +display_name: Scratch +description: A minimal Scaffolding for a Coder Template +icon: ../../../site/static/emojis/1f4e6.png +maintainer_github: coder +verified: true +tags: [] +--- + +# A minimal Scaffolding for a Coder Template + +Use this starter template as a basis to create your own unique template from scratch. diff --git a/examples/templates/scratch/main.tf b/examples/templates/scratch/main.tf new file mode 100644 index 0000000000000..c3f209a38b35a --- /dev/null +++ b/examples/templates/scratch/main.tf @@ -0,0 +1,64 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + } +} + +data "coder_provisioner" "me" {} + +data "coder_workspace" "me" {} + +resource "coder_agent" "main" { + arch = data.coder_provisioner.me.arch + os = data.coder_provisioner.me.os + startup_script_timeout = 180 + startup_script = <<-EOT + set -e + # Run programs at workspace startup + EOT + + metadata { + display_name = "CPU Usage" + key = "0_cpu_usage" + script = "coder stat cpu" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "RAM Usage" + key = "1_ram_usage" + script = "coder stat mem" + interval = 10 + timeout = 1 + } +} + +# Use this to set environment variables in your workspace +# details: https://registry.terraform.io/providers/coder/coder/latest/docs/resources/env +resource "coder_env" "my_env" { + agent_id = coder_agent.main.id + name = "FOO" + value = "bar" +} + +# Adds code-server +# See all available modules at https://regsitry.coder.com +module "code-server" { + source = "registry.coder.com/modules/code-server/coder" + version = "1.0.2" + agent_id = coder_agent.main.id +} + +# Runs a script at workspace start/stop or on a cron schedule +# details: https://registry.terraform.io/providers/coder/coder/latest/docs/resources/script +resource "coder_script" "my_script" { + agent_id = coder_agent.main.id + display_name = "My Script" + run_on_start = true + script = <<-EOF + echo "Hello ${data.coder_workspace.me.owner}!" + EOF +} From 4c60dccc8981b88d7a6627c0391632f077f3abfa Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 12:14:00 +0000 Subject: [PATCH 02/14] Add create from scratch flow --- .../CreateTemplatePage/CreateTemplatePage.tsx | 11 +++- .../DuplicateTemplateView.tsx | 11 +++- .../ImportStarterTemplateView.tsx | 11 +++- .../CreateTemplatePage/UploadTemplateView.tsx | 12 +++- .../pages/TemplatesPage/TemplatesPageView.tsx | 58 ++++++++++++++----- 5 files changed, 80 insertions(+), 23 deletions(-) diff --git a/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx b/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx index 7051a5ab953f4..c5440e0929701 100644 --- a/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx +++ b/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx @@ -6,11 +6,16 @@ import { FullPageHorizontalForm } from "components/FullPageForm/FullPageHorizont import { DuplicateTemplateView } from "./DuplicateTemplateView"; import { ImportStarterTemplateView } from "./ImportStarterTemplateView"; import { UploadTemplateView } from "./UploadTemplateView"; +import { Template } from "api/typesGenerated"; const CreateTemplatePage: FC = () => { const navigate = useNavigate(); const [searchParams] = useSearchParams(); + const onSuccess = (template: Template) => { + navigate(`/templates/${template.name}/files`); + }; + const onCancel = () => { navigate(-1); }; @@ -23,11 +28,11 @@ const CreateTemplatePage: FC = () => { {searchParams.has("fromTemplate") ? ( - + ) : searchParams.has("exampleId") ? ( - + ) : ( - + )} diff --git a/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx b/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx index 3a96ce6b9b571..62540343c9c1d 100644 --- a/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx +++ b/site/src/pages/CreateTemplatePage/DuplicateTemplateView.tsx @@ -15,8 +15,15 @@ import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Loader } from "components/Loader/Loader"; import { CreateTemplateForm } from "./CreateTemplateForm"; import { firstVersionFromFile, getFormPermissions, newTemplate } from "./utils"; +import { Template } from "api/typesGenerated"; -export const DuplicateTemplateView: FC = () => { +type DuplicateTemplateViewProps = { + onSuccess: (template: Template) => void; +}; + +export const DuplicateTemplateView: FC = ({ + onSuccess, +}) => { const navigate = useNavigate(); const organizationId = useOrganizationId(); const [searchParams] = useSearchParams(); @@ -79,7 +86,7 @@ export const DuplicateTemplateView: FC = () => { ), template: newTemplate(formData), }); - navigate(`/templates/${template.name}`); + onSuccess(template); }} /> ); diff --git a/site/src/pages/CreateTemplatePage/ImportStarterTemplateView.tsx b/site/src/pages/CreateTemplatePage/ImportStarterTemplateView.tsx index 9ab04ab7044e8..5075b0ecae915 100644 --- a/site/src/pages/CreateTemplatePage/ImportStarterTemplateView.tsx +++ b/site/src/pages/CreateTemplatePage/ImportStarterTemplateView.tsx @@ -18,8 +18,15 @@ import { getFormPermissions, newTemplate, } from "./utils"; +import { Template } from "api/typesGenerated"; -export const ImportStarterTemplateView: FC = () => { +type ImportStarterTemplateViewProps = { + onSuccess: (template: Template) => void; +}; + +export const ImportStarterTemplateView: FC = ({ + onSuccess, +}) => { const navigate = useNavigate(); const organizationId = useOrganizationId(); const [searchParams] = useSearchParams(); @@ -76,7 +83,7 @@ export const ImportStarterTemplateView: FC = () => { ), template: newTemplate(formData), }); - navigate(`/templates/${template.name}`); + onSuccess(template); }} /> ); diff --git a/site/src/pages/CreateTemplatePage/UploadTemplateView.tsx b/site/src/pages/CreateTemplatePage/UploadTemplateView.tsx index e6f4e918ec3ac..d228e484d0e4d 100644 --- a/site/src/pages/CreateTemplatePage/UploadTemplateView.tsx +++ b/site/src/pages/CreateTemplatePage/UploadTemplateView.tsx @@ -11,8 +11,16 @@ import { useOrganizationId } from "contexts/auth/useOrganizationId"; import { useDashboard } from "modules/dashboard/useDashboard"; import { CreateTemplateForm } from "./CreateTemplateForm"; import { firstVersionFromFile, getFormPermissions, newTemplate } from "./utils"; +import { Template } from "api/typesGenerated"; +import { FC } from "react"; -export const UploadTemplateView = () => { +type UploadTemplateViewProps = { + onSuccess: (template: Template) => void; +}; + +export const UploadTemplateView: FC = ({ + onSuccess, +}) => { const navigate = useNavigate(); const organizationId = useOrganizationId(); @@ -61,7 +69,7 @@ export const UploadTemplateView = () => { ), template: newTemplate(formData), }); - navigate(`/templates/${template.name}`); + onSuccess(template); }} /> ); diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 276a77ea5f8d3..98a0b6152895e 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -8,7 +8,7 @@ import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; import AddIcon from "@mui/icons-material/AddOutlined"; import { type FC } from "react"; -import { useNavigate, Link as RouterLink } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import { createDayString } from "utils/createDayString"; import { formatTemplateBuildTime, @@ -45,6 +45,15 @@ import { docs } from "utils/docs"; import Skeleton from "@mui/material/Skeleton"; import { AvatarDataSkeleton } from "components/AvatarData/AvatarDataSkeleton"; import { DeprecatedBadge } from "components/Badges/Badges"; +import { + MoreMenu, + MoreMenuContent, + MoreMenuItem, + MoreMenuTrigger, +} from "components/MoreMenu/MoreMenu"; +import NoteAddOutlined from "@mui/icons-material/NoteAddOutlined"; +import UploadOutlined from "@mui/icons-material/UploadOutlined"; +import Inventory2 from "@mui/icons-material/Inventory2"; export const Language = { developerCount: (activeCount: number): string => { @@ -165,25 +174,46 @@ export const TemplatesPageView: FC = ({ }) => { const isLoading = !templates; const isEmpty = templates && templates.length === 0; + const navigate = useNavigate(); return ( - - - + + + + + + { + navigate(`/templates/new?exampleId=scratch`); + }} + > + + From scratch + + { + navigate("/templates/new"); + }} + > + + Upload template + + { + navigate("/starter-templates"); + }} + > + + Choose a starter template + + + ) } > From cdb36a82a5fa11e11c94b4e070ca04019ba96420 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 12:23:44 +0000 Subject: [PATCH 03/14] Don't show scratch template --- .../pages/StarterTemplatesPage/StarterTemplatesPage.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/site/src/pages/StarterTemplatesPage/StarterTemplatesPage.tsx b/site/src/pages/StarterTemplatesPage/StarterTemplatesPage.tsx index 5c47bc1311fec..e24a37026700a 100644 --- a/site/src/pages/StarterTemplatesPage/StarterTemplatesPage.tsx +++ b/site/src/pages/StarterTemplatesPage/StarterTemplatesPage.tsx @@ -6,12 +6,14 @@ import { useOrganizationId } from "contexts/auth/useOrganizationId"; import { pageTitle } from "utils/page"; import { getTemplatesByTag } from "utils/starterTemplates"; import { StarterTemplatesPageView } from "./StarterTemplatesPageView"; +import { TemplateExample } from "api/typesGenerated"; const StarterTemplatesPage: FC = () => { const organizationId = useOrganizationId(); const templateExamplesQuery = useQuery(templateExamples(organizationId)); const starterTemplatesByTag = templateExamplesQuery.data - ? getTemplatesByTag(templateExamplesQuery.data) + ? // Currently, the scratch template should not be displayed on the starter templates page. + getTemplatesByTag(removeScratchExample(templateExamplesQuery.data)) : undefined; return ( @@ -28,4 +30,8 @@ const StarterTemplatesPage: FC = () => { ); }; +const removeScratchExample = (data: TemplateExample[]) => { + return data.filter((example) => example.id !== "scratch"); +}; + export default StarterTemplatesPage; From 2e756c4553bf8d640473eb1aef58a0c444a96af9 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 12:33:09 +0000 Subject: [PATCH 04/14] Add stories for create template button --- .../CreateTemplateButton.stories.tsx | 22 ++++++++ .../TemplatesPage/CreateTemplateButton.tsx | 56 +++++++++++++++++++ .../pages/TemplatesPage/TemplatesPageView.tsx | 47 +--------------- 3 files changed, 80 insertions(+), 45 deletions(-) create mode 100644 site/src/pages/TemplatesPage/CreateTemplateButton.stories.tsx create mode 100644 site/src/pages/TemplatesPage/CreateTemplateButton.tsx diff --git a/site/src/pages/TemplatesPage/CreateTemplateButton.stories.tsx b/site/src/pages/TemplatesPage/CreateTemplateButton.stories.tsx new file mode 100644 index 0000000000000..c1c965662c604 --- /dev/null +++ b/site/src/pages/TemplatesPage/CreateTemplateButton.stories.tsx @@ -0,0 +1,22 @@ +import { CreateTemplateButton } from "./CreateTemplateButton"; +import type { Meta, StoryObj } from "@storybook/react"; +import { userEvent, screen } from "@storybook/test"; + +const meta: Meta = { + title: "pages/TemplatesPage/CreateTemplateButton", + component: CreateTemplateButton, +}; + +export default meta; +type Story = StoryObj; + +export const Close: Story = {}; + +export const Open: Story = { + play: async ({ step }) => { + const user = userEvent.setup(); + await step("click on trigger", async () => { + await user.click(screen.getByRole("button")); + }); + }, +}; diff --git a/site/src/pages/TemplatesPage/CreateTemplateButton.tsx b/site/src/pages/TemplatesPage/CreateTemplateButton.tsx new file mode 100644 index 0000000000000..12057045d6a21 --- /dev/null +++ b/site/src/pages/TemplatesPage/CreateTemplateButton.tsx @@ -0,0 +1,56 @@ +import Button from "@mui/material/Button"; +import AddIcon from "@mui/icons-material/AddOutlined"; +import { + MoreMenu, + MoreMenuContent, + MoreMenuItem, + MoreMenuTrigger, +} from "components/MoreMenu/MoreMenu"; +import NoteAddOutlined from "@mui/icons-material/NoteAddOutlined"; +import UploadOutlined from "@mui/icons-material/UploadOutlined"; +import Inventory2 from "@mui/icons-material/Inventory2"; +import { FC } from "react"; + +type CreateTemplateButtonProps = { + onNavigate: (path: string) => void; +}; + +export const CreateTemplateButton: FC = ({ + onNavigate, +}) => { + return ( + + + + + + { + onNavigate(`/templates/new?exampleId=scratch`); + }} + > + + From scratch + + { + onNavigate("/templates/new"); + }} + > + + Upload template + + { + onNavigate("/starter-templates"); + }} + > + + Choose a starter template + + + + ); +}; diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 98a0b6152895e..9b71a3ca3e15b 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -6,7 +6,6 @@ import TableCell from "@mui/material/TableCell"; import TableContainer from "@mui/material/TableContainer"; import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; -import AddIcon from "@mui/icons-material/AddOutlined"; import { type FC } from "react"; import { useNavigate } from "react-router-dom"; import { createDayString } from "utils/createDayString"; @@ -45,15 +44,7 @@ import { docs } from "utils/docs"; import Skeleton from "@mui/material/Skeleton"; import { AvatarDataSkeleton } from "components/AvatarData/AvatarDataSkeleton"; import { DeprecatedBadge } from "components/Badges/Badges"; -import { - MoreMenu, - MoreMenuContent, - MoreMenuItem, - MoreMenuTrigger, -} from "components/MoreMenu/MoreMenu"; -import NoteAddOutlined from "@mui/icons-material/NoteAddOutlined"; -import UploadOutlined from "@mui/icons-material/UploadOutlined"; -import Inventory2 from "@mui/icons-material/Inventory2"; +import { CreateTemplateButton } from "./CreateTemplateButton"; export const Language = { developerCount: (activeCount: number): string => { @@ -180,41 +171,7 @@ export const TemplatesPageView: FC = ({ - - - - - { - navigate(`/templates/new?exampleId=scratch`); - }} - > - - From scratch - - { - navigate("/templates/new"); - }} - > - - Upload template - - { - navigate("/starter-templates"); - }} - > - - Choose a starter template - - - - ) + canCreateTemplates && } > From 060951119a5ca3f23b3b31e587cd519b318fb745 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 12:40:56 +0000 Subject: [PATCH 05/14] Test if scratch template is not displayed --- .../StarterTemplatesPage.test.tsx | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 site/src/pages/StarterTemplatesPage/StarterTemplatesPage.test.tsx diff --git a/site/src/pages/StarterTemplatesPage/StarterTemplatesPage.test.tsx b/site/src/pages/StarterTemplatesPage/StarterTemplatesPage.test.tsx new file mode 100644 index 0000000000000..a1f25f937a0b1 --- /dev/null +++ b/site/src/pages/StarterTemplatesPage/StarterTemplatesPage.test.tsx @@ -0,0 +1,59 @@ +import { render, screen } from "@testing-library/react"; +import StarterTemplatesPage from "./StarterTemplatesPage"; +import { AppProviders } from "App"; +import { RouterProvider, createMemoryRouter } from "react-router-dom"; +import { RequireAuth } from "contexts/auth/RequireAuth"; +import { rest } from "msw"; +import { + MockTemplateExample, + MockTemplateExample2, +} from "testHelpers/entities"; +import { server } from "testHelpers/server"; + +test("does not display the scratch template", async () => { + server.use( + rest.get( + "api/v2/organizations/:organizationId/templates/examples", + (req, res, ctx) => { + return res( + ctx.status(200), + ctx.json([ + MockTemplateExample, + MockTemplateExample2, + { + ...MockTemplateExample, + id: "scratch", + name: "Scratch", + description: "Create a template from scratch", + }, + ]), + ); + }, + ), + ); + + render( + + , + children: [ + { + path: "/starter-templates", + element: , + }, + ], + }, + ], + { initialEntries: ["/starter-templates"] }, + )} + /> + , + ); + + await screen.findByText(MockTemplateExample.name); + screen.getByText(MockTemplateExample2.name); + expect(screen.queryByText("Scratch")).not.toBeInTheDocument(); +}); From f8a6efc4ee1034de579371ba22122b28b7a64858 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 12:50:35 +0000 Subject: [PATCH 06/14] Add test for scratch flow --- .../TemplatesPage/TemplatesPage.test.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 site/src/pages/TemplatesPage/TemplatesPage.test.tsx diff --git a/site/src/pages/TemplatesPage/TemplatesPage.test.tsx b/site/src/pages/TemplatesPage/TemplatesPage.test.tsx new file mode 100644 index 0000000000000..b91c4aa96e1bd --- /dev/null +++ b/site/src/pages/TemplatesPage/TemplatesPage.test.tsx @@ -0,0 +1,42 @@ +import { render, screen } from "@testing-library/react"; +import { AppProviders } from "App"; +import { RequireAuth } from "contexts/auth/RequireAuth"; +import { RouterProvider, createMemoryRouter } from "react-router-dom"; +import TemplatesPage from "./TemplatesPage"; +import userEvent from "@testing-library/user-event"; + +test("create template from scratch", async () => { + const user = userEvent.setup(); + const router = createMemoryRouter( + [ + { + element: , + children: [ + { + path: "/templates", + element: , + }, + { + path: "/templates/new", + element:
, + }, + ], + }, + ], + { initialEntries: ["/templates"] }, + ); + render( + + + , + ); + const createTemplateButton = await screen.findByRole("button", { + name: "Create Template", + }); + await user.click(createTemplateButton); + const fromScratchMenuItem = await screen.findByText("From scratch"); + await user.click(fromScratchMenuItem); + await screen.findByTestId("new-template-page"); + expect(router.state.location.pathname).toBe("/templates/new"); + expect(router.state.location.search).toBe("?exampleId=scratch"); +}); From 9ee211232536fde5ea3ba79ec9abbabe727b41a8 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 13:08:19 +0000 Subject: [PATCH 07/14] Fix typo --- examples/templates/scratch/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/templates/scratch/main.tf b/examples/templates/scratch/main.tf index c3f209a38b35a..b6f7332e24873 100644 --- a/examples/templates/scratch/main.tf +++ b/examples/templates/scratch/main.tf @@ -45,7 +45,7 @@ resource "coder_env" "my_env" { } # Adds code-server -# See all available modules at https://regsitry.coder.com +# See all available modules at https://registry.coder.com module "code-server" { source = "registry.coder.com/modules/code-server/coder" version = "1.0.2" From 6ff64f447b7bb5b906c747a343612985f2e0db36 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 13:17:21 +0000 Subject: [PATCH 08/14] Update golden files --- cli/testdata/coder_templates_init_--help.golden | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/testdata/coder_templates_init_--help.golden b/cli/testdata/coder_templates_init_--help.golden index 9f7289407caf2..5a1d4ffd947bf 100644 --- a/cli/testdata/coder_templates_init_--help.golden +++ b/cli/testdata/coder_templates_init_--help.golden @@ -6,7 +6,7 @@ USAGE: Get started with a templated template. OPTIONS: - --id aws-devcontainer|aws-linux|aws-windows|azure-linux|do-linux|docker|gcp-devcontainer|gcp-linux|gcp-vm-container|gcp-windows|kubernetes|nomad-docker + --id aws-devcontainer|aws-linux|aws-windows|azure-linux|do-linux|docker|gcp-devcontainer|gcp-linux|gcp-vm-container|gcp-windows|kubernetes|nomad-docker|scratch Specify a given example template by ID. ——— From d9581d0d7beef239b4351018e06b19f94d2964e3 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 13:27:01 +0000 Subject: [PATCH 09/14] Fix tests --- site/src/pages/CreateTemplatePage/CreateTemplatePage.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/pages/CreateTemplatePage/CreateTemplatePage.test.tsx b/site/src/pages/CreateTemplatePage/CreateTemplatePage.test.tsx index 8891e376b2d19..9301701365ec0 100644 --- a/site/src/pages/CreateTemplatePage/CreateTemplatePage.test.tsx +++ b/site/src/pages/CreateTemplatePage/CreateTemplatePage.test.tsx @@ -88,7 +88,7 @@ test("Create template from starter template", async () => { ); await waitFor(() => expect(API.createTemplate).toBeCalledTimes(1)); expect(router.state.location.pathname).toEqual( - `/templates/${MockTemplate.name}`, + `/templates/${MockTemplate.name}/files`, ); expect(API.createTemplateVersion).toHaveBeenCalledWith(MockOrganization.id, { example_id: "aws-windows", @@ -138,7 +138,7 @@ test("Create template from duplicating a template", async () => { ); await waitFor(() => { expect(router.state.location.pathname).toEqual( - `/templates/${MockTemplate.name}`, + `/templates/${MockTemplate.name}/files`, ); }); }); From 7c2474469ed98d4285078bb44af2cc4960049e0e Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 13:55:15 +0000 Subject: [PATCH 10/14] Fix e2e tests --- site/e2e/helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index ff3e7206df9e9..549367d87efef 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -134,7 +134,7 @@ export const createTemplate = async ( const name = randomName(); await page.getByLabel("Name *").fill(name); await page.getByTestId("form-submit").click(); - await expect(page).toHaveURL("/templates/" + name, { + await expect(page).toHaveURL(`/templates/${name}/files`, { timeout: 30000, }); return name; From 914a7246f42c9bbde86f037484e5164eb9b8fd15 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Fri, 9 Feb 2024 11:11:38 -0300 Subject: [PATCH 11/14] Apply suggestions from code review Co-authored-by: Mathias Fredriksson --- examples/templates/scratch/README.md | 2 +- examples/templates/scratch/main.tf | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/templates/scratch/README.md b/examples/templates/scratch/README.md index 5752c22cf949c..85b8eab2bb8de 100644 --- a/examples/templates/scratch/README.md +++ b/examples/templates/scratch/README.md @@ -1,6 +1,6 @@ --- display_name: Scratch -description: A minimal Scaffolding for a Coder Template +description: A minimal starter template for Coder icon: ../../../site/static/emojis/1f4e6.png maintainer_github: coder verified: true diff --git a/examples/templates/scratch/main.tf b/examples/templates/scratch/main.tf index b6f7332e24873..19153cb4322d0 100644 --- a/examples/templates/scratch/main.tf +++ b/examples/templates/scratch/main.tf @@ -13,7 +13,6 @@ data "coder_workspace" "me" {} resource "coder_agent" "main" { arch = data.coder_provisioner.me.arch os = data.coder_provisioner.me.os - startup_script_timeout = 180 startup_script = <<-EOT set -e # Run programs at workspace startup @@ -38,11 +37,10 @@ resource "coder_agent" "main" { # Use this to set environment variables in your workspace # details: https://registry.terraform.io/providers/coder/coder/latest/docs/resources/env -resource "coder_env" "my_env" { +resource "coder_env" "welcome_message" { agent_id = coder_agent.main.id - name = "FOO" - value = "bar" -} + name = "WELCOME_MESSAGE" + value = "Welcome to your Coder workspace!" # Adds code-server # See all available modules at https://registry.coder.com From 63bd718970b0d627d64a020488f731d2486964cc Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 14:18:11 +0000 Subject: [PATCH 12/14] Fix format --- examples/templates/scratch/main.tf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/templates/scratch/main.tf b/examples/templates/scratch/main.tf index 19153cb4322d0..3ec15a22a9f56 100644 --- a/examples/templates/scratch/main.tf +++ b/examples/templates/scratch/main.tf @@ -11,9 +11,9 @@ data "coder_provisioner" "me" {} data "coder_workspace" "me" {} resource "coder_agent" "main" { - arch = data.coder_provisioner.me.arch - os = data.coder_provisioner.me.os - startup_script = <<-EOT + arch = data.coder_provisioner.me.arch + os = data.coder_provisioner.me.os + startup_script = <<-EOT set -e # Run programs at workspace startup EOT @@ -41,6 +41,7 @@ resource "coder_env" "welcome_message" { agent_id = coder_agent.main.id name = "WELCOME_MESSAGE" value = "Welcome to your Coder workspace!" +} # Adds code-server # See all available modules at https://registry.coder.com From 8389b337ac33796dd76dc4803438f9f031d58c33 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 14:23:10 +0000 Subject: [PATCH 13/14] Only uses coder_script to def scripts --- examples/templates/scratch/main.tf | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/examples/templates/scratch/main.tf b/examples/templates/scratch/main.tf index 3ec15a22a9f56..35a7c69d6b26d 100644 --- a/examples/templates/scratch/main.tf +++ b/examples/templates/scratch/main.tf @@ -11,12 +11,8 @@ data "coder_provisioner" "me" {} data "coder_workspace" "me" {} resource "coder_agent" "main" { - arch = data.coder_provisioner.me.arch - os = data.coder_provisioner.me.os - startup_script = <<-EOT - set -e - # Run programs at workspace startup - EOT + arch = data.coder_provisioner.me.arch + os = data.coder_provisioner.me.os metadata { display_name = "CPU Usage" @@ -53,11 +49,14 @@ module "code-server" { # Runs a script at workspace start/stop or on a cron schedule # details: https://registry.terraform.io/providers/coder/coder/latest/docs/resources/script -resource "coder_script" "my_script" { - agent_id = coder_agent.main.id - display_name = "My Script" - run_on_start = true - script = <<-EOF - echo "Hello ${data.coder_workspace.me.owner}!" +resource "coder_script" "startup_script" { + agent_id = coder_agent.main.id + display_name = "Startup Script" + script = <<-EOF + #!/bin/sh + set -e + # Run programs at workspace startup EOF + run_on_start = true + start_blocks_login = true } From 66c8e7893be4c2c9687d9906e65025d04bf35886 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 9 Feb 2024 14:29:16 +0000 Subject: [PATCH 14/14] Fix gen files --- examples/examples.gen.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/examples.gen.json b/examples/examples.gen.json index f8f80b1e6f5ad..0999521386030 100644 --- a/examples/examples.gen.json +++ b/examples/examples.gen.json @@ -161,7 +161,7 @@ "id": "scratch", "url": "", "name": "Scratch", - "description": "A minimal Scaffolding for a Coder Template", + "description": "A minimal starter template for Coder", "icon": "/emojis/1f4e6.png", "tags": [], "markdown": "\n# A minimal Scaffolding for a Coder Template\n\nUse this starter template as a basis to create your own unique template from scratch.\n"