8000 chore: hide workspace creation UI for users without permission · coder/coder@03acbe3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 03acbe3

Browse files
committed
chore: hide workspace creation UI for users without permission
1 parent 61246bc commit 03acbe3

File tree

4 files changed

+53
-6
lines changed

4 files changed

+53
-6
lines changed

site/src/modules/management/organizationPermissions.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ export const organizationPermissionChecks = (organizationId: string) =>
101101
},
102102
action: "update",
103103
},
104+
createWorkspaces: {
105+
object: {
106+
resource_type: "workspace",
107+
organization_id: organizationId,
108+
owner_id: "*",
109+
},
110+
action: "create",
111+
},
104112
}) as const satisfies Record<string, AuthorizationCheck>;
105113

106114
/**

site/src/pages/TemplatesPage/TemplatesPage.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { organizationsPermissions } from "api/queries/organizations";
12
import { templateExamples, templates } from "api/queries/templates";
23
import { useFilter } from "components/Filter/Filter";
34
import { useAuthenticated } from "contexts/auth/RequireAuth";
@@ -25,7 +26,15 @@ export const TemplatesPage: FC = () => {
2526
...templateExamples(),
2627
enabled: permissions.createTemplates,
2728
});
28-
const error = templatesQuery.error || examplesQuery.error;
29+
30+
const orgPermissionsQuery = useQuery(
31+
organizationsPermissions(
32+
templatesQuery.data?.map((template) => template.organization_id),
33+
),
34+
);
35+
36+
const error =
37+
templatesQuery.error || examplesQuery.error || orgPermissionsQuery.error;
2938

3039
return (
3140
<>
@@ -39,6 +48,7 @@ export const TemplatesPage: FC = () => {
3948
canCreateTemplates={permissions.createTemplates}
4049
examples={examplesQuery.data}
4150
templates={templatesQuery.data}
51+
orgPermissions={orgPermissionsQuery.data}
4252
/>
4353
</>
4454
);

site/src/pages/TemplatesPage/TemplatesPageView.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
} from "components/TableLoader/TableLoader";
4040
import { useClickableTableRow } from "hooks/useClickableTableRow";
4141
import { PlusIcon } from "lucide-react";
42+
import type { OrganizationPermissions } from "modules/management/organizationPermissions";
4243
import { linkToTemplate, useLinks } from "modules/navigation";
4344
import type { FC } from "react";
4445
import { Link, useNavigate } from "react-router-dom";
@@ -88,9 +89,14 @@ const TemplateHelpTooltip: FC = () => {
8889
interface TemplateRowProps {
8990
showOrganizations: boolean;
9091
template: Template;
92+
orgPermissions: Record<string, OrganizationPermissions> | undefined;
9193
}
9294

93-
const TemplateRow: FC<TemplateRowProps> = ({ showOrganizations, template }) => {
95+
const TemplateRow: FC<TemplateRowProps> = ({
96+
showOrganizations,
97+
template,
98+
orgPermissions,
99+
}) => {
94100
const getLink = useLinks();
95101
const templatePageLink = getLink(
96102
linkToTemplate(template.organization_name, template.name),
@@ -154,7 +160,7 @@ const TemplateRow: FC<TemplateRowProps> = ({ showOrganizations, template }) => {
154160
<TableCell css={styles.actionCell}>
155161
{template.deprecated ? (
156162
<DeprecatedBadge />
157-
) : (
163+
) : orgPermissions?.[template.organization_id]?.createWorkspaces ? (
158164
<MuiButton
159165
size="small"
160166
css={styles.actionButton}
@@ -168,7 +174,7 @@ const TemplateRow: FC<TemplateRowProps> = ({ showOrganizations, template }) => {
168174
>
169175
Create Workspace
170176
</MuiButton>
171-
)}
177+
) : null}
172178
</TableCell>
173179
</TableRow>
174180
);
@@ -181,6 +187,7 @@ export interface TemplatesPageViewProps {
181187
canCreateTemplates: boolean;
182188
examples: TemplateExample[] | undefined;
183189
templates: Template[] | undefined;
190+
orgPermissions: Record<string, OrganizationPermissions> | undefined;
184191
}
185192

186193
export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
@@ -190,6 +197,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
190197
canCreateTemplates,
191198
examples,
192199
templates,
200+
orgPermissions,
193201
}) => {
194202
const isLoading = !templates;
195203
const isEmpty = templates && templates.length === 0;
@@ -254,6 +262,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
254262
key={template.id}
255263
showOrganizations={showOrganizations}
256264
template={template}
265+
orgPermissions={orgPermissions}
257266
/>
258267
))
259268
)}

site/src/pages/WorkspacesPage/WorkspacesPage.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { organizationsPermissions } from "api/queries/organizations";
12
import { templates } from "api/queries/templates";
23
import type { Workspace } from "api/typesGenerated";
34
import { useFilter } from "components/Filter/Filter";
@@ -7,7 +8,7 @@ import { useEffectEvent } from "hooks/hookPolyfills";
78
import { usePagination } from "hooks/usePagination";
89
import { useDashboard } from "modules/dashboard/useDashboard";
910
import { useOrganizationsFilterMenu } from "modules/tableFiltering/options";
10-
import { type FC, useEffect, useState } from "react";
11+
import { type FC, useEffect, useMemo, useState } from "react";
1112
import { Helmet } from "react-helmet-async";
1213
import { useQuery } from "react-query";
1314
import { useSearchParams } from "react-router-dom";
@@ -44,6 +45,25 @@ const WorkspacesPage: FC = () => {
4445

4546
const templatesQuery = useQuery(templates());
4647

48+
// Check if user can create workspaces in each organization
49+
const orgPermissionsQuery = useQuery(
50+
organizationsPermissions(
51+
templatesQuery.data?.map((template) => template.organization_id),
52+
),
53+
);
54+
55+
// Filter templates based on workspace creation permission
56+
const filteredTemplates = useMemo(() => {
57+
if (!templatesQuery.data || !orgPermissionsQuery.data) {
58+
return templatesQuery.data;
59+
}
60+
61+
return templatesQuery.data.filter((template) => {
62+
const orgPermission = orgPermissionsQuery.data[template.organization_id];
63+
return orgPermission?.createWorkspaces;
64+
});
65+
}, [templatesQuery.data, orgPermissionsQuery.data]);
66+
4767
const filterProps = useWorkspacesFilter({
4868
searchParamsResult,
4969
onFilterChange: () => pagination.goToPage(1),
@@ -90,7 +110,7 @@ const WorkspacesPage: FC = () => {
90110
checkedWorkspaces={checkedWorkspaces}
91111
onCheckChange={setCheckedWorkspaces}
92112
canCheckWorkspaces={canCheckWorkspaces}
93-
templates={templatesQuery.data}
113+
templates={filteredTemplates}
94114
templatesFetchStatus={templatesQuery.status}
95115
workspaces={data?.workspaces}
96116
error={error}

0 commit comments

Comments
 (0)
0