From c9363191144a99d5998be5f6993c1ea32ccede58 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 15 Feb 2024 22:03:08 +0000 Subject: [PATCH 1/7] Revert "refactor(site): verify external auth before display ws form (#11777)" This reverts commit 6145da8a9e064abc21000cafe44318ce8090a8e7. --- .../CreateWorkspacePage.test.tsx | 103 ++++++---- .../CreateWorkspacePageView.stories.tsx | 2 +- .../CreateWorkspacePageView.tsx | 192 +++++++++++------- .../ExternalAuthBanner.stories.tsx | 34 ---- .../ExternalAuthBanner/ExternalAuthBanner.tsx | 91 --------- .../ExternalAuthItem.stories.tsx | 50 ----- .../ExternalAuthItem.test.tsx | 62 ------ .../ExternalAuthBanner/ExternalAuthItem.tsx | 124 ----------- .../ExternalAuthButton.stories.tsx | 108 ++++++++++ .../ExternalAuthButton.tsx | 74 +++++++ 10 files changed, 358 insertions(+), 482 deletions(-) delete mode 100644 site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.stories.tsx delete mode 100644 site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.tsx delete mode 100644 site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.stories.tsx delete mode 100644 site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.test.tsx delete mode 100644 site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.tsx create mode 100644 site/src/pages/CreateWorkspacePage/ExternalAuthButton.stories.tsx create mode 100644 site/src/pages/CreateWorkspacePage/ExternalAuthButton.tsx diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx index d301e21bbe839..ab4159a86ce5a 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx @@ -6,12 +6,14 @@ import { MockUser, MockWorkspace, MockWorkspaceQuota, + MockWorkspaceRequest, MockWorkspaceRichParametersRequest, MockTemplateVersionParameter1, MockTemplateVersionParameter2, MockTemplateVersionParameter3, MockTemplateVersionExternalAuthGithub, MockOrganization, + MockTemplateVersionExternalAuthGithubAuthenticated, } from "testHelpers/entities"; import { renderWithAuth, @@ -19,8 +21,6 @@ import { } from "testHelpers/renderHelpers"; import CreateWorkspacePage from "./CreateWorkspacePage"; import { Language } from "./CreateWorkspacePageView"; -import { server } from "testHelpers/server"; -import { rest } from "msw"; const nameLabelText = "Workspace Name"; const createWorkspaceText = "Create Workspace"; @@ -157,6 +157,63 @@ describe("CreateWorkspacePage", () => { expect(validationError).toBeInTheDocument(); }); + it("external auth authenticates and succeeds", async () => { + jest + .spyOn(API, "getWorkspaceQuota") + .mockResolvedValueOnce(MockWorkspaceQuota); + jest + .spyOn(API, "getUsers") + .mockResolvedValueOnce({ users: [MockUser], count: 1 }); + jest.spyOn(API, "createWorkspace").mockResolvedValueOnce(MockWorkspace); + jest + .spyOn(API, "getTemplateVersionExternalAuth") + .mockResolvedValue([MockTemplateVersionExternalAuthGithub]); + + renderCreateWorkspacePage(); + await waitForLoaderToBeRemoved(); + + const nameField = await screen.findByLabelText(nameLabelText); + // have to use fireEvent b/c userEvent isn't cleaning up properly between tests + fireEvent.change(nameField, { + target: { value: "test" }, + }); + + const githubButton = await screen.findByText("Login with GitHub"); + await userEvent.click(githubButton); + + jest + .spyOn(API, "getTemplateVersionExternalAuth") + .mockResolvedValue([MockTemplateVersionExternalAuthGithubAuthenticated]); + + await screen.findByText("Authenticated with GitHub"); + + const submitButton = screen.getByText(createWorkspaceText); + await userEvent.click(submitButton); + + await waitFor(() => + expect(API.createWorkspace).toBeCalledWith( + MockUser.organization_ids[0], + MockUser.id, + expect.objectContaining({ + ...MockWorkspaceRequest, + }), + ), + ); + }); + + it("external auth: errors if unauthenticated", async () => { + jest + .spyOn(API, "getTemplateVersionExternalAuth") + .mockResolvedValueOnce([MockTemplateVersionExternalAuthGithub]); + + renderCreateWorkspacePage(); + await waitForLoaderToBeRemoved(); + + await screen.findByText( + "To create a workspace using the selected template, please ensure you are authenticated with all the external providers listed below.", + ); + }); + it("auto create a workspace if uses mode=auto", async () => { const param = "first_parameter"; const paramValue = "It works!"; @@ -231,46 +288,4 @@ describe("CreateWorkspacePage", () => { expect(warningMessage).toHaveTextContent(Language.duplicationWarning); expect(nameInput).toHaveValue(`${MockWorkspace.name}-copy`); }); - - it("displays the form after connecting to all the external services", async () => { - jest.spyOn(window, "open").mockImplementation(() => null); - const user = userEvent.setup(); - const notAuthenticatedExternalAuth = { - ...MockTemplateVersionExternalAuthGithub, - authenticated: false, - }; - server.use( - rest.get( - "/api/v2/templateversions/:versionId/external-auth", - (req, res, ctx) => { - return res(ctx.json([notAuthenticatedExternalAuth])); - }, - ), - ); - renderCreateWorkspacePage(); - - await screen.findByText("External authentication"); - expect(screen.queryByRole("form")).not.toBeInTheDocument(); - - const connectButton = screen.getByRole("button", { - name: /connect/i, - }); - server.use( - rest.get( - "/api/v2/templateversions/:versionId/external-auth", - (req, res, ctx) => { - const authenticatedExternalAuth = { - ...MockTemplateVersionExternalAuthGithub, - authenticated: true, - }; - return res(ctx.json([authenticatedExternalAuth])); - }, - ), - ); - await user.click(connectButton); - // TODO: Consider improving the timeout by simulating react-query polling. - // Current implementation could not achieve this, further research is - // needed. - await screen.findByRole("form", undefined, { timeout: 10_000 }); - }); }); diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index 5662f96338ef6..5e24527f46541 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -108,7 +108,7 @@ export const Parameters: Story = { }, }; -export const RequiresExternalAuth: Story = { +export const ExternalAuth: Story = { args: { externalAuth: [ { diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 1d2cdcf660a4f..5aa06425c2cbb 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -25,6 +25,11 @@ import { getInitialRichParameterValues, useValidationSchemaForRichParameters, } from "utils/richParameters"; +import { + ImmutableTemplateParametersSection, + MutableTemplateParametersSection, +} from "components/TemplateParameters/TemplateParameters"; +import { ExternalAuthButton } from "./ExternalAuthButton"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Stack } from "components/Stack/Stack"; import { Alert } from "components/Alert/Alert"; @@ -171,48 +176,74 @@ export const CreateWorkspacePageView: FC = ({ - {requiresExternalAuth ? ( - - ) : ( - + {Boolean(error) && } + + {mode === "duplicate" && ( + + {Language.duplicationWarning} + + )} + + {/* General info */} + - {Boolean(error) && } + + {versionId && versionId !== template.active_version_id && ( + + + + This parameter has been preset, and cannot be modified. + + + )} - {mode === "duplicate" && ( - - {Language.duplicationWarning} - - )} + - {/* General info */} + {permissions.createWorkspaceForUser && ( + { + setOwner(user ?? defaultOwner); + }} + label="Owner" + size="medium" + /> + )} + + + + {externalAuth && externalAuth.length > 0 && ( - {versionId && versionId !== template.active_version_id && ( - - - - This parameter has been preset, and cannot be modified. - - + {requiresExternalAuth && ( + + To create a workspace using the selected template, please + ensure you are authenticated with all the external providers + listed below. + )}
= ({ size="medium" /> )} + {externalAuth.map((auth) => ( + + ))} + )} - {parameters.length > 0 && ( - - {/* + {parameters.length > 0 && ( + + {/* Opted not to use FormFields in order to increase spacing. This decision was made because rich parameter inputs are more visually dense than standard text fields. */} -
- {parameters.map((parameter, index) => { - const parameterField = `rich_parameter_values.${index}`; - const parameterInputName = `${parameterField}.value`; - const isDisabled = - disabledParamsList?.includes( - parameter.name.toLowerCase().replace(/ /g, "_"), - ) || creatingWorkspace; +
+ {parameters.map((parameter, index) => { + const parameterField = `rich_parameter_values.${index}`; + const parameterInputName = `${parameterField}.value`; + const isDisabled = + disabledParamsList?.includes( + parameter.name.toLowerCase().replace(/ /g, "_"), + ) || creatingWorkspace; - return ( - { - await form.setFieldValue(parameterField, { - name: parameter.name, - value, - }); - }} - autofillSource={autofillSources[parameter.name]} - key={parameter.name} - parameter={parameter} - disabled={isDisabled} - /> - ); - })} -
- - )} + return ( + { + await form.setFieldValue(parameterField, { + name: parameter.name, + value, + }); + }} + autofillSource={autofillSources[parameter.name]} + key={parameter.name} + parameter={parameter} + disabled={isDisabled} + /> + ); + })} +
+
+ )} - - - )} + + ); }; diff --git a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.stories.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.stories.tsx deleted file mode 100644 index 2d9c4e9c45359..0000000000000 --- a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.stories.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { TemplateVersionExternalAuth } from "api/typesGenerated"; -import { ExternalAuthBanner } from "./ExternalAuthBanner"; -import type { Meta, StoryObj } from "@storybook/react"; - -const MockExternalAuth: TemplateVersionExternalAuth = { - id: "", - type: "", - display_name: "GitHub", - display_icon: "/icon/github.svg", - authenticate_url: "", - authenticated: false, -}; - -const meta: Meta = { - title: "pages/CreateWorkspacePage/ExternalAuthBanner", - component: ExternalAuthBanner, -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = { - args: { - providers: [ - MockExternalAuth, - { - ...MockExternalAuth, - display_name: "Google", - display_icon: "/icon/google.svg", - authenticated: true, - }, - ], - }, -}; diff --git a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.tsx deleted file mode 100644 index ee8e4b47f546d..0000000000000 --- a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Interpolation, Theme } from "@emotion/react"; -import { TemplateVersionExternalAuth } from "api/typesGenerated"; -import { ExternalAuthPollingState } from "../CreateWorkspacePage"; -import { ExternalAuthItem } from "./ExternalAuthItem"; -import { FC } from "react"; - -type ExternalAuthBannerProps = { - providers: TemplateVersionExternalAuth[]; - pollingState: ExternalAuthPollingState; - onStartPolling: () => void; -}; - -export const ExternalAuthBanner: FC = ({ - providers, - pollingState, - onStartPolling, -}) => { - return ( -
-
-
-

External authentication

-

- To create a workspace using the selected template, please ensure you - are connected with all the external services. -

-
- -
    - {providers.map((p) => ( - - ))} -
-
-
- ); -}; - -const styles = { - root: (theme) => ({ - display: "flex", - alignItems: "center", - justifyContent: "center", - padding: 48, - minHeight: 460, - border: `1px solid ${theme.palette.divider}`, - borderRadius: 8, - lineHeight: "1.5", - }), - - header: { - textAlign: "center", - // Better text distribution - maxWidth: 324, - margin: "auto", - }, - - content: { - maxWidth: 380, - }, - - title: { - fontSize: 20, - fontWeight: 400, - margin: 0, - lineHeight: "1.2", - }, - - description: (theme) => ({ - margin: 0, - marginTop: 12, - fontSize: 14, - color: theme.palette.text.secondary, - }), - - providerList: { - listStyle: "none", - padding: 0, - margin: 0, - display: "flex", - flexDirection: "column", - gap: 8, - marginTop: 24, - }, -} as Record>; diff --git a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.stories.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.stories.tsx deleted file mode 100644 index a60b3e317c19e..0000000000000 --- a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.stories.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { TemplateVersionExternalAuth } from "api/typesGenerated"; -import { ExternalAuthItem } from "./ExternalAuthItem"; -import type { Meta, StoryObj } from "@storybook/react"; - -const MockExternalAuth: TemplateVersionExternalAuth = { - id: "", - type: "", - display_name: "GitHub", - display_icon: "/icon/github.svg", - authenticate_url: "", - authenticated: false, -}; - -const meta: Meta = { - title: "pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem", - component: ExternalAuthItem, - decorators: [ - (Story) => ( -
- -
- ), - ], -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = { - args: { - provider: MockExternalAuth, - }, -}; - -export const Connected: Story = { - args: { - provider: { - ...MockExternalAuth, - authenticated: true, - }, - }, -}; - -export const Connecting: Story = { - args: { - provider: MockExternalAuth, - defaultStatus: "connecting", - isPolling: true, - }, -}; diff --git a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.test.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.test.tsx deleted file mode 100644 index f0d0871b9f7e3..0000000000000 --- a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.test.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import { ExternalAuthItem } from "./ExternalAuthItem"; -import { ThemeProvider } from "contexts/ThemeProvider"; -import { TemplateVersionExternalAuth } from "api/typesGenerated"; -import userEvent from "@testing-library/user-event"; - -jest.spyOn(window, "open").mockImplementation(() => null); - -const MockExternalAuth: TemplateVersionExternalAuth = { - id: "", - type: "", - display_name: "GitHub", - display_icon: "/icon/github.svg", - authenticate_url: "", - authenticated: false, -}; - -test("changes to idle when polling stops", async () => { - const user = userEvent.setup(); - const startPollingFn = jest.fn(); - const { rerender } = render( - , - { wrapper: ThemeProvider }, - ); - - const connectButton = screen.getByText(/connect/i); - expect(isLoading(connectButton)).toBeFalsy(); - - await user.click(connectButton); - expect(startPollingFn).toHaveBeenCalledTimes(1); - expect(window.open).toHaveBeenCalledTimes(1); - - rerender( - , - ); - - // Check if the button is loading - screen.getByRole("progressbar"); - - rerender( - , - ); - - expect(isLoading(connectButton)).toBeFalsy(); -}); - -function isLoading(el: HTMLButtonElement) { - const progressBar = el.querySelector('[role="progressbar"]'); - return Boolean(progressBar); -} diff --git a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.tsx deleted file mode 100644 index 45d5e6057875e..0000000000000 --- a/site/src/pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthItem.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { Interpolation, Theme } from "@emotion/react"; -import DoneAllOutlined from "@mui/icons-material/DoneAllOutlined"; -import LoadingButton from "@mui/lab/LoadingButton"; -import { TemplateVersionExternalAuth } from "api/typesGenerated"; -import { ExternalImage } from "components/ExternalImage/ExternalImage"; -import { FC, useEffect, useState } from "react"; -// eslint-disable-next-line no-restricted-imports -- used to allow extension with "component" -import Box, { BoxProps } from "@mui/material/Box"; - -type Status = "idle" | "connecting"; - -type ExternalAuthItemProps = { - provider: TemplateVersionExternalAuth; - isPolling: boolean; - defaultStatus?: Status; - onStartPolling: () => void; -} & BoxProps; - -export const ExternalAuthItem: FC = ({ - provider, - isPolling, - defaultStatus = "idle", - onStartPolling, - ...boxProps -}) => { - const [status, setStatus] = useState(defaultStatus); - - useEffect(() => { - if (!isPolling) { - setStatus("idle"); - } - }, [isPolling]); - - return ( - - - - {provider.display_name} - - {provider.authenticated ? ( - - Connected - - - ) : ( - { - setStatus("connecting"); - window.open( - provider.authenticate_url, - "_blank", - "width=900,height=600", - ); - onStartPolling(); - }} - > - Connect… - - )} - - ); -}; - -const styles = { - providerItem: (theme) => ({ - display: "flex", - alignItems: "center", - padding: "8px 8px 8px 20px", - border: `1px solid ${theme.palette.divider}`, - borderRadius: 6, - justifyContent: "space-between", - gap: 24, - fontSize: 14, - }), - - providerHeader: { - display: "flex", - alignItems: "center", - gap: 12, - flex: 1, - overflow: "hidden", - }, - - providerName: { - fontWeight: 500, - display: "block", - whiteSpace: "nowrap", - maxWidth: "100%", - textOverflow: "ellipsis", - overflow: "hidden", - }, - - providerIcon: { - width: 16, - height: 16, - }, - - connectButton: { - flexShrink: 0, - borderRadius: 4, - }, - - providerConnectedLabel: (theme) => ({ - fontSize: 13, - display: "flex", - alignItems: "center", - color: theme.palette.text.disabled, - gap: 8, - // Have the same height of the button - height: 32, - // Better visual alignment - padding: "0 8px", - }), - - providerConnectedLabelIcon: (theme) => ({ - color: theme.roles.success.fill.solid, - fontSize: 16, - }), -} as Record>; diff --git a/site/src/pages/CreateWorkspacePage/ExternalAuthButton.stories.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuthButton.stories.tsx new file mode 100644 index 0000000000000..97c9d743552ad --- /dev/null +++ b/site/src/pages/CreateWorkspacePage/ExternalAuthButton.stories.tsx @@ -0,0 +1,108 @@ +import { TemplateVersionExternalAuth } from "api/typesGenerated"; +import { ExternalAuthButton } from "./ExternalAuthButton"; +import type { Meta, StoryObj } from "@storybook/react"; + +const MockExternalAuth: TemplateVersionExternalAuth = { + id: "", + type: "", + display_name: "GitHub", + display_icon: "/icon/github.svg", + authenticate_url: "", + authenticated: false, +}; + +const meta: Meta = { + title: "pages/CreateWorkspacePage/ExternalAuth", + component: ExternalAuthButton, +}; + +export default meta; +type Story = StoryObj; + +export const Github: Story = { + args: { + auth: MockExternalAuth, + }, +}; + +export const GithubWithRetry: Story = { + args: { + auth: MockExternalAuth, + displayRetry: true, + }, +}; + +export const GithubAuthenticated: Story = { + args: { + auth: { + ...MockExternalAuth, + authenticated: true, + }, + }, +}; + +export const Gitlab: Story = { + args: { + auth: { + ...MockExternalAuth, + display_icon: "/icon/gitlab.svg", + display_name: "GitLab", + authenticated: false, + }, + }, +}; + +export const GitlabAuthenticated: Story = { + args: { + auth: { + ...MockExternalAuth, + display_icon: "/icon/gitlab.svg", + display_name: "GitLab", + authenticated: true, + }, + }, +}; + +export const AzureDevOps: Story = { + args: { + auth: { + ...MockExternalAuth, + display_icon: "/icon/azure-devops.svg", + display_name: "Azure DevOps", + authenticated: false, + }, + }, +}; + +export const AzureDevOpsAuthenticated: Story = { + args: { + auth: { + ...MockExternalAuth, + display_icon: "/icon/azure-devops.svg", + display_name: "Azure DevOps", + authenticated: true, + }, + }, +}; + +export const Bitbucket: Story = { + args: { + auth: { + ...MockExternalAuth, + display_icon: "/icon/bitbucket.svg", + display_name: "Bitbucket", + authenticated: false, + }, + }, +}; + +export const BitbucketAuthenticated: Story = { + args: { + auth: { + ...MockExternalAuth, + display_icon: "/icon/bitbucket.svg", + display_name: "Bitbucket", + authenticated: true, + }, + }, +}; diff --git a/site/src/pages/CreateWorkspacePage/ExternalAuthButton.tsx b/site/src/pages/CreateWorkspacePage/ExternalAuthButton.tsx new file mode 100644 index 0000000000000..3412a9aac0b3d --- /dev/null +++ b/site/src/pages/CreateWorkspacePage/ExternalAuthButton.tsx @@ -0,0 +1,74 @@ +import ReplayIcon from "@mui/icons-material/Replay"; +import Button from "@mui/material/Button"; +import Tooltip from "@mui/material/Tooltip"; +import { type FC } from "react"; +import LoadingButton from "@mui/lab/LoadingButton"; +import { visuallyHidden } from "@mui/utils"; +import { ExternalImage } from "components/ExternalImage/ExternalImage"; +import { TemplateVersionExternalAuth } from "api/typesGenerated"; + +export interface ExternalAuthButtonProps { + auth: TemplateVersionExternalAuth; + displayRetry: boolean; + isLoading: boolean; + onStartPolling: () => void; +} + +export const ExternalAuthButton: FC = ({ + auth, + displayRetry, + isLoading, + onStartPolling, +}) => { + return ( + <> +
+ + ) + } + disabled={auth.authenticated} + onClick={() => { + window.open( + auth.authenticate_url, + "_blank", + "width=900,height=600", + ); + onStartPolling(); + }} + > + {auth.authenticated + ? `Authenticated with ${auth.display_name}` + : `Login with ${auth.display_name}`} + + + {displayRetry && ( + + + + )} +
+ + ); +}; From 044e98fc2c038e824401eedb99837ca2134eb9c2 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 16 Feb 2024 17:43:24 +0000 Subject: [PATCH 2/7] whoops --- site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 5aa06425c2cbb..3a30c07c1c65b 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -47,7 +47,6 @@ import { CreateWorkspaceMode, ExternalAuthPollingState, } from "./CreateWorkspacePage"; -import { ExternalAuthBanner } from "./ExternalAuthBanner/ExternalAuthBanner"; import { CreateWSPermissions } from "./permissions"; export const Language = { From f599b8f50d4fd6e6b3552b12ffa7bbcf4757ae78 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 16 Feb 2024 17:54:57 +0000 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 3a30c07c1c65b..7d58604b10a1d 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -25,10 +25,6 @@ import { getInitialRichParameterValues, useValidationSchemaForRichParameters, } from "utils/richParameters"; -import { - ImmutableTemplateParametersSection, - MutableTemplateParametersSection, -} from "components/TemplateParameters/TemplateParameters"; import { ExternalAuthButton } from "./ExternalAuthButton"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Stack } from "components/Stack/Stack"; From bc6f96aa087f1a9923f98d92059c9914ea8c108d Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Tue, 20 Feb 2024 21:14:45 +0000 Subject: [PATCH 4/7] duplicate fields --- .../CreateWorkspacePageView.tsx | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index db8611ab29212..b9d10b88c4c24 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -240,40 +240,6 @@ export const CreateWorkspacePageView: FC = ({ listed below. )} -
- - - Need a suggestion?{" "} - - -
- - {permissions.createWorkspaceForUser && ( - { - setOwner(user ?? defaultOwner); - }} - label="Owner" - size="medium" - /> - )} {externalAuth.map((auth) => ( Date: Tue, 20 Feb 2024 21:42:24 +0000 Subject: [PATCH 5/7] fix merge stuff --- .../CreateWorkspacePageView.tsx | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index b9d10b88c4c24..4a0c9257d259b 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -171,7 +171,11 @@ export const CreateWorkspacePageView: FC = ({ - + {Boolean(error) && } {mode === "duplicate" && ( @@ -204,15 +208,30 @@ export const CreateWorkspacePageView: FC = ({ )} - +
+ + + Need a suggestion?{" "} + + +
{permissions.createWorkspaceForUser && ( = ({ > {requiresExternalAuth && ( - + // This should really be a `notice` but `severity` is a MUI prop, and we'd need + // to basically make our own `Alert` component. + To create a workspace using the selected template, please ensure you are authenticated with all the external providers listed below. From d113e25651b61dda8bc6056dc31b935da6efdb8a Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Tue, 20 Feb 2024 22:37:22 +0000 Subject: [PATCH 6/7] - `autofocus` --- site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 4a0c9257d259b..9f52bd254191c 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -214,7 +214,6 @@ export const CreateWorkspacePageView: FC = ({ disabled={creatingWorkspace} // resetMutation facilitates the clearing of validation errors onChange={onChangeTrimmed(form, resetMutation)} - autoFocus fullWidth label="Workspace Name" /> From 36191cefdcfcfcb9b8690338b69753441d6acfe6 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Wed, 21 Feb 2024 00:22:52 +0000 Subject: [PATCH 7/7] specify more reasonable interval and timeout --- .../CreateWorkspacePage/CreateWorkspacePage.test.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx index 5a849cad6ec71..76f86b4bff53d 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx @@ -213,7 +213,11 @@ describe("CreateWorkspacePage", () => { .spyOn(API, "getTemplateVersionExternalAuth") .mockResolvedValue([MockTemplateVersionExternalAuthGithubAuthenticated]); - await screen.findByText("Authenticated with GitHub"); + await screen.findByText( + "Authenticated with GitHub", + {}, + { interval: 500, timeout: 5000 }, + ); const submitButton = screen.getByText(createWorkspaceText); await userEvent.click(submitButton); @@ -229,7 +233,7 @@ describe("CreateWorkspacePage", () => { ); }); - it("external auth: errors if unauthenticated", async () => { + it("external auth errors if unauthenticated", async () => { jest .spyOn(API, "getTemplateVersionExternalAuth") .mockResolvedValueOnce([MockTemplateVersionExternalAuthGithub]);