Skip to content

Commit 7cf3361

Browse files
committed
refactor(site)verify external auth before display ws form
1 parent 369821e commit 7cf3361

9 files changed

+485
-320
lines changed

site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx

Lines changed: 122 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
ImmutableTemplateParametersSection,
2828
MutableTemplateParametersSection,
2929
} from "components/TemplateParameters/TemplateParameters";
30-
import { ExternalAuthButton } from "./ExternalAuthButton";
3130
import { ErrorAlert } from "components/Alert/ErrorAlert";
3231
import { Stack } from "components/Stack/Stack";
3332
import {
@@ -37,6 +36,7 @@ import {
3736
import { useSearchParams } from "react-router-dom";
3837
import { CreateWSPermissions } from "./permissions";
3938
import { Alert } from "components/Alert/Alert";
39+
import { ExternalAuthBanner } from "./ExternalAuthBanner/ExternalAuthBanner";
4040

4141
export const Language = {
4242
duplicationWarning:
@@ -126,152 +126,139 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
126126

127127
return (
128128
<FullPageHorizontalForm title="New workspace" onCancel={onCancel}>
129-
<HorizontalForm onSubmit={form.handleSubmit}>
130-
{Boolean(error) && <ErrorAlert error={error} />}
131-
132-
{mode === "duplicate" && (
133-
<Alert severity="info" dismissible>
134-
{Language.duplicationWarning}
135-
</Alert>
136-
)}
129+
{requiresExternalAuth ? (
130+
<ExternalAuthBanner
131+
providers={externalAuth}
132+
pollingState={externalAuthPollingState}
133+
onStartPolling={startPollingExternalAuth}
134+
/>
135+
) : (
136+
<HorizontalForm onSubmit={form.handleSubmit}>
137+
{Boolean(error) && <ErrorAlert error={error} />}
137138

138-
{/* General info */}
139-
<FormSection
140-
title="General"
141-
description="The template and name of your new workspace."
142-
>
143-
<FormFields>
144-
<SelectedTemplate template={template} />
145-
{versionId && versionId !== template.active_version_id && (
146-
<Stack spacing={1} css={styles.hasDescription}>
147-
<TextField
148-
disabled
149-
fullWidth
150-
value={versionId}
151-
label="Version ID"
152-
/>
153-
<span css={styles.description}>
154-
This parameter has been preset, and cannot be modified.
155-
</span>
156-
</Stack>
157-
)}
158-
<TextField
159-
{...getFieldHelpers("name")}
160-
disabled={creatingWorkspace}
161-
// resetMutation facilitates the clearing of validation errors
162-
onChange={onChangeTrimmed(form, resetMutation)}
163-
autoFocus
164-
fullWidth
165-
label="Workspace Name"
166-
/>
167-
</FormFields>
168-
</FormSection>
139+
{mode === "duplicate" && (
140+
<Alert severity="info" dismissible>
141+
{Language.duplicationWarning}
142+
</Alert>
143+
)}
169144

170-
{permissions.createWorkspaceForUser && (
171145
<FormSection
172-
title="Workspace Owner"
173-
description="Only admins can create workspace for other users."
146+
title="General"
147+
description="The template and name of your new workspace."
174148
>
175149
<FormFields>
176-
<UserAutocomplete
177-
value={owner}
178-
onChange={(user) => {
179-
setOwner(user ?? defaultOwner);
180-
}}
181-
label="Owner"
182-
size="medium"
150+
<SelectedTemplate template={template} />
151+
{versionId && versionId !== template.active_version_id && (
152+
<Stack spacing={1} css={styles.hasDescription}>
153+
<TextField
154+
disabled
155+
fullWidth
156+
value={versionId}
157+
label="Version ID"
158+
/>
159+
<span css={styles.description}>
160+
This parameter has been preset, and cannot be modified.
161+
</span>
162+
</Stack>
163+
)}
164+
<TextField
165+
{...getFieldHelpers("name")}
166+
disabled={creatingWorkspace}
167+
// resetMutation facilitates the clearing of validation errors
168+
onChange={onChangeTrimmed(form, resetMutation)}
169+
autoFocus
170+
fullWidth
171+
label="Workspace Name"
183172
/>
184173
</FormFields>
185174
</FormSection>
186-
)}
187175

188-
{externalAuth && externalAuth.length > 0 && (
189-
<FormSection
190-
title="External Authentication"
191-
description="This template requires authentication to external services."
192-
>
193-
<FormFields>
194-
{requiresExternalAuth && (
195-
<Alert severity="error">
196-
To create a workspace using the selected template, please
197-
ensure you are authenticated with all the external providers
198-
listed below.
199-
</Alert>
200-
)}
201-
{externalAuth.map((auth) => (
202-
<ExternalAuthButton
203-
key={auth.id}
204-
auth={auth}
205-
isLoading={externalAuthPollingState === "polling"}
206-
onStartPolling={startPollingExternalAuth}
207-
displayRetry={externalAuthPollingState === "abandoned"}
176+
{permissions.createWorkspaceForUser && (
177+
<FormSection
178+
title="Workspace Owner"
179+
description="Only admins can create workspace for other users."
180+
>
181+
<FormFields>
182+
<UserAutocomplete
183+
value={owner}
184+
onChange={(user) => {
185+
setOwner(user ?? defaultOwner);
186+
}}
187+
label="Owner"
188+
size="medium"
208189
/>
209-
))}
210-
</FormFields>
211-
</FormSection>
212-
)}
190+
</FormFields>
191+
</FormSection>
192+
)}
213193

214-
{parameters && (
215-
<>
216-
<MutableTemplateParametersSection
217-
templateParameters={parameters}
218-
getInputProps={(parameter, index) => {
219-
return {
220-
...getFieldHelpers(
221-
"rich_parameter_values[" + index + "].value",
222-
),
223-
onChange: async (value) => {
224-
await form.setFieldValue("rich_parameter_values." + index, {
225-
name: parameter.name,
226-
value: value,
227-
});
228-
},
229-
disabled:
230-
disabledParamsList?.includes(
231-
parameter.name.toLowerCase().replace(/ /g, "_"),
232-
) || creatingWorkspace,
233-
};
234-
}}
235-
/>
236-
<ImmutableTemplateParametersSection
237-
templateParameters={parameters}
238-
classes={{
239-
root: css`
240-
border: 1px solid ${theme.palette.warning.light};
241-
border-radius: 8px;
242-
background-color: ${theme.palette.background.paper};
243-
padding: 80px;
244-
margin-left: -80px;
245-
margin-right: -80px;
246-
`,
247-
}}
248-
getInputProps={(parameter, index) => {
249-
return {
250-
...getFieldHelpers(
251-
"rich_parameter_values[" + index + "].value",
252-
),
253-
onChange: async (value) => {
254-
await form.setFieldValue("rich_parameter_values." + index, {
255-
name: parameter.name,
256-
value: value,
257-
});
258-
},
259-
disabled:
260-
disabledParamsList?.includes(
261-
parameter.name.toLowerCase().replace(/ /g, "_"),
262-
) || creatingWorkspace,
263-
};
264-
}}
265-
/>
266-
</>
267-
)}
194+
{parameters && (
195+
<>
196+
<MutableTemplateParametersSection
197+
templateParameters={parameters}
198+
getInputProps={(parameter, index) => {
199+
return {
200+
...getFieldHelpers(
201+
"rich_parameter_values[" + index + "].value",
202+
),
203+
onChange: async (value) => {
204+
await form.setFieldValue(
205+
"rich_parameter_values." + index,
206+
{
207+
name: parameter.name,
208+
value: value,
209+
},
210+
);
211+
},
212+
disabled:
213+
disabledParamsList?.includes(
214+
parameter.name.toLowerCase().replace(/ /g, "_"),
215+
) || creatingWorkspace,
216+
};
217+
}}
218+
/>
219+
<ImmutableTemplateParametersSection
220+
templateParameters={parameters}
221+
classes={{
222+
root: css`
223+
border: 1px solid ${theme.palette.warning.light};
224+
border-radius: 8px;
225+
background-color: ${theme.palette.background.paper};
226+
padding: 80px;
227+
margin-left: -80px;
228+
margin-right: -80px;
229+
`,
230+
}}
231+
getInputProps={(parameter, index) => {
232+
return {
233+
...getFieldHelpers(
234+
"rich_parameter_values[" + index + "].value",
235+
),
236+
onChange: async (value) => {
237+
await form.setFieldValue(
238+
"rich_parameter_values." + index,
239+
{
240+
name: parameter.name,
241+
value: value,
242+
},
243+
);
244+
},
245+
disabled:
246+
disabledParamsList?.includes(
247+
parameter.name.toLowerCase().replace(/ /g, "_"),
248+
) || creatingWorkspace,
249+
};
250+
}}
251+
/>
252+
</>
253+
)}
268254

269-
<FormFooter
270-
onCancel={onCancel}
271-
isLoading={creatingWorkspace}
272-
submitLabel="Create Workspace"
273-
/>
274-
</HorizontalForm>
255+
<FormFooter
256+
onCancel={onCancel}
257+
isLoading={creatingWorkspace}
258+
submitLabel="Create Workspace"
259+
/>
260+
</HorizontalForm>
261+
)}
275262
</FullPageHorizontalForm>
276263
);
277264
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { TemplateVersionExternalAuth } from "api/typesGenerated";
2+
import { ExternalAuthBanner } from "./ExternalAuthBanner";
3+
import type { Meta, StoryObj } from "@storybook/react";
4+
5+
const MockExternalAuth: TemplateVersionExternalAuth = {
6+
id: "",
7+
type: "",
8+
display_name: "GitHub",
9+
display_icon: "/icon/github.svg",
10+
authenticate_url: "",
11+
authenticated: false,
12+
};
13+
14+
const meta: Meta<typeof ExternalAuthBanner> = {
15+
title: "pages/CreateWorkspacePage/ExternalAuthBanner/ExternalAuthBanner",
16+
component: ExternalAuthBanner,
17+
};
18+
19+
export default meta;
20+
type Story = StoryObj<typeof ExternalAuthBanner>;
21+
22+
export const Default: Story = {
23+
args: {
24+
providers: [
25+
MockExternalAuth,
26+
{
27+
...MockExternalAuth,
28+
display_name: "Google",
29+
display_icon: "/icon/google.svg",
30+
authenticated: true,
31+
},
32+
],
33+
},
34+
};

0 commit comments

Comments
 (0)