Skip to content

Commit b07530b

Browse files
committed
FE works!
1 parent 71bc50d commit b07530b

File tree

13 files changed

+106
-31
lines changed

13 files changed

+106
-31
lines changed

coderd/apidoc/docs.go

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codersdk/users.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ type OIDCAuthMethod struct {
223223

224224
type UserParameter struct {
225225
Name string `json:"name"`
226-
Value string `json:"display_name"`
226+
Value string `json:"value"`
227227
LastUsedAt time.Time `json:"last_used"`
228228
}
229229

docs/api/schemas.md

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/api/users.md

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/api/api.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ export const getAuthenticatedUser = async () => {
129129
return response.data;
130130
};
131131

132+
export const getUserParameters = async () => {
133+
const response = await axios.get<TypesGen.UserParameter[]>(
134+
"/api/v2/users/me/parameters",
135+
);
136+
return response.data;
137+
};
138+
132139
export const getAuthMethods = async (): Promise<TypesGen.AuthMethods> => {
133140
const response = await axios.get<TypesGen.AuthMethods>(
134141
"/api/v2/users/authmethods",

site/src/api/queries/users.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ export const me = (): UseQueryOptions<User> & {
134134
};
135135
};
136136

137+
export const userParameters = () => {
138+
return {
139+
queryKey: ["userParameters"],
140+
queryFn: API.getUserParameters,
141+
};
142+
};
143+
137144
export const hasFirstUser = () => {
138145
return {
139146
queryKey: ["hasFirstUser"],

site/src/api/typesGenerated.ts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/components/RichParameterInput/RichParameterInput.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,16 @@ export type RichParameterInputProps = Omit<
137137
"size" | "onChange"
138138
> & {
139139
parameter: TemplateVersionParameter;
140+
// defaultReason is commentary on how the default value was determined.
141+
defaultReason?: JSX.Element;
140142
onChange: (value: string) => void;
141143
size?: Size;
142144
};
143145

144146
export const RichParameterInput: FC<RichParameterInputProps> = ({
145147
parameter,
146148
size = "medium",
149+
defaultReason,
147150
...fieldProps
148151
}) => {
149152
return (
@@ -156,6 +159,11 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
156159
<ParameterLabel parameter={parameter} />
157160
<div css={{ display: "flex", flexDirection: "column" }}>
158161
<RichParameterField {...fieldProps} size={size} parameter={parameter} />
162+
{defaultReason && (
163+
<div css={{ marginTop: 4, fontSize: 12 }}>
164+
🪄 Autofilling {defaultReason}
165+
</div>
166+
)}
159167
</div>
160168
</Stack>
161169
);

site/src/components/TemplateParameters/TemplateParameters.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ComponentProps, FC } from "react";
88

99
export type TemplateParametersSectionProps = {
1010
templateParameters: TemplateVersionParameter[];
11+
defaultReasons?: Record<string, JSX.Element>;
1112
getInputProps: (
1213
parameter: TemplateVersionParameter,
1314
index: number,
@@ -16,7 +17,12 @@ export type TemplateParametersSectionProps = {
1617

1718
export const MutableTemplateParametersSection: FC<
1819
TemplateParametersSectionProps
19-
> = ({ templateParameters, getInputProps, ...formSectionProps }) => {
20+
> = ({
21+
templateParameters,
22+
getInputProps,
23+
defaultReasons,
24+
...formSectionProps
25+
}) => {
2026
const hasMutableParameters =
2127
templateParameters.filter((p) => p.mutable).length > 0;
2228

@@ -36,6 +42,9 @@ export const MutableTemplateParametersSection: FC<
3642
{...getInputProps(parameter, index)}
3743
key={parameter.name}
3844
parameter={parameter}
45+
defaultReason={
46+
defaultReasons && defaultReasons[parameter.name]
47+
}
3948
/>
4049
),
4150
)}

site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
TemplateVersionParameter,
3+
UserParameter,
34
Workspace,
45
WorkspaceBuildParameter,
56
} from "api/typesGenerated";
@@ -9,7 +10,10 @@ import { type FC, useCallback, useState, useEffect } from "react";
910
import { Helmet } from "react-helmet-async";
1011
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
1112
import { pageTitle } from "utils/page";
12-
import { CreateWorkspacePageView } from "./CreateWorkspacePageView";
13+
import {
14+
CreateWorkspacePageView,
15+
DefaultBuildParameter,
16+
} from "./CreateWorkspacePageView";
1317
import { Loader } from "components/Loader/Loader";
1418
import { ErrorAlert } from "components/Alert/ErrorAlert";
1519
import {
@@ -29,6 +33,7 @@ import { checkAuthorization } from "api/queries/authCheck";
2933
import { CreateWSPermissions, createWorkspaceChecks } from "./permissions";
3034
import { paramsUsedToCreateWorkspace } from "utils/workspace";
3135
import { useEffectEvent } from "hooks/hookPolyfills";
36+
import { userParameters } from "api/queries/users";
3237

3338
export const createWorkspaceModes = ["form", "auto", "duplicate"] as const;
3439
export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number];
@@ -41,7 +46,6 @@ const CreateWorkspacePage: FC = () => {
4146
const me = useMe();
4247
const navigate = useNavigate();
4348
const [searchParams, setSearchParams] = useSearchParams();
44-
const defaultBuildParameters = getDefaultBuildParameters(searchParams);
4549
const mode = getWorkspaceMode(searchParams);
4650
const customVersionId = searchParams.get("version") ?? undefined;
4751
const defaultName = getDefaultName(mode, searchParams);
@@ -53,6 +57,8 @@ const CreateWorkspacePage: FC = () => {
5357
const createWorkspaceMutation = useMutation(createWorkspace(queryClient));
5458

5559
const templateQuery = useQuery(templateByName(organizationId, templateName));
60+
const userParametersQuery = useQuery(userParameters());
61+
5662
const permissionsQuery = useQuery(
5763
checkAuthorization({
5864
checks: createWorkspaceChecks(organizationId),
@@ -89,6 +95,11 @@ const CreateWorkspacePage: FC = () => {
8995
[navigate],
9096
);
9197

98+
const defaultBuildParameters = getDefaultBuildParameters(
99+
searchParams,
100+
userParametersQuery.data ? userParametersQuery.data : [],
101+
);
102+
92103
const automateWorkspaceCreation = useEffectEvent(async () => {
93104
try {
94105
const newWorkspace = await autoCreateWorkspaceMutation.mutateAsync({
@@ -210,15 +221,31 @@ const useExternalAuth = (versionId: string | undefined) => {
210221

211222
const getDefaultBuildParameters = (
212223
urlSearchParams: URLSearchParams,
213-
): WorkspaceBuildParameter[] => {
214-
const buildValues: WorkspaceBuildParameter[] = [];
224+
userParameters: UserParameter[],
225+
): DefaultBuildParameter[] => {
226+
const userParamMap = userParameters.reduce((acc, param) => {
227+
acc.set(param.name, param);
228+
return acc;
229+
}, new Map<string, UserParameter>());
230+
231+
const buildValues: DefaultBuildParameter[] = [];
215232
Array.from(urlSearchParams.keys())
216233
.filter((key) => key.startsWith("param."))
217234
.forEach((key) => {
218235
const name = key.replace("param.", "");
219236
const value = urlSearchParams.get(key) ?? "";
220-
buildValues.push({ name, value });
237+
// URL should take precedence over user parameters
238+
userParamMap.delete(name);
239+
buildValues.push({ name, value, reason: <>supplied by URL</> });
240+
});
241+
242+
userParamMap.forEach((param) => {
243+
buildValues.push({
244+
name: param.name,
245+
value: param.value,
246+
reason: <>recently used value</>,
221247
});
248+
});
222249
return buildValues;
223250
};
224251

site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import TextField from "@mui/material/TextField";
44
import type * as TypesGen from "api/typesGenerated";
55
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
66
import { FormikContextType, useFormik } from "formik";
7-
import { type FC, useEffect, useState } from "react";
7+
import { type FC, useEffect, useState, useMemo } from "react";
88
import {
99
getFormHelpers,
1010
nameValidator,
@@ -43,6 +43,10 @@ export const Language = {
4343
"Duplicating a workspace only copies its parameters. No state from the old workspace is copied over.",
4444
} as const;
4545

46+
export type DefaultBuildParameter = {
47+
reason: JSX.Element;
48+
} & TypesGen.WorkspaceBuildParameter;
49+
4650
export interface CreateWorkspacePageViewProps {
4751
mode: CreateWorkspaceMode;
4852
error: unknown;
@@ -55,7 +59,7 @@ export interface CreateWorkspacePageViewProps {
5559
externalAuthPollingState: ExternalAuthPollingState;
5660
startPollingExternalAuth: () => void;
5761
parameters: TypesGen.TemplateVersionParameter[];
58-
defaultBuildParameters: TypesGen.WorkspaceBuildParameter[];
62+
defaultBuildParameters: DefaultBuildParameter[];
5963
permissions: CreateWSPermissions;
6064
creatingWorkspace: boolean;
6165
onCancel: () => void;
@@ -125,6 +129,16 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
125129
error,
126130
);
127131

132+
const defaultReasons = useMemo(() => {
133+
return defaultBuildParameters.reduce(
134+
(acc, param) => {
135+
acc[param.name] = param.reason;
136+
return acc;
137+
},
138+
{} as Record<string, JSX.Element>,
139+
);
140+
}, [defaultBuildParameters]);
141+
128142
return (
129143
<FullPageHorizontalForm title="New workspace" onCancel={onCancel}>
130144
<HorizontalForm onSubmit={form.handleSubmit}>
@@ -211,6 +225,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
211225
{parameters && (
212226
<>
213227
<MutableTemplateParametersSection
228+
defaultReasons={defaultReasons}
214229
templateParameters={parameters}
215230
getInputProps={(parameter, index) => {
216231
return {
@@ -231,6 +246,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
231246
}}
232247
/>
233248
<ImmutableTemplateParametersSection
249+
defaultReasons={defaultReasons}
234250
templateParameters={parameters}
235251
classes={{
236252
root: css`

0 commit comments

Comments
 (0)