diff --git a/site/src/api/queries/organizations.ts b/site/src/api/queries/organizations.ts index b0e25a985bd0f..36a1c3f808ce8 100644 --- a/site/src/api/queries/organizations.ts +++ b/site/src/api/queries/organizations.ts @@ -306,6 +306,7 @@ export const organizationsPermissions = ( export const workspacePermissionsByOrganization = ( organizationIds: string[] | undefined, + userId: string, ) => { if (!organizationIds) { return { enabled: false }; @@ -315,10 +316,9 @@ export const workspacePermissionsByOrganization = ( queryKey: ["workspaces", organizationIds.sort(), "permissions"], queryFn: async () => { const prefixedChecks = organizationIds.flatMap((orgId) => - Object.entries(workspacePermissionChecks(orgId)).map(([key, val]) => [ - `${orgId}.${key}`, - val, - ]), + Object.entries(workspacePermissionChecks(orgId, userId)).map( + ([key, val]) => [`${orgId}.${key}`, val], + ), ); const response = await API.checkAuthorization({ diff --git a/site/src/modules/permissions/workspaces.ts b/site/src/modules/permissions/workspaces.ts index 9ebb75d4790de..b0834877e8e6c 100644 --- a/site/src/modules/permissions/workspaces.ts +++ b/site/src/modules/permissions/workspaces.ts @@ -1,10 +1,13 @@ -export const workspacePermissionChecks = (organizationId: string) => +export const workspacePermissionChecks = ( + organizationId: string, + userId: string, +) => ({ - createWorkspaceForUser: { + createWorkspace: { object: { resource_type: "workspace", organization_id: organizationId, - owner_id: "*", + owner_id: userId, }, action: "create", }, diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index 26f1808b83152..150a79bd69487 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -17,10 +17,6 @@ import { Loader } from "components/Loader/Loader"; import { useAuthenticated } from "contexts/auth/RequireAuth"; import { useEffectEvent } from "hooks/hookPolyfills"; import { useDashboard } from "modules/dashboard/useDashboard"; -import { - type WorkspacePermissions, - workspacePermissionChecks, -} from "modules/permissions/workspaces"; import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName"; import { type FC, useCallback, useEffect, useRef, useState } from "react"; import { Helmet } from "react-helmet-async"; @@ -30,6 +26,7 @@ import { pageTitle } from "utils/page"; import type { AutofillBuildParameter } from "utils/richParameters"; import { paramsUsedToCreateWorkspace } from "utils/workspace"; import { CreateWorkspacePageView } from "./CreateWorkspacePageView"; +import { type CreateWSPermissions, createWorkspaceChecks } from "./permissions"; export const createWorkspaceModes = ["form", "auto", "duplicate"] as const; export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number]; @@ -67,7 +64,7 @@ const CreateWorkspacePage: FC = () => { const permissionsQuery = useQuery( templateQuery.data ? checkAuthorization({ - checks: workspacePermissionChecks(templateQuery.data.organization_id), + checks: createWorkspaceChecks(templateQuery.data.organization_id), }) : { enabled: false }, ); @@ -209,7 +206,7 @@ const CreateWorkspacePage: FC = () => { externalAuthPollingState={externalAuthPollingState} startPollingExternalAuth={startPollingExternalAuth} hasAllRequiredExternalAuth={hasAllRequiredExternalAuth} - permissions={permissionsQuery.data as WorkspacePermissions} + permissions={permissionsQuery.data as CreateWSPermissions} parameters={realizedParameters as TemplateVersionParameter[]} presets={templateVersionPresetsQuery.data ?? []} creatingWorkspace={createWorkspaceMutation.isLoading} diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 660580b5b80b8..656e18563eb60 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -28,7 +28,6 @@ import { Stack } from "components/Stack/Stack"; import { Switch } from "components/Switch/Switch"; import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete"; import { type FormikContextType, useFormik } from "formik"; -import type { WorkspacePermissions } from "modules/permissions/workspaces"; import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName"; import { type FC, useCallback, useEffect, useMemo, useState } from "react"; import { @@ -47,7 +46,7 @@ import type { ExternalAuthPollingState, } from "./CreateWorkspacePage"; import { ExternalAuthButton } from "./ExternalAuthButton"; - +import type { CreateWSPermissions } from "./permissions"; export const Language = { duplicationWarning: "Duplicating a workspace only copies its parameters. No state from the old workspace is copied over.", @@ -69,7 +68,7 @@ export interface CreateWorkspacePageViewProps { parameters: TypesGen.TemplateVersionParameter[]; autofillParameters: AutofillBuildParameter[]; presets: TypesGen.Preset[]; - permissions: WorkspacePermissions; + permissions: CreateWSPermissions; creatingWorkspace: boolean; onCancel: () => void; onSubmit: ( diff --git a/site/src/pages/CreateWorkspacePage/permissions.ts b/site/src/pages/CreateWorkspacePage/permissions.ts new file mode 100644 index 0000000000000..07bad5031ddc2 --- /dev/null +++ b/site/src/pages/CreateWorkspacePage/permissions.ts @@ -0,0 +1,16 @@ +export const createWorkspaceChecks = (organizationId: string) => + ({ + createWorkspaceForUser: { + object: { + resource_type: "workspace", + organization_id: organizationId, + owner_id: "*", + }, + action: "create", + }, + }) as const; + +export type CreateWSPermissions = Record< + keyof ReturnType, + boolean +>; diff --git a/site/src/pages/TemplatePage/TemplateLayout.tsx b/site/src/pages/TemplatePage/TemplateLayout.tsx index 93d25d6f591db..78b8822b6fa42 100644 --- a/site/src/pages/TemplatePage/TemplateLayout.tsx +++ b/site/src/pages/TemplatePage/TemplateLayout.tsx @@ -5,6 +5,7 @@ import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Loader } from "components/Loader/Loader"; import { Margins } from "components/Margins/Margins"; import { TabLink, Tabs, TabsList } from "components/Tabs/Tabs"; +import { useAuthenticated } from "contexts/auth/RequireAuth"; import { workspacePermissionChecks } from "modules/permissions/workspaces"; import { type FC, @@ -73,6 +74,7 @@ export const TemplateLayout: FC = ({ children = , }) => { const navigate = useNavigate(); + const { user: me } = useAuthenticated(); const { organization: organizationName = "default", template: templateName } = useParams() as { organization?: string; template: string }; const { data, error, isLoading } = useQuery({ @@ -81,7 +83,7 @@ export const TemplateLayout: FC = ({ }); const workspacePermissionsQuery = useQuery( checkAuthorization({ - checks: workspacePermissionChecks(organizationName), + checks: workspacePermissionChecks(organizationName, me.id), }), ); diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.stories.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.stories.tsx index 4acd28446631f..b70dd4204b1ba 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.stories.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.stories.tsx @@ -14,7 +14,7 @@ const meta: Meta = { canUpdateTemplate: true, }, workspacePermissions: { - createWorkspaceForUser: true, + createWorkspace: true, }, }, }; @@ -35,7 +35,7 @@ export const CanNotUpdate: Story = { export const CannotCreateWorkspace: Story = { args: { workspacePermissions: { - createWorkspaceForUser: false, + createWorkspace: false, }, }, }; diff --git a/site/src/pages/TemplatePage/TemplatePageHeader.tsx b/site/src/pages/TemplatePage/TemplatePageHeader.tsx index 1d70379e75f43..918db1bfe9368 100644 --- a/site/src/pages/TemplatePage/TemplatePageHeader.tsx +++ b/site/src/pages/TemplatePage/TemplatePageHeader.tsx @@ -179,17 +179,16 @@ export const TemplatePageHeader: FC = ({ - {!template.deprecated && - workspacePermissions.createWorkspaceForUser && ( - - )} + {!template.deprecated && workspacePermissions.createWorkspace && ( + + )} {permissions.canUpdateTemplate && ( { - const { permissions } = useAuthenticated(); + const { permissions, user: me } = useAuthenticated(); const { showOrganizations } = useDashboard(); const searchParamsResult = useSearchParams(); @@ -30,6 +30,7 @@ export const TemplatesPage: FC = () => { const workspacePermissionsQuery = useQuery( workspacePermissionsByOrganization( templatesQuery.data?.map((template) => template.organization_id), + me.id, ), ); diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.stories.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.stories.tsx index bed6b72c5d719..d259113286f88 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.stories.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.stories.tsx @@ -76,7 +76,7 @@ export const WithTemplates: Story = { examples: [], workspacePermissions: { [MockTemplate.organization_id]: { - createWorkspaceForUser: true, + createWorkspace: true, }, }, }, @@ -94,7 +94,7 @@ export const CannotCreateWorkspaces: Story = { ...WithTemplates.args, workspacePermissions: { [MockTemplate.organization_id]: { - createWorkspaceForUser: false, + createWorkspace: false, }, }, }, diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index fbf3743043c08..abd867bfcb60a 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -160,7 +160,7 @@ const TemplateRow: FC = ({ {template.deprecated ? ( ) : workspacePermissions?.[template.organization_id] - ?.createWorkspaceForUser ? ( + ?.createWorkspace ? ( { // each hook. const searchParamsResult = useSafeSearchParams(); const pagination = usePagination({ searchParamsResult }); - const { permissions } = useAuthenticated(); + const { permissions, user: me } = useAuthenticated(); const { entitlements } = useDashboard(); const templatesQuery = useQuery(templates()); @@ -48,6 +48,7 @@ const WorkspacesPage: FC = () => { const orgPermissionsQuery = useQuery( workspacePermissionsByOrganization( templatesQuery.data?.map((template) => template.organization_id), + me.id, ), ); @@ -59,7 +60,7 @@ const WorkspacesPage: FC = () => { return templatesQuery.data.filter((template) => { const orgPermission = orgPermissionsQuery.data[template.organization_id]; - return orgPermission?.createWorkspaceForUser; + return orgPermission?.createWorkspace; }); }, [templatesQuery.data, orgPermissionsQuery.data]); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy