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

Skip to content

Commit 124bf93

Browse files
committed
chore: hide workspace creation UI for users without permission
1 pa
8000
rent 86b61ef commit 124bf93

File tree

4 files changed

+53
-6
lines changed

4 files changed

+53
-6
lines changed

site/src/modules/permissions/organizations.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@ 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+
},
118126
}) as const satisfies Record<string, AuthorizationCheck>;
119127

120128
/**

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";
@@ -87,9 +88,14 @@ const TemplateHelpTooltip: FC = () => {
8788
interface TemplateRowProps {
8889
showOrganizations: boolean;
8990
template: Template;
91+
orgPermissions: Record<string, OrganizationPermissions> | undefined;
9092
}
9193

92-
const TemplateRow: FC<TemplateRowProps> = ({ showOrganizations, template }) => {
94+
const TemplateRow: FC<TemplateRowProps> = ({
95+
showOrganizations,
96+
template,
97+
orgPermissions,
98+
}) => {
9399
const getLink = useLinks();
94100
const templatePageLink = getLink(
95101
linkToTemplate(template.organization_name, template.name),
@@ -152,7 +158,7 @@ const TemplateRow: FC<TemplateRowProps> = ({ showOrganizations, template }) => {
152158
<TableCell css={styles.actionCell}>
153159
{template.deprecated ? (
154160
<DeprecatedBadge />
155-
) : (
161+
) : orgPermissions?.[template.organization_id]?.createWorkspaces ? (
156162
<MuiButton
157163
size="small"
158164
css={styles.actionButton}
@@ -166,7 +172,7 @@ const TemplateRow: FC<TemplateRowProps> = ({ showOrganizations, template }) => {
166172
>
167173
Create Workspace
168174
</MuiButton>
169-
)}
175+
) : null}
170176
</TableCell>
171177
</TableRow>
172178
);
@@ -179,6 +185,7 @@ export interface TemplatesPageViewProps {
179185
canCreateTemplates: boolean;
180186
examples: TemplateExample[] | undefined;
181187
templates: Template[] | undefined;
188+
orgPermissions: Record<string, OrganizationPermissions> | undefined;
182189
}
183190

184191
export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
@@ -188,6 +195,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
188195
canCreateTemplates,
189196
examples,
190197
templates,
198+
orgPermissions,
191199
}) => {
192200
const isLoading = !templates;
193201
const isEmpty = templates && templates.length === 0;
@@ -249,6 +257,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
249257
key={template.id}
250258
showOrganizations={showOrganizations}
251259
template={template}
260+
orgPermissions={orgPermissions}
252261
/>
253262
))
254263
)}

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