8000 chore: updates for PR review · coder/coder@6544543 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6544543

Browse files
committed
8000
chore: updates for PR review
1 parent f7fb986 commit 6544543

File tree

12 files changed

+112
-67
lines changed

12 files changed

+112
-67
lines changed

site/src/api/queries/organizations.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import {
1313
type OrganizationPermissions,
1414
organizationPermissionChecks,
1515
} from "modules/permissions/organizations";
16+
import {
17+
type WorkspacePermissionName,
18+
type WorkspacePermissions,
19+
workspacePermissionChecks,
20+
} from "modules/permissions/workspaces";
1621
import type { QueryClient } from "react-query";
1722
import { meKey } from "./users";
1823

@@ -299,6 +304,44 @@ export const organizationsPermissions = (
299304
};
300305
};
301306

307+
export const workspacePermissionsByOrganization = (
308+
organizationIds: string[] | undefined,
309+
) => {
310+
if (!organizationIds) {
311+
return { enabled: false };
312+
}
313+
314+
return {
315+
queryKey: ["workspaces", organizationIds.sort(), "permissions"],
316+
queryFn: async () => {
317+
const prefixedChecks = organizationIds.flatMap((orgId) =>
318+
Object.entries(workspacePermissionChecks(orgId)).map(([key, val]) => [
319+
`${orgId}.${key}`,
320+
val,
321+
]),
322+
);
323+
324+
const response = await API.checkAuthorization({
325+
checks: Object.fromEntries(prefixedChecks),
326+
});
327+
328+
return Object.entries(response).reduce(
329+
(acc, [key, value]) => {
330+
const index = key.indexOf(".");
331+
const orgId = key.substring(0, index);
332+
const perm = key.substring(index + 1);
333+
if (!acc[orgId]) {
334+
acc[orgId] = {};
335+
}
336+
acc[orgId][perm as WorkspacePermissionName] = value;
337+
return acc;
338+
},
339+
{} as Record<string, Partial<WorkspacePermissions>>,
340+
) as Record<string, WorkspacePermissions>;
341+
},
342+
};
343+
};
344+
302345
export const getOrganizationIdpSyncClaimFieldValuesKey = (
303346
organization: string,
304347
field: string,

site/src/modules/permissions/organizations.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,6 @@ export const organizationPermissionChecks = (organizationId: string) =>
115115
},
116116
action: "update",
117117
},
118-
createWorkspaces: {
119-
object: {
120-
resource_type: "workspace",
121-
organization_id: organizationId,
122-
owner_id: "*",
123-
},
124-
action: "create",
125-
},
126118
}) as const satisfies Record<string, AuthorizationCheck>;
127119

128120
/**
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const workspacePermissionChecks = (organizationId: string) =>
2+
({
3+
createWorkspaceForUser: {
4+
object: {
5+
resource_type: "workspace",
6+
organization_id: organizationId,
7+
owner_id: "*",
8+
},
9+
action: "create",
10+
},
11+
}) as const;
12+
13+
export type WorkspacePermissions = Record<
14+
keyof ReturnType<typeof workspacePermissionChecks>,
15+
boolean
16+
>;
17+
18+
export type WorkspacePermissionName = keyof ReturnType<
19+
typeof workspacePermissionChecks
20+
>;

site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import { Loader } from "components/Loader/Loader";
1717
import { useAuthenticated } from "contexts/auth/RequireAuth";
1818
import { useEffectEvent } from "hooks/hookPolyfills";
1919
import { useDashboard } from "modules/dashboard/useDashboard";
20+
import {
21+
type WorkspacePermissions,
22+
workspacePermissionChecks,
23+
} from "modules/permissions/workspaces";
2024
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
2125
import { type FC, useCallback, useEffect, useRef, useState } from "react";
2226
import { Helmet } from "react-helmet-async";
@@ -26,7 +30,6 @@ import { pageTitle } from "utils/page";
2630
import type { AutofillBuildParameter } from "utils/richParameters";
2731
import { paramsUsedToCreateWorkspace } from "utils/workspace";
2832
import { CreateWorkspacePageView } from "./CreateWorkspacePageView";
29-
import { type CreateWSPermissions, createWorkspaceChecks } from "./permissions";
3033

3134
export const createWorkspaceModes = ["form", "auto", "duplicate"] as const;
3235
export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number];
@@ -64,7 +67,7 @@ const CreateWorkspacePage: FC = () => {
6467
const permissionsQuery = useQuery(
6568
templateQuery.data
6669
? checkAuthorization({
67-
checks: createWorkspaceChecks(templateQuery.data.organization_id),
70+
checks: workspacePermissionChecks(templateQuery.data.organization_id),
6871
})
6972
: { enabled: false },
7073
);
@@ -206,7 +209,7 @@ const CreateWorkspacePage: FC = () => {
206209
externalAuthPollingState={externalAuthPollingState}
207210
startPollingExternalAuth={startPollingExternalAuth}
208211
hasAllRequiredExternalAuth={hasAllRequiredExternalAuth}
209-
permissions={permissionsQuery.data as CreateWSPermissions}
212+
permissions={permissionsQuery.data as WorkspacePermissions}
210213
parameters={realizedParameters as TemplateVersionParameter[]}
211214
presets={templateVersionPresetsQuery.data ?? []}
212215
creatingWorkspace={createWorkspaceMutation.isLoading}

site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { Stack } from "components/Stack/Stack";
2828
import { Switch } from "components/Switch/Switch";
2929
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
3030
import { type FormikContextType, useFormik } from "formik";
31+
import type { WorkspacePermissions } from "modules/permissions/workspaces";
3132
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
3233
import { type FC, useCallback, useEffect, useMemo, useState } from "react";
3334
import {
@@ -46,7 +47,6 @@ import type {
4647
ExternalAuthPollingState,
4748
} from "./CreateWorkspacePage";
4849
import { ExternalAuthButton } from "./ExternalAuthButton";
49-
import type { CreateWSPermissions } from "./permissions";
5050

5151
export const Language = {
5252
duplicationWarning:
@@ -69,7 +69,7 @@ export interface CreateWorkspacePageViewProps {
6969
parameters: TypesGen.TemplateVersionParameter[];
7070
autofillParameters: AutofillBuildParameter[];
7171
presets: TypesGen.Preset[];
72-
permissions: CreateWSPermissions;
72+
permissions: WorkspacePermissions;
7373
creatingWorkspace: boolean;
7474
onCancel: () => void;
7575
onSubmit: (

site/src/pages/CreateWorkspacePage/permissions.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

site/src/pages/TemplatePage/TemplateLayout.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { API } from "api/api";
2-
import { organizationsPermissions } from "api/queries/organizations";
2+
import { checkAuthorization } from "api/queries/authCheck";
33
import type { AuthorizationRequest } from "api/typesGenerated";
44
import { ErrorAlert } from "components/Alert/ErrorAlert";
55
import { Loader } from "components/Loader/Loader";
66
import { Margins } from "components/Margins/Margins";
77
import { TabLink, Tabs, TabsList } from "components/Tabs/Tabs";
8+
import { workspacePermissionChecks } from "modules/permissions/workspaces";
89
import {
910
type FC,
1011
type PropsWithChildren,
@@ -78,9 +79,12 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
7879
queryKey: ["template", templateName],
7980
queryFn: () => fetchTemplate(organizationName, templateName),
8081
});
81-
const orgPermissionsQuery = useQuery(
82-
organizationsPermissions([organizationName]),
82+
const workspacePermissionsQuery = useQuery(
83+
checkAuthorization({
84+
checks: workspacePermissionChecks(organizationName),
85+
}),
8386
);
87+
8488
const location = useLocation();
8589
const paths = location.pathname.split("/");
8690
const activeTab = paths.at(-1) === templateName ? "summary" : paths.at(-1)!;
@@ -89,27 +93,25 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
8993
const shouldShowInsights =
9094
data?.permissions?.canUpdateTemplate || data?.permissions?.canReadInsights;
9195

92-
if (error || orgPermissionsQuery.error) {
96+
if (error || workspacePermissionsQuery.error) {
9397
return (
9498
<div css={{ margin: 16 }}>
9599
<ErrorAlert error={error} />
96100
</div>
97101
);
98102
}
99103

100-
if (isLoading || !data || !orgPermissionsQuery.data) {
104+
if (isLoading || !data || !workspacePermissionsQuery.data) {
101105
return <Loader />;
102106
}
103107

104-
const orgPermissions = orgPermissionsQuery.data?.[organizationName];
105-
106108
return (
107109
<>
108110
<TemplatePageHeader
109111
template={data.template}
110112
activeVersion={data.activeVersion}
111113
permissions={data.permissions}
112-
orgPermissions={orgPermissions}
114+
workspacePermissions={workspacePermissionsQuery.data}
113115
onDeleteTemplate={() => {
114116
navigate("/templates");
115117
}}

site/src/pages/TemplatePage/TemplatePageHeader.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import {
3131
import { Pill } from "components/Pill/Pill";
3232
import { Stack } from "components/Stack/Stack";
3333
import { linkToTemplate, useLinks } from "modules/navigation";
34-
import type { OrganizationPermissions } from "modules/permissions/organizations";
3534
import type { FC } from "react";
3635
import { useQuery } from "react-query";
3736
import { Link as RouterLink, useNavigate } from "react-router-dom";
@@ -159,15 +158,15 @@ export type TemplatePageHeaderProps = {
159158
template: Template;
160159
activeVersion: TemplateVersion;
161160
permissions: AuthorizationResponse;
162-
orgPermissions: OrganizationPermissions | undefined;
161+
workspacePermissions: AuthorizationResponse;
163162
onDeleteTemplate: () => void;
164163
};
165164

166165
export const TemplatePageHeader: FC<TemplatePageHeaderProps> = ({
167166
template,
168167
activeVersion,
169168
permissions,
170-
orgPermissions,
169+
workspacePermissions,
171170
onDeleteTemplate,
172171
}) => {
173172
const getLink = useLinks();
@@ -180,16 +179,17 @@ export const TemplatePageHeader: FC<TemplatePageHeaderProps> = ({
180179
<PageHeader
181180
actions={
182181
<>
183-
{!template.deprecated && orgPermissions?.createWorkspaces && (
184-
<Button
185-
variant="contained"
186-
startIcon={<AddIcon />}
187-
component={RouterLink}
188-
to={`${templateLink}/workspace`}
189-
>
190-
Create Workspace
191-
</Button>
192-
)}
182+
{!template.deprecated &&
183+
workspacePermissions.createWorkspaceForUser && (
184+
<Button
185+
variant="contained"
186+
startIcon={<AddIcon />}
187+
component={RouterLink}
188+
to={`${templateLink}/workspace`}
189+
>
190+
Create Workspace
191+
</Button>
192+
)}
193193

194194
{permissions.canUpdateTemplate && (
195195
<TemplateMenu

site/src/pages/TemplatesPage/TemplatesPage.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { organizationsPermissions } from "api/queries/organizations";
1+
import { workspacePermissionsByOrganization } from "api/queries/organizations";
22
import { templateExamples, templates } from "api/queries/templates";
33
import { useFilter } from "components/Filter/Filter";
44
import { useAuthenticated } from "contexts/auth/RequireAuth";
@@ -27,14 +27,16 @@ export const TemplatesPage: FC = () => {
2727
enabled: permissions.createTemplates,
2828
});
2929

30-
const orgPermissionsQuery = useQuery(
31-
organizationsPermissions(
30+
const workspacePermissionsQuery = useQuery(
31+
workspacePermissionsByOrganization(
3232
templatesQuery.data?.map((template) => template.organization_id),
3333
),
3434
);
3535

3636
const error =
37-
templatesQuery.error || examplesQuery.error || orgPermissionsQuery.error;
37+
templatesQuery.error ||
38+
examplesQuery.error ||
39+
workspacePermissionsQuery.error;
3840

3941
return (
4042
<>
@@ -48,7 +50,7 @@ export const TemplatesPage: FC = () => {
4850
canCreateTemplates={permissions.createTemplates}
4951
examples={examplesQuery.data}
5052
templates={templatesQuery.data}
51-
orgPermissions={orgPermissionsQuery.data}
53+
workspacePermissions={workspacePermissionsQuery.data}
5254
/>
5355
</>
5456
);

site/src/pages/TemplatesPage/TemplatesPageView.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import {
4040
import { useClickableTableRow } from "hooks/useClickableTableRow";
4141
import { PlusIcon } from "lucide-react";
4242
import { linkToTemplate, useLinks } from "modules/navigation";
43-
import type { OrganizationPermissions } from "modules/permissions/organizations";
43+
import type { WorkspacePermissions } from "modules/permissions/workspaces";
4444
import type { FC } from "react";
4545
import { Link, useNavigate } from "react-router-dom";
4646
import { createDayString } from "utils/createDayString";
@@ -88,13 +88,13 @@ const TemplateHelpTooltip: FC = () => {
8888
interface TemplateRowProps {
8989
showOrganizations: boolean;
9090
template: Template;
91-
orgPermissions: Record<string, OrganizationPermissions> | undefined;
91+
workspacePermissions: Record<string, WorkspacePermissions> | undefined;
9292
}
9393

9494
const TemplateRow: FC<TemplateRowProps> = ({
9595
showOrganizations,
9696
template,
97-
orgPermissions,
97+
workspacePermissions,
9898
}) => {
9999
const getLink = useLinks();
100100
const templatePageLink = getLink(
@@ -158,7 +158,8 @@ const TemplateRow: FC<TemplateRowProps> = ({
158158
<TableCell css={styles.actionCell}>
159159
{template.deprecated ? (
160160
<DeprecatedBadge />
161-
) : orgPermissions?.[template.organization_id]?.createWorkspaces ? (
161+
) : workspacePermissions?.[template.organization_id]
162+
?.createWorkspaceForUser ? (
162163
<MuiButton
163164
size="small"
164165
css={styles.actionButton}
@@ -185,7 +186,7 @@ export interface TemplatesPageViewProps {
185186
canCreateTemplates: boolean;
186187
examples: TemplateExample[] | undefined;
187188
templates: Template[] | undefined;
188-
orgPermissions: Record<string, OrganizationPermissions> | undefined;
189+
workspacePermissions: Record<string, WorkspacePermissions> | undefined;
189190
}
190191

191192
export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
@@ -195,7 +196,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
195196
canCreateTemplates,
196197
examples,
197198
templates,
198-
orgPermissions,
199+
workspacePermissions,
199200
}) => {
200201
const isLoading = !templates;
201202
const isEmpty = templates && templates.length === 0;
@@ -257,7 +258,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
257258
key={template.id}
258259
showOrganizations={showOrganizations}
259260
template={template}
260-
orgPermissions={orgPermissions}
261+
workspacePermissions={workspacePermissions}
261262
/>
262263
))
263264
)}

0 commit comments

Comments
 (0)
0