diff --git a/docs/user-guides/shared-workspaces.md b/docs/user-guides/shared-workspaces.md index 467a9dbb8b..6770089012 100644 --- a/docs/user-guides/shared-workspaces.md +++ b/docs/user-guides/shared-workspaces.md @@ -40,6 +40,9 @@ To remove sharing from a workspace: - `coder sharing remove --group contractor` - Workspace is no longer shared with the group `contractor`. +> [!Important] +> The workspace must be restarted for the user or group removal to take effect. + To show who a workspace is shared with: - `coder sharing show ` @@ -61,3 +64,4 @@ To list shared workspaces: - `use` allows for connection via SSH and apps, the ability to start and stop the workspace, view logs and stats, and update on start when required. - `admin` allows for all of the above, as well as the ability to rename the workspace, update at any time, and invite others with the `use` role. - Neither role allows for the user to delete the workspace. +- After removing a user/group, a workspace restart is required for the removal to take effect. diff --git a/site/src/modules/workspaces/WorkspaceSharingForm/WorkspaceSharingForm.tsx b/site/src/modules/workspaces/WorkspaceSharingForm/WorkspaceSharingForm.tsx index a66f82000c..bbc70a039d 100644 --- a/site/src/modules/workspaces/WorkspaceSharingForm/WorkspaceSharingForm.tsx +++ b/site/src/modules/workspaces/WorkspaceSharingForm/WorkspaceSharingForm.tsx @@ -5,6 +5,7 @@ import type { WorkspaceRole, WorkspaceUser, } from "api/typesGenerated"; +import { Alert } from "components/Alert/Alert"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Avatar } from "components/Avatar/Avatar"; import { AvatarData } from "components/Avatar/AvatarData"; @@ -149,6 +150,7 @@ interface WorkspaceSharingFormProps { onRemoveGroup: (group: Group) => void; addMemberForm?: ReactNode; isCompact?: boolean; + showRestartWarning?: boolean; } export const WorkspaceSharingForm: FC = ({ @@ -163,6 +165,7 @@ export const WorkspaceSharingForm: FC = ({ onRemoveGroup, addMemberForm, isCompact, + showRestartWarning, }) => { const isEmpty = Boolean( workspaceACL && @@ -307,6 +310,11 @@ export const WorkspaceSharingForm: FC = ({
{Boolean(error) && } {canUpdatePermissions && addMemberForm} + {showRestartWarning && ( + + Workspace restart required for the removal to take effect. + + )}
{tableHeader}
@@ -321,6 +329,11 @@ export const WorkspaceSharingForm: FC = ({
{Boolean(error) && } {canUpdatePermissions && addMemberForm} + {showRestartWarning && ( + + Workspace restart required for the removal to take effect. + + )} {tableHeader} {tableBody} diff --git a/site/src/modules/workspaces/WorkspaceSharingForm/useWorkspaceSharing.ts b/site/src/modules/workspaces/WorkspaceSharingForm/useWorkspaceSharing.ts index 819eaecd0b..6c32420138 100644 --- a/site/src/modules/workspaces/WorkspaceSharingForm/useWorkspaceSharing.ts +++ b/site/src/modules/workspaces/WorkspaceSharingForm/useWorkspaceSharing.ts @@ -11,6 +11,7 @@ import type { WorkspaceUser, } from "api/typesGenerated"; import { displaySuccess } from "components/GlobalSnackbar/utils"; +import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "react-query"; /** @@ -20,6 +21,7 @@ import { useMutation, useQuery, useQueryClient } from "react-query"; */ export function useWorkspaceSharing(workspace: Workspace) { const queryClient = useQueryClient(); + const [hasRemovedMember, setHasRemovedMember] = useState(false); const workspaceACLQuery = useQuery(workspaceACL(workspace.id)); @@ -41,6 +43,7 @@ export function useWorkspaceSharing(workspace: Workspace) { userId: user.id, role, }); + setHasRemovedMember(false); displaySuccess("User added to workspace successfully!"); reset(); }; @@ -60,6 +63,7 @@ export function useWorkspaceSharing(workspace: Workspace) { userId: user.id, role: "", }); + setHasRemovedMember(true); displaySuccess("User removed successfully!"); }; @@ -73,6 +77,7 @@ export function useWorkspaceSharing(workspace: Workspace) { groupId: group.id, role, }); + setHasRemovedMember(false); displaySuccess("Group added to workspace successfully!"); reset(); }; @@ -92,6 +97,7 @@ export function useWorkspaceSharing(workspace: Workspace) { groupId: group.id, role: "", }); + setHasRemovedMember(true); displaySuccess("Group removed successfully!"); }; @@ -108,6 +114,7 @@ export function useWorkspaceSharing(workspace: Workspace) { isLoading: workspaceACLQuery.isLoading, error: workspaceACLQuery.error, mutationError, + hasRemovedMember, // User actions addUser, updateUser, diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/ShareButton.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/ShareButton.tsx index 58ef00770f..c19ee06172 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/ShareButton.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/ShareButton.tsx @@ -42,6 +42,7 @@ export const ShareButton: FC = ({ updatingGroupId={sharing.updatingGroupId} onUpdateGroup={sharing.updateGroup} onRemoveGroup={sharing.removeGroup} + showRestartWarning={sharing.hasRemovedMember} isCompact addMemberForm={ { onUpdateGroup={sharing.updateGroup} updatingGroupId={sharing.updatingGroupId} onRemoveGroup={sharing.removeGroup} + hasRemovedMember={sharing.hasRemovedMember} /> ); diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPageView.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPageView.tsx index 8573ca1863..2d44c1fa8c 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPageView.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/WorkspaceSharingPageView.tsx @@ -30,6 +30,7 @@ interface WorkspaceSharingPageViewProps { onUpdateGroup: (group: WorkspaceGroup, role: WorkspaceRole) => void; updatingGroupId?: WorkspaceGroup["id"] | undefined; onRemoveGroup: (group: Group) => void; + hasRemovedMember?: boolean; } export const WorkspaceSharingPageView: FC = ({ @@ -47,6 +48,7 @@ export const WorkspaceSharingPageView: FC = ({ updatingGroupId, onUpdateGroup, onRemoveGroup, + hasRemovedMember, }) => { return ( = ({ updatingGroupId={updatingGroupId} onUpdateGroup={onUpdateGroup} onRemoveGroup={onRemoveGroup} + showRestartWarning={hasRemovedMember} addMemberForm={