Skip to content

Commit 53a985f

Browse files
authored
refactor: clean up workspace and template settings (#9654)
1 parent 6c409b8 commit 53a985f

File tree

13 files changed

+153
-123
lines changed

13 files changed

+153
-123
lines changed

site/src/api/queries/templates.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,38 @@
11
import * as API from "api/api";
2+
import { type Template, type AuthorizationResponse } from "api/typesGenerated";
3+
import { type QueryOptions } from "@tanstack/react-query";
4+
5+
export const templateByNameKey = (orgId: string, name: string) => [
6+
orgId,
7+
"template",
8+
name,
9+
"settings",
10+
];
11+
12+
export const templateByName = (
13+
orgId: string,
14+
name: string,
15+
): QueryOptions<{ template: Template; permissions: AuthorizationResponse }> => {
16+
return {
17+
queryKey: templateByNameKey(orgId, name),
18+
queryFn: async () => {
19+
const template = await API.getTemplateByName(orgId, name);
20+
const permissions = await API.checkAuthorization({
21+
checks: {
22+
canUpdateTemplate: {
23+
object: {
24+
resource_type: "template",
25+
resource_id: template.id,
26+
},
27+
action: "update",
28+
},
29+
},
30+
});
31+
32+
return { template, permissions };
33+
},
34+
};
35+
};
236

337
const getTemplatesQueryKey = (orgId: string) => [orgId, "templates"];
438

site/src/api/queries/workspace.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as API from "api/api";
2+
import { type Workspace } from "api/typesGenerated";
3+
import { type QueryOptions } from "@tanstack/react-query";
4+
5+
export const workspaceByOwnerAndNameKey = (owner: string, name: string) => [
6+
"workspace",
7+
owner,
8+
name,
9+
"settings",
10+
];
11+
12+
export const workspaceByOwnerAndName = (
13+
owner: string,
14+
name: string,
15+
): QueryOptions<Workspace> => {
16+
return {
17+
queryKey: workspaceByOwnerAndNameKey(owner, name),
18+
queryFn: () => API.getWorkspaceByOwnerAndName(owner, name),
19+
};
20+
};

site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsPage.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import { FC } from "react";
66
import { Helmet } from "react-helmet-async";
77
import { useNavigate, useParams } from "react-router-dom";
88
import { pageTitle } from "utils/page";
9-
import {
10-
getTemplateQuery,
11-
useTemplateSettingsContext,
12-
} from "../TemplateSettingsLayout";
9+
import { useTemplateSettings } from "../TemplateSettingsLayout";
1310
import { TemplateSettingsPageView } from "./TemplateSettingsPageView";
11+
import { templateByNameKey } from "api/queries/templates";
12+
import { useOrganizationId } from "hooks";
1413

1514
export const TemplateSettingsPage: FC = () => {
1615
const { template: templateName } = useParams() as { template: string };
1716
const navigate = useNavigate();
18-
const { template } = useTemplateSettingsContext();
17+
const orgId = useOrganizationId();
18+
const { template } = useTemplateSettings();
1919
const queryClient = useQueryClient();
2020
const {
2121
mutate: updateTemplate,
@@ -25,9 +25,9 @@ export const TemplateSettingsPage: FC = () => {
2525
(data: UpdateTemplateMeta) => updateTemplateMeta(template.id, data),
2626
{
2727
onSuccess: async () => {
28-
await queryClient.invalidateQueries({
29-
queryKey: getTemplateQuery(templateName),
30-
});
28+
await queryClient.invalidateQueries(
29+
templateByNameKey(orgId, templateName),
30+
);
3131
displaySuccess("Template updated successfully");
3232
},
3333
},

site/src/pages/TemplateSettingsPage/TemplatePermissionsPage/TemplatePermissionsPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import { FC } from "react";
1111
import { Helmet } from "react-helmet-async";
1212
import { pageTitle } from "utils/page";
1313
import { templateACLMachine } from "xServices/template/templateACLXService";
14-
import { useTemplateSettingsContext } from "../TemplateSettingsLayout";
14+
import { useTemplateSettings } from "../TemplateSettingsLayout";
1515
import { TemplatePermissionsPageView } from "./TemplatePermissionsPageView";
1616
import { docs } from "utils/docs";
1717

1818
export const TemplatePermissionsPage: FC<
1919
React.PropsWithChildren<unknown>
2020
> = () => {
2121
const organizationId = useOrganizationId();
22-
const { template, permissions } = useTemplateSettingsContext();
22+
const { template, permissions } = useTemplateSettings();
2323
const { template_rbac: isTemplateRBACEnabled } = useFeatureVisibility();
2424
const [state, send] = useMachine(templateACLMachine, {
2525
context: { templateId: template.id },

site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
138138
}
139139
},
140140
initialTouched,
141+
enableReinitialize: true,
141142
});
142143

143144
const getFieldHelpers = getFormHelpers<TemplateScheduleFormValues>(

site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useMutation } from "@tanstack/react-query";
1+
import { useMutation, useQueryClient } from "@tanstack/react-query";
22
import { updateTemplateMeta } from "api/api";
33
import { UpdateTemplateMeta } from "api/typesGenerated";
44
import { useDashboard } from "components/Dashboard/DashboardProvider";
@@ -7,14 +7,17 @@ import { FC } from "react";
77
import { Helmet } from "react-helmet-async";
88
import { useNavigate, useParams } from "react-router-dom";
99
import { pageTitle } from "utils/page";
10-
import { useTemplateSettingsContext } from "../TemplateSettingsLayout";
10+
import { useTemplateSettings } from "../TemplateSettingsLayout";
1111
import { TemplateSchedulePageView } from "./TemplateSchedulePageView";
12-
import { useLocalStorage } from "hooks";
12+
import { useLocalStorage, useOrganizationId } from "hooks";
13+
import { templateByNameKey } from "api/queries/templates";
1314

1415
const TemplateSchedulePage: FC = () => {
1516
const { template: templateName } = useParams() as { template: string };
1617
const navigate = useNavigate();
17-
const { template } = useTemplateSettingsContext();
18+
const queryClient = useQueryClient();
19+
const orgId = useOrganizationId();
20+
const { template } = useTemplateSettings();
1821
const { entitlements, experiments } = useDashboard();
1922
const allowAdvancedScheduling =
2023
entitlements.features["advanced_template_scheduling"].enabled;
@@ -33,7 +36,10 @@ const TemplateSchedulePage: FC = () => {
3336
} = useMutation(
3437
(data: UpdateTemplateMeta) => updateTemplateMeta(template.id, data),
3538
{
36-
onSuccess: () => {
39+
onSuccess: async () => {
40+
await queryClient.invalidateQueries(
41+
templateByNameKey(orgId, templateName),
42+
);
3743
displaySuccess("Template updated successfully");
3844
// clear browser storage of workspaces impending deletion
3945
clearLocal("dismissedWorkspaceList"); // workspaces page

site/src/pages/TemplateSettingsPage/TemplateSettingsLayout.tsx

Lines changed: 29 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,91 +7,59 @@ import { pageTitle } from "../../utils/page";
77
import { Loader } from "components/Loader/Loader";
88
import { Outlet, useParams } from "react-router-dom";
99
import { Margins } from "components/Margins/Margins";
10-
import { checkAuthorization, getTemplateByName } from "api/api";
1110
import { useQuery } from "@tanstack/react-query";
1211
import { useOrganizationId } from "hooks/useOrganizationId";
12+
import { templateByName } from "api/queries/templates";
13+
import { type AuthorizationResponse, type Template } from "api/typesGenerated";
14+
import { ErrorAlert } from "components/Alert/ErrorAlert";
1315

14-
const templatePermissions = (templateId: string) =>
15-
({
16-
canUpdateTemplate: {
17-
object: {
18-
resource_type: "template",
19-
resource_id: templateId,
20-
},
21-
action: "update",
22-
},
23-
}) as const;
24-
25-
const fetchTemplateSettings = async (orgId: string, name: string) => {
26-
const template = await getTemplateByName(orgId, name);
27-
const permissions = await checkAuthorization({
28-
checks: templatePermissions(template.id),
29-
});
30-
31-
return {
32-
template,
33-
permissions,
34-
};
35-
};
36-
37-
export const getTemplateQuery = (name: string) => [
38-
"template",
39-
name,
40-
"settings",
41-
];
42-
43-
const useTemplate = (orgId: string, name: string) => {
44-
return useQuery({
45-
queryKey: getTemplateQuery(name),
46-
queryFn: () => fetchTemplateSettings(orgId, name),
47-
keepPreviousData: true,
48-
});
49-
};
50-
51-
const TemplateSettingsContext = createContext<
52-
Awaited<ReturnType<typeof fetchTemplateSettings>> | undefined
16+
const TemplateSettings = createContext<
17+
{ template: Template; permissions: AuthorizationResponse } | undefined
5318
>(undefined);
5419

55-
export const useTemplateSettingsContext = () => {
56-
const context = useContext(TemplateSettingsContext);
57-
58-
if (!context) {
59-
throw new Error(
60-
"useTemplateSettingsContext must be used within a TemplateSettingsContext.Provider",
61-
);
20+
export function useTemplateSettings() {
21+
const value = useContext(TemplateSettings);
22+
if (!value) {
23+
throw new Error("This hook can only be used from a template settings page");
6224
}
6325

64-
return context;
65-
};
26+
return value;
27+
}
6628

6729
export const TemplateSettingsLayout: FC = () => {
6830
const styles = useStyles();
6931
const orgId = useOrganizationId();
7032
const { template: templateName } = useParams() as { template: string };
71-
const { data: settings } = useTemplate(orgId, templateName);
33+
const { data, error, isLoading, isError } = useQuery(
34+
templateByName(orgId, templateName),
35+
);
36+
37+
if (isLoading) {
38+
return <Loader />;
39+
}
7240

7341
return (
7442
<>
7543
<Helmet>
7644
<title>{pageTitle([templateName, "Settings"])}</title>
7745
</Helmet>
7846

79-
{settings ? (
80-
<TemplateSettingsContext.Provider value={settings}>
81-
<Margins>
82-
<Stack className={styles.wrapper} direction="row" spacing={10}>
83-
<Sidebar template={settings.template} />
47+
<Margins>
48+
<Stack className={styles.wrapper} direction="row" spacing={10}>
49+
{isError ? (
50+
<ErrorAlert error={error} />
51+
) : (
52+
<TemplateSettings.Provider value={data}>
53+
<Sidebar template={data.template} />
8454
<Suspense fallback={<Loader />}>
8555
<main className={styles.content}>
8656
<Outlet />
8757
</main>
8858
</Suspense>
89-
</Stack>
90-
</Margins>
91-
</TemplateSettingsContext.Provider>
92-
) : (
93-
<Loader />
94-
)}
59+
</TemplateSettings.Provider>
60+
)}
61+
</Stack>
62+
</Margins>
9563
</>
9664
);
9765
};

site/src/pages/TemplateSettingsPage/TemplateVariablesPage/TemplateVariablesPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Helmet } from "react-helmet-async";
1111
import { useNavigate, useParams } from "react-router-dom";
1212
import { templateVariablesMachine } from "xServices/template/templateVariablesXService";
1313
import { pageTitle } from "../../../utils/page";
14-
import { useTemplateSettingsContext } from "../TemplateSettingsLayout";
14+
import { useTemplateSettings } from "../TemplateSettingsLayout";
1515
import { TemplateVariablesPageView } from "./TemplateVariablesPageView";
1616

1717
export const TemplateVariablesPage: FC = () => {
@@ -20,7 +20,7 @@ export const TemplateVariablesPage: FC = () => {
2020
template: string;
2121
};
2222
const organizationId = useOrganizationId();
23-
const { template } = useTemplateSettingsContext();
23+
const { template } = useTemplateSettings();
2424
const navigate = useNavigate();
2525
const [state, send] = useMachine(templateVariablesMachine, {
2626
context: {

site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getWorkspaceParameters, postWorkspaceBuild } from "api/api";
22
import { Helmet } from "react-helmet-async";
33
import { pageTitle } from "utils/page";
4-
import { useWorkspaceSettingsContext } from "../WorkspaceSettingsLayout";
4+
import { useWorkspaceSettings } from "../WorkspaceSettingsLayout";
55
import { useMutation, useQuery } from "@tanstack/react-query";
66
import { Loader } from "components/Loader/Loader";
77
import {
@@ -17,7 +17,7 @@ import { ErrorAlert } from "components/Alert/ErrorAlert";
1717
import { WorkspaceBuildParameter } from "api/typesGenerated";
1818

1919
const WorkspaceParametersPage = () => {
20-
const { workspace } = useWorkspaceSettingsContext();
20+
const workspace = useWorkspaceSettings();
2121
const parameters = useQuery({
2222
queryKey: ["workspace", workspace.id, "parameters"],
2323
queryFn: () => getWorkspaceParameters(workspace),

site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ export const WorkspaceScheduleForm: FC<
201201
onSubmit,
202202
validationSchema,
203203
initialTouched,
204+
enableReinitialize: true,
204205
});
205206
const formHelpers = getFormHelpers<WorkspaceScheduleFormValues>(
206207
form,

site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,21 @@ import {
1010
scheduleChanged,
1111
} from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule";
1212
import { ttlMsToAutostop } from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/ttl";
13-
import { useWorkspaceSettingsContext } from "pages/WorkspaceSettingsPage/WorkspaceSettingsLayout";
13+
import { useWorkspaceSettings } from "pages/WorkspaceSettingsPage/WorkspaceSettingsLayout";
1414
import { FC } from "react";
1515
import { Helmet } from "react-helmet-async";
1616
import { Navigate, useNavigate, useParams } from "react-router-dom";
1717
import { pageTitle } from "utils/page";
1818
import * as TypesGen from "api/typesGenerated";
19+
import { workspaceByOwnerAndNameKey } from "api/queries/workspace";
1920
import { WorkspaceScheduleForm } from "./WorkspaceScheduleForm";
2021
import { workspaceSchedule } from "xServices/workspaceSchedule/workspaceScheduleXService";
2122
import {
2223
formValuesToAutostartRequest,
2324
formValuesToTTLRequest,
2425
} from "./formToRequest";
2526
import { ErrorAlert } from "components/Alert/ErrorAlert";
27+
import { useQueryClient } from "@tanstack/react-query";
2628

2729
const getAutostart = (workspace: TypesGen.Workspace) =>
2830
scheduleToAutostart(workspace.autostart_schedule);
@@ -44,7 +46,8 @@ export const WorkspaceSchedulePage: FC = () => {
4446
const navigate = useNavigate();
4547
const username = params.username.replace("@", "");
4648
const workspaceName = params.workspace;
47-
const { workspace } = useWorkspaceSettingsContext();
49+
const queryClient = useQueryClient();
50+
const workspace = useWorkspaceSettings();
4851
const [scheduleState, scheduleSend] = useMachine(workspaceSchedule, {
4952
context: { workspace },
5053
});
@@ -97,7 +100,7 @@ export const WorkspaceSchedulePage: FC = () => {
97100
onCancel={() => {
98101
navigate(`/@${username}/${workspaceName}`);
99102
}}
100-
onSubmit={(values) => {
103+
onSubmit={async (values) => {
101104
scheduleSend({
102105
type: "SUBMIT_SCHEDULE",
103106
autostart: formValuesToAutostartRequest(values),
@@ -111,6 +114,10 @@ export const WorkspaceSchedulePage: FC = () => {
111114
values,
112115
),
113116
});
117+
118+
await queryClient.invalidateQueries(
119+
workspaceByOwnerAndNameKey(params.username, params.workspace),
120+
);
114121
}}
115122
/>
116123
)}

0 commit comments

Comments
 (0)