From cf632d55d0c4bf09da881ff28d89ff72e70962b3 Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Mon, 1 Aug 2022 20:08:14 +0000 Subject: [PATCH 1/3] fix: handle create workspace errors --- coderd/workspaces.go | 2 +- .../CreateWorkspacePage.tsx | 25 ++++++++-- .../CreateWorkspacePageView.stories.tsx | 50 ++++++++++++++++++- .../CreateWorkspacePageView.tsx | 42 ++++++++++++++-- .../createWorkspaceXService.ts | 29 ++++++++++- 5 files changed, 136 insertions(+), 12 deletions(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 8101772232e1e..fd696d5f0edb1 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -329,7 +329,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req Message: fmt.Sprintf("Workspace %q already exists in the %q template.", createWorkspace.Name, template.Name), Validations: []codersdk.ValidationError{{ Field: "name", - Detail: "this value is already in use and should be unique", + Detail: "This value is already in use and should be unique.", }}, }) return diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index d534c0bbc9f26..2359ccb42a4e1 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -5,7 +5,7 @@ import { useNavigate, useParams } from "react-router-dom" import { useOrganizationId } from "../../hooks/useOrganizationId" import { pageTitle } from "../../util/page" import { createWorkspaceMachine } from "../../xServices/createWorkspace/createWorkspaceXService" -import { CreateWorkspacePageView } from "./CreateWorkspacePageView" +import { CreateWorkspaceErrors, CreateWorkspacePageView } from "./CreateWorkspacePageView" const CreateWorkspacePage: FC = () => { const organizationId = useOrganizationId() @@ -21,6 +21,15 @@ const CreateWorkspacePage: FC = () => { }, }) + const { + templates, + templateSchema, + selectedTemplate, + getTemplateSchemaError, + getTemplatesError, + createWorkspaceError, + } = createWorkspaceState.context + return ( <> @@ -30,10 +39,16 @@ const CreateWorkspacePage: FC = () => { loadingTemplates={createWorkspaceState.matches("gettingTemplates")} loadingTemplateSchema={createWorkspaceState.matches("gettingTemplateSchema")} creatingWorkspace={createWorkspaceState.matches("creatingWorkspace")} - templateName={createWorkspaceState.context.templateName} - templates={createWorkspaceState.context.templates} - selectedTemplate={createWorkspaceState.context.selectedTemplate} - templateSchema={createWorkspaceState.context.templateSchema} + hasTemplateErrors={createWorkspaceState.matches("error")} + templateName={templateName} + templates={templates} + selectedTemplate={selectedTemplate} + templateSchema={templateSchema} + createWorkspaceErrors={{ + [CreateWorkspaceErrors.GET_TEMPLATES_ERROR]: getTemplatesError, + [CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR]: getTemplateSchemaError, + [CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR]: createWorkspaceError, + }} onCancel={() => { navigate("/templates") }} diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index 926e0d61f286d..61b689029d403 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -1,7 +1,11 @@ import { ComponentMeta, Story } from "@storybook/react" import { ParameterSchema } from "../../api/typesGenerated" -import { MockTemplate } from "../../testHelpers/entities" -import { CreateWorkspacePageView, CreateWorkspacePageViewProps } from "./CreateWorkspacePageView" +import { makeMockApiError, MockTemplate } from "../../testHelpers/entities" +import { + CreateWorkspaceErrors, + CreateWorkspacePageView, + CreateWorkspacePageViewProps, +} from "./CreateWorkspacePageView" const createParameterSchema = (partial: Partial): ParameterSchema => { return { @@ -40,6 +44,7 @@ NoParameters.args = { templates: [MockTemplate], selectedTemplate: MockTemplate, templateSchema: [], + createWorkspaceErrors: {}, } export const Parameters = Template.bind({}) @@ -60,4 +65,45 @@ Parameters.args = { validation_contains: ["Small", "Medium", "Big"], }), ], + createWorkspaceErrors: {}, +} + +export const GetTemplatesError = Template.bind({}) +GetTemplatesError.args = { + ...Parameters.args, + createWorkspaceErrors: { + [CreateWorkspaceErrors.GET_TEMPLATES_ERROR]: makeMockApiError({ + message: "Failed to fetch templates.", + detail: "You do not have permission to access this resource.", + }), + }, + hasTemplateErrors: true, +} + +export const GetTemplateSchemaError = Template.bind({}) +GetTemplateSchemaError.args = { + ...Parameters.args, + createWorkspaceErrors: { + [CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR]: makeMockApiError({ + message: 'Failed to fetch template schema for "docker-amd64".', + detail: "You do not have permission to access this resource.", + }), + }, + hasTemplateErrors: true, +} + +export const CreateWorkspaceError = Template.bind({}) +CreateWorkspaceError.args = { + ...Parameters.args, + createWorkspaceErrors: { + [CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR]: makeMockApiError({ + message: 'Workspace "test" already exists in the "docker-amd64" template.', + validations: [ + { + field: "name", + detail: "This value is already in use and should be unique.", + }, + ], + }), + }, } diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 1b4e27d3b08e5..9fdb53ba117f3 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -1,5 +1,6 @@ import { makeStyles } from "@material-ui/core/styles" import TextField from "@material-ui/core/TextField" +import { ErrorSummary } from "components/ErrorSummary/ErrorSummary" import { FormikContextType, useFormik } from "formik" import { FC, useState } from "react" import * as Yup from "yup" @@ -9,21 +10,29 @@ import { FullPageForm } from "../../components/FullPageForm/FullPageForm" import { Loader } from "../../components/Loader/Loader" import { ParameterInput } from "../../components/ParameterInput/ParameterInput" import { Stack } from "../../components/Stack/Stack" -import { getFormHelpers, nameValidator, onChangeTrimmed } from "../../util/formUtils" +import { getFormHelpersWithError, nameValidator, onChangeTrimmed } from "../../util/formUtils" export const Language = { templateLabel: "Template", nameLabel: "Name", } +export enum CreateWorkspaceErrors { + GET_TEMPLATES_ERROR = "getTemplatesError", + GET_TEMPLATE_SCHEMA_ERROR = "getTemplateSchemaError", + CREATE_WORKSPACE_ERROR = "createWorkspaceError", +} + export interface CreateWorkspacePageViewProps { loadingTemplates: boolean loadingTemplateSchema: boolean creatingWorkspace: boolean + hasTemplateErrors: boolean templateName: string templates?: TypesGen.Template[] selectedTemplate?: TypesGen.Template templateSchema?: TypesGen.ParameterSchema[] + createWorkspaceErrors: Partial> onCancel: () => void onSubmit: (req: TypesGen.CreateWorkspaceRequest) => void } @@ -62,18 +71,45 @@ export const CreateWorkspacePageView: FC = (props) source_value: value, }) }) - return props.onSubmit({ + props.onSubmit({ ...request, parameter_values: createRequests, }) + form.setSubmitting(false) }, }) - const getFieldHelpers = getFormHelpers(form) + + const getFieldHelpers = getFormHelpersWithError( + form, + props.createWorkspaceErrors[CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR], + ) + + if (props.hasTemplateErrors) { + return ( + + {props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATES_ERROR] && ( + + )} + {props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR] && ( + + )} + + ) + } return (
+ {props.createWorkspaceErrors[CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR] && ( + + )} event.request, }), + assignCreateWorkspaceError: assign({ + createWorkspaceError: (_, event) => event.data, + }), + clearCreateWorkspaceError: assign({ + createWorkspaceError: (_) => undefined, + }), + assignGetTemplatesError: assign({ + getTemplatesError: (_, event) => event.data, + }), + clearGetTemplatesError: assign({ + getTemplatesError: (_) => undefined, + }), + assignGetTemplateSchemaError: assign({ + getTemplateSchemaError: (_, event) => event.data, + }), + clearGetTemplateSchemaError: assign({ + getTemplateSchemaError: (_) => undefined, + }), }, }, ) From ce2b2f3210575502608279d747dc8cc77c45b59d Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Mon, 1 Aug 2022 20:26:28 +0000 Subject: [PATCH 2/3] fix story with form error --- .../CreateWorkspacePage/CreateWorkspacePageView.stories.tsx | 3 +++ .../pages/CreateWorkspacePage/CreateWorkspacePageView.tsx | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index 61b689029d403..0554389fd3924 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -106,4 +106,7 @@ CreateWorkspaceError.args = { ], }), }, + initialTouched: { + name: true, + }, } diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 9fdb53ba117f3..564891ccae025 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -1,7 +1,7 @@ import { makeStyles } from "@material-ui/core/styles" import TextField from "@material-ui/core/TextField" import { ErrorSummary } from "components/ErrorSummary/ErrorSummary" -import { FormikContextType, useFormik } from "formik" +import { FormikContextType, FormikTouched, useFormik } from "formik" import { FC, useState } from "react" import * as Yup from "yup" import * as TypesGen from "../../api/typesGenerated" @@ -35,6 +35,8 @@ export interface CreateWorkspacePageViewProps { createWorkspaceErrors: Partial> onCancel: () => void onSubmit: (req: TypesGen.CreateWorkspaceRequest) => void + // initialTouched is only used for testing the error state of the form. + initialTouched?: FormikTouched } export const validationSchema = Yup.object({ @@ -53,6 +55,7 @@ export const CreateWorkspacePageView: FC = (props) }, enableReinitialize: true, validationSchema, + initialTouched: props.initialTouched, onSubmit: (request) => { if (!props.templateSchema) { throw new Error("No template schema loaded") From 50ee56951852a46b3ae9da4296a6cd51d2a9eee3 Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Tue, 2 Aug 2022 05:53:55 +0000 Subject: [PATCH 3/3] fix: chromatic workflow filter --- .github/workflows/coder.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/coder.yaml b/.github/workflows/coder.yaml index ca09ef2629607..f25857fbb09bf 100644 --- a/.github/workflows/coder.yaml +++ b/.github/workflows/coder.yaml @@ -68,10 +68,7 @@ jobs: sh: - "**.sh" ts: - - "**.tsx?" - - "**.jsx?" - - "**.lock" - - "**.json" + - 'site/**' - id: debug run: | echo "${{ toJSON(steps.filter )}}" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy