fix: disable task sharing (#21867)

This commit is contained in:
ケイラ
2026-02-03 09:43:40 -07:00
committed by GitHub
parent a16debee76
commit 7fd13019e5
9 changed files with 35 additions and 64 deletions
+11
View File
@@ -2353,6 +2353,17 @@ func (api *API) patchWorkspaceACL(rw http.ResponseWriter, r *http.Request) {
return
}
// Don't allow adding new groups or users to a workspace associated with a
// task. Sharing a task workspace without sharing the task itself is a broken
// half measure that we don't want to support right now. To be fixed!
if workspace.TaskID.Valid {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Task workspaces cannot be shared.",
Detail: "This workspace is managed by a task. Task sharing has not yet been implemented.",
})
return
}
apiKey := httpmw.APIKey(r)
if _, ok := req.UserRoles[apiKey.UserID.String()]; ok {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
@@ -7,7 +7,6 @@ import {
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "components/DropdownMenu/DropdownMenu";
import { CoderIcon } from "components/Icons/CoderIcon";
@@ -22,13 +21,7 @@ import {
} from "components/Tooltip/Tooltip";
import { useAuthenticated } from "hooks";
import { useSearchParamsKey } from "hooks/useSearchParamsKey";
import {
EditIcon,
EllipsisIcon,
PanelLeftIcon,
Share2Icon,
TrashIcon,
} from "lucide-react";
import { EditIcon, EllipsisIcon, PanelLeftIcon, TrashIcon } from "lucide-react";
import { type FC, useState } from "react";
import { useQuery } from "react-query";
import { Link as RouterLink, useNavigate, useParams } from "react-router";
@@ -234,15 +227,6 @@ const TaskSidebarMenuItem: FC<TaskSidebarMenuItemProps> = ({ task }) => {
<DropdownMenuContent align="end">
<DropdownMenuGroup>
<DropdownMenuItem asChild>
<RouterLink
to={`/@${task.owner_name}/${task.workspace_name}/settings/sharing`}
>
<Share2Icon />
Share
</RouterLink>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="text-content-destructive focus:text-content-destructive"
onClick={(e) => {
@@ -141,6 +141,7 @@ export const RoleSelectField: FC<RoleSelectFieldProps> = ({
interface WorkspaceSharingFormProps {
workspaceACL: WorkspaceACL | undefined;
canUpdatePermissions: boolean;
isTaskWorkspace: boolean;
error: unknown;
onUpdateUser: (user: WorkspaceUser, role: WorkspaceRole) => void;
updatingUserId: WorkspaceUser["id"] | undefined;
@@ -156,6 +157,7 @@ interface WorkspaceSharingFormProps {
export const WorkspaceSharingForm: FC<WorkspaceSharingFormProps> = ({
workspaceACL,
canUpdatePermissions,
isTaskWorkspace,
error,
updatingUserId,
onUpdateUser,
@@ -185,14 +187,24 @@ export const WorkspaceSharingForm: FC<WorkspaceSharingFormProps> = ({
const tableBody = (
<TableBody>
{!workspaceACL ? (
{isTaskWorkspace ? (
<TableRow>
<TableCell colSpan={999}>
<EmptyState
message="Task workspaces cannot be shared"
description="This workspace is managed by a task. Task sharing has not yet been implemented."
isCompact={isCompact}
/>
</TableCell>
</TableRow>
) : !workspaceACL ? (
<TableLoader />
) : isEmpty ? (
<TableRow>
<TableCell colSpan={999}>
<EmptyState
message="No shared members or groups yet"
description="Add a member or group using the controls above"
description="Add a member or group using the controls above."
isCompact={isCompact}
/>
</TableCell>
+1 -7
View File
@@ -5,7 +5,6 @@ import { workspaceBuildParameters } from "api/queries/workspaceBuilds";
import {
startWorkspace,
workspaceByOwnerAndName,
workspacePermissions,
} from "api/queries/workspaces";
import type {
Workspace,
@@ -79,7 +78,6 @@ const TaskPage = () => {
return state.error ? false : 5_000;
},
});
const { data: permissions } = useQuery(workspacePermissions(workspace));
const refetch = taskQuery.error ? taskQuery.refetch : workspaceQuery.refetch;
const error = taskQuery.error ?? workspaceQuery.error;
const waitingStatuses: WorkspaceStatus[] = ["starting", "pending"];
@@ -200,11 +198,7 @@ const TaskPage = () => {
<TaskPageLayout>
<title>{pageTitle(task.display_name)}</title>
<TaskTopbar
task={task}
workspace={workspace}
canUpdatePermissions={permissions?.updateWorkspace ?? false}
/>
<TaskTopbar task={task} workspace={workspace} />
{content}
<ModifyPromptDialog
+2 -16
View File
@@ -16,21 +16,12 @@ import {
} from "lucide-react";
import type { FC } from "react";
import { Link as RouterLink } from "react-router";
import { ShareButton } from "../WorkspacePage/WorkspaceActions/ShareButton";
import { TaskStartupWarningButton } from "./TaskStartupWarningButton";
import { TaskStatusLink } from "./TaskStatusLink";
type TaskTopbarProps = {
task: Task;
workspace: Workspace;
canUpdatePermissions: boolean;
};
type TaskTopbarProps = { task: Task; workspace: Workspace };
export const TaskTopbar: FC<TaskTopbarProps> = ({
task,
workspace,
canUpdatePermissions,
}) => {
export const TaskTopbar: FC<TaskTopbarProps> = ({ task, workspace }) => {
return (
<header className="flex flex-shrink-0 items-center gap-2 p-3 border-solid border-border border-0 border-b">
<TooltipProvider>
@@ -79,11 +70,6 @@ export const TaskTopbar: FC<TaskTopbarProps> = ({
</Tooltip>
</TooltipProvider>
<ShareButton
workspace={workspace}
canUpdatePermissions={canUpdatePermissions}
/>
<Button asChild variant="outline" size="sm">
<RouterLink to={`/@${workspace.owner_name}/${workspace.name}`}>
<LayoutPanelTopIcon />
@@ -248,7 +248,7 @@ export const OpenKebabMenu: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const kebabButtons = await canvas.findAllByRole("button", {
name: /open task actions/i,
name: /show task actions/i,
});
await userEvent.click(kebabButtons[0]);
},
@@ -262,7 +262,7 @@ export const OpenDeleteDialog: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const kebabButtons = await canvas.findAllByRole("button", {
name: /open task actions/i,
name: /show task actions/i,
});
await userEvent.click(kebabButtons[0]);
+2 -20
View File
@@ -9,7 +9,6 @@ import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "components/DropdownMenu/DropdownMenu";
import { Skeleton } from "components/Skeleton/Skeleton";
@@ -26,12 +25,7 @@ import {
TableRowSkeleton,
} from "components/TableLoader/TableLoader";
import { useClickableTableRow } from "hooks";
import {
EllipsisVertical,
RotateCcwIcon,
Share2Icon,
TrashIcon,
} from "lucide-react";
import { EllipsisVertical, RotateCcwIcon, TrashIcon } from "lucide-react";
import { TaskDeleteDialog } from "modules/tasks/TaskDeleteDialog/TaskDeleteDialog";
import { TaskStatus } from "modules/tasks/TaskStatus/TaskStatus";
import { type FC, type ReactNode, useState } from "react";
@@ -266,22 +260,10 @@ const TaskRow: FC<TaskRowProps> = ({
onClick={(e) => e.stopPropagation()}
>
<EllipsisVertical aria-hidden="true" />
<span className="sr-only">Open task actions</span>
<span className="sr-only">Show task actions</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation();
navigate(
`/@${task.owner_name}/${task.workspace_name}/settings/sharing`,
);
}}
>
<Share2Icon />
Share
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="text-content-destructive focus:text-content-destructive"
onClick={(e) => {
@@ -35,6 +35,7 @@ export const ShareButton: FC<ShareButtonProps> = ({
<WorkspaceSharingForm
workspaceACL={sharing.workspaceACL}
canUpdatePermissions={canUpdatePermissions}
isTaskWorkspace={Boolean(workspace.task_id)}
error={sharing.error ?? sharing.mutationError}
updatingUserId={sharing.updatingUserId}
onUpdateUser={sharing.updateUser}
@@ -54,6 +54,7 @@ export const WorkspaceSharingPageView: FC<WorkspaceSharingPageViewProps> = ({
<WorkspaceSharingForm
workspaceACL={workspaceACL}
canUpdatePermissions={canUpdatePermissions}
isTaskWorkspace={Boolean(workspace.task_id)}
error={error}
updatingUserId={updatingUserId}
onUpdateUser={onUpdateUser}