fix: set permissions for experimental Createworkspace page (#17254)

This commit is contained in:
Jaayden Halko
2025-04-04 09:59:01 -04:00
committed by GitHub
parent 510bc37cbc
commit ae67e33c66
13 changed files with 54 additions and 47 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ export const workspacePermissionChecks = (
userId: string,
) =>
({
createWorkspace: {
createWorkspaceForUserID: {
object: {
resource_type: "workspace",
organization_id: organizationId,
@@ -26,7 +26,10 @@ 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";
import {
type CreateWorkspacePermissions,
createWorkspaceChecks,
} from "./permissions";
export const createWorkspaceModes = ["form", "auto", "duplicate"] as const;
export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number];
@@ -206,7 +209,7 @@ const CreateWorkspacePage: FC = () => {
externalAuthPollingState={externalAuthPollingState}
startPollingExternalAuth={startPollingExternalAuth}
hasAllRequiredExternalAuth={hasAllRequiredExternalAuth}
permissions={permissionsQuery.data as CreateWSPermissions}
permissions={permissionsQuery.data as CreateWorkspacePermissions}
parameters={realizedParameters as TemplateVersionParameter[]}
presets={templateVersionPresetsQuery.data ?? []}
creatingWorkspace={createWorkspaceMutation.isLoading}
@@ -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";
@@ -32,6 +28,10 @@ import { paramsUsedToCreateWorkspace } from "utils/workspace";
import { CreateWorkspacePageViewExperimental } from "./CreateWorkspacePageViewExperimental";
export const createWorkspaceModes = ["form", "auto", "duplicate"] as const;
export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number];
import {
type CreateWorkspacePermissions,
createWorkspaceChecks,
} from "./permissions";
export type ExternalAuthPollingState = "idle" | "polling" | "abandoned";
@@ -66,10 +66,7 @@ const CreateWorkspacePageExperimental: FC = () => {
const permissionsQuery = useQuery(
templateQuery.data
? checkAuthorization({
checks: workspacePermissionChecks(
templateQuery.data.organization_id,
me.id,
),
checks: createWorkspaceChecks(templateQuery.data.organization_id),
})
: { enabled: false },
);
@@ -211,7 +208,7 @@ const CreateWorkspacePageExperimental: FC = () => {
externalAuthPollingState={externalAuthPollingState}
startPollingExternalAuth={startPollingExternalAuth}
hasAllRequiredExternalAuth={hasAllRequiredExternalAuth}
permissions={permissionsQuery.data as WorkspacePermissions}
permissions={permissionsQuery.data as CreateWorkspacePermissions}
parameters={realizedParameters as TemplateVersionParameter[]}
presets={templateVersionPresetsQuery.data ?? []}
creatingWorkspace={createWorkspaceMutation.isLoading}
@@ -27,7 +27,7 @@ const meta: Meta<typeof CreateWorkspacePageView> = {
hasAllRequiredExternalAuth: true,
mode: "form",
permissions: {
createWorkspaceForUser: true,
createWorkspaceForAny: true,
},
onCancel: action("onCancel"),
},
@@ -46,7 +46,7 @@ import type {
ExternalAuthPollingState,
} from "./CreateWorkspacePage";
import { ExternalAuthButton } from "./ExternalAuthButton";
import type { CreateWSPermissions } from "./permissions";
import type { CreateWorkspacePermissions } from "./permissions";
export const Language = {
duplicationWarning:
"Duplicating a workspace only copies its parameters. No state from the old workspace is copied over.",
@@ -68,7 +68,7 @@ export interface CreateWorkspacePageViewProps {
parameters: TypesGen.TemplateVersionParameter[];
autofillParameters: AutofillBuildParameter[];
presets: TypesGen.Preset[];
permissions: CreateWSPermissions;
permissions: CreateWorkspacePermissions;
creatingWorkspace: boolean;
onCancel: () => void;
onSubmit: (
@@ -255,7 +255,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
<FormSection
title="General"
description={
permissions.createWorkspaceForUser
permissions.createWorkspaceForAny
? "The name of the workspace and its owner. Only admins can create workspaces for other users."
: "The name of your new workspace."
}
@@ -300,7 +300,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
</FormHelperText>
</div>
{permissions.createWorkspaceForUser && (
{permissions.createWorkspaceForAny && (
<UserAutocomplete
value={owner}
onChange={(user) => {
@@ -15,7 +15,6 @@ import { Stack } from "components/Stack/Stack";
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
import { type FormikContextType, useFormik } from "formik";
import { ArrowLeft } from "lucide-react";
import type { WorkspacePermissions } from "modules/permissions/workspaces";
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
import {
type FC,
@@ -37,7 +36,7 @@ import type {
ExternalAuthPollingState,
} from "./CreateWorkspacePage";
import { ExternalAuthButton } from "./ExternalAuthButton";
import type { CreateWorkspacePermissions } from "./permissions";
export const Language = {
duplicationWarning:
"Duplicating a workspace only copies its parameters. No state from the old workspace is copied over.",
@@ -59,7 +58,7 @@ export interface CreateWorkspacePageViewExperimentalProps {
parameters: TypesGen.TemplateVersionParameter[];
autofillParameters: AutofillBuildParameter[];
presets: TypesGen.Preset[];
permissions: WorkspacePermissions;
permissions: CreateWorkspacePermissions;
creatingWorkspace: boolean;
onCancel: () => void;
onSubmit: (
@@ -253,7 +252,7 @@ export const CreateWorkspacePageViewExperimental: FC<
<hgroup>
<h2 className="text-xl font-semibold m-0">General</h2>
<p className="text-sm text-content-secondary mt-0">
{permissions.createWorkspace
{permissions.createWorkspaceForAny
? "Only admins can create workspaces for other users."
: "The name of your new workspace."}
</p>
@@ -300,7 +299,7 @@ export const CreateWorkspacePageViewExperimental: FC<
</div>
</div>
</div>
{permissions.createWorkspace && (
{permissions.createWorkspaceForAny && (
<div className="flex flex-col gap-2 flex-1">
<Label className="text-sm" htmlFor={`${id}-workspace-name`}>
Owner
@@ -1,6 +1,6 @@
export const createWorkspaceChecks = (organizationId: string) =>
({
createWorkspaceForUser: {
createWorkspaceForAny: {
object: {
resource_type: "workspace",
organization_id: organizationId,
@@ -10,7 +10,7 @@ export const createWorkspaceChecks = (organizationId: string) =>
},
}) as const;
export type CreateWSPermissions = Record<
export type CreateWorkspacePermissions = Record<
keyof ReturnType<typeof createWorkspaceChecks>,
boolean
>;
@@ -6,7 +6,10 @@ 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 WorkspacePermissions,
workspacePermissionChecks,
} from "modules/permissions/workspaces";
import {
type FC,
type PropsWithChildren,
@@ -113,7 +116,9 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
template={data.template}
activeVersion={data.activeVersion}
permissions={data.permissions}
workspacePermissions={workspacePermissionsQuery.data}
workspacePermissions={
workspacePermissionsQuery.data as WorkspacePermissions
}
onDeleteTemplate={() => {
navigate("/templates");
}}
@@ -14,7 +14,7 @@ const meta: Meta<typeof TemplatePageHeader> = {
canUpdateTemplate: true,
},
workspacePermissions: {
createWorkspace: true,
createWorkspaceForUserID: true,
},
},
};
@@ -35,7 +35,7 @@ export const CanNotUpdate: Story = {
export const CannotCreateWorkspace: Story = {
args: {
workspacePermissions: {
createWorkspace: false,
createWorkspaceForUserID: false,
},
},
};
@@ -31,6 +31,7 @@ import {
import { Pill } from "components/Pill/Pill";
import { Stack } from "components/Stack/Stack";
import { linkToTemplate, useLinks } from "modules/navigation";
import type { WorkspacePermissions } from "modules/permissions/workspaces";
import type { FC } from "react";
import { useQuery } from "react-query";
import { Link as RouterLink, useNavigate } from "react-router-dom";
@@ -158,7 +159,7 @@ export type TemplatePageHeaderProps = {
template: Template;
activeVersion: TemplateVersion;
permissions: AuthorizationResponse;
workspacePermissions: AuthorizationResponse;
workspacePermissions: WorkspacePermissions;
onDeleteTemplate: () => void;
};
@@ -179,16 +180,17 @@ export const TemplatePageHeader: FC<TemplatePageHeaderProps> = ({
<PageHeader
actions={
<>
{!template.deprecated && workspacePermissions.createWorkspace && (
<Button
variant="contained"
startIcon={<AddIcon />}
component={RouterLink}
to={`${templateLink}/workspace`}
>
Create Workspace
</Button>
)}
{!template.deprecated &&
workspacePermissions.createWorkspaceForUserID && (
<Button
variant="contained"
startIcon={<AddIcon />}
component={RouterLink}
to={`${templateLink}/workspace`}
>
Create Workspace
</Button>
)}
{permissions.canUpdateTemplate && (
<TemplateMenu
@@ -76,7 +76,7 @@ export const WithTemplates: Story = {
examples: [],
workspacePermissions: {
[MockTemplate.organization_id]: {
createWorkspace: true,
createWorkspaceForUserID: true,
},
},
},
@@ -94,7 +94,7 @@ export const CannotCreateWorkspaces: Story = {
...WithTemplates.args,
workspacePermissions: {
[MockTemplate.organization_id]: {
createWorkspace: false,
createWorkspaceForUserID: false,
},
},
},
@@ -160,7 +160,7 @@ const TemplateRow: FC<TemplateRowProps> = ({
{template.deprecated ? (
<DeprecatedBadge />
) : workspacePermissions?.[template.organization_id]
?.createWorkspace ? (
?.createWorkspaceForUserID ? (
<MuiButton
size="small"
css={styles.actionButton}
@@ -45,7 +45,7 @@ const WorkspacesPage: FC = () => {
const templatesQuery = useQuery(templates());
const orgPermissionsQuery = useQuery(
const workspacePermissionsQuery = useQuery(
workspacePermissionsByOrganization(
templatesQuery.data?.map((template) => template.organization_id),
me.id,
@@ -54,15 +54,16 @@ const WorkspacesPage: FC = () => {
// Filter templates based on workspace creation permission
const filteredTemplates = useMemo(() => {
if (!templatesQuery.data || !orgPermissionsQuery.data) {
if (!templatesQuery.data || !workspacePermissionsQuery.data) {
return templatesQuery.data;
}
return templatesQuery.data.filter((template) => {
const orgPermission = orgPermissionsQuery.data[template.organization_id];
return orgPermission?.createWorkspace;
const workspacePermission =
workspacePermissionsQuery.data[template.organization_id];
return workspacePermission?.createWorkspaceForUserID;
});
}, [templatesQuery.data, orgPermissionsQuery.data]);
}, [templatesQuery.data, workspacePermissionsQuery.data]);
const filterProps = useWorkspacesFilter({
searchParamsResult,