Skip to content

Commit 7a5a51e

Browse files
authored
Minor workspace issues fix (#1413)
1 parent 0919cf4 commit 7a5a51e

File tree

6 files changed

+109
-91
lines changed

6 files changed

+109
-91
lines changed

web_ui/packages/core/src/users/hook/use-users.hook.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ export const useUsers = (): UseUsers => {
367367
if (FEATURE_FLAG_MANAGE_USERS_ROLES) {
368368
await queryClient.invalidateQueries({ queryKey: QUERY_KEYS.USERS(organizationId) });
369369
await queryClient.invalidateQueries({ queryKey: QUERY_KEYS.ACTIVE_USER(organizationId) });
370+
await queryClient.invalidateQueries({ queryKey: QUERY_KEYS.WORKSPACES(organizationId) });
370371
} else {
371372
await queryClient.invalidateQueries({
372373
queryKey: QUERY_KEYS.USER_ROLES(organizationId, userId, resourceType),

web_ui/src/pages/landing-page/workspaces-tabs/workspaces-tabs.component.tsx

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// LIMITED EDGE SOFTWARE DISTRIBUTION LICENSE
33

44
import { useFeatureFlags } from '@geti/core/src/feature-flags/hooks/use-feature-flags.hook';
5+
import { useActiveUser } from '@geti/core/src/users/hook/use-users.hook';
6+
import { isOrganizationAdmin } from '@geti/core/src/users/user-role-utils';
7+
import { RESOURCE_TYPE } from '@geti/core/src/users/users.interface';
58
import { useWorkspacesApi } from '@geti/core/src/workspaces/hooks/use-workspaces.hook';
69
import { WorkspaceEntity } from '@geti/core/src/workspaces/services/workspaces.interface';
710
import { ActionButton, Flex, Item, Loading, TabList, TabPanels, Tabs, Tooltip, TooltipTrigger } from '@geti/ui';
@@ -26,6 +29,7 @@ export const WorkspacesTabs = () => {
2629
const { organizationId } = useOrganizationIdentifier();
2730
const { workspaces, selectWorkspace, selectedWorkspaceId, handleSelectWorkspace } = useWorkspacesTabs();
2831
const { FEATURE_FLAG_WORKSPACE_ACTIONS } = useFeatureFlags();
32+
const { data: activeUser } = useActiveUser(organizationId);
2933
const createWorkspaceDialogState = useOverlayTriggerState({});
3034

3135
const { useCreateWorkspaceMutation } = useWorkspacesApi(organizationId);
@@ -51,38 +55,44 @@ export const WorkspacesTabs = () => {
5155
orientation={'vertical'}
5256
onSelectionChange={handleSelectWorkspace}
5357
>
54-
<Flex width={'100%'} alignItems={'center'} UNSAFE_className={classes.tabWrapper}>
55-
<TabList UNSAFE_className={classes.tabList}>
56-
{(item: TabItem) => (
57-
<Item textValue={item.name as string} key={item.key}>
58-
<>
59-
<Flex alignItems={'center'}>
60-
{selectedWorkspaceId === item.key && FEATURE_FLAG_WORKSPACE_ACTIONS ? (
61-
<HasPermission
62-
operations={[OPERATION.WORKSPACE_MANAGEMENT]}
63-
specialCondition={true}
64-
Fallback={
65-
<CustomTabItem
66-
name={item.name as string}
67-
isMoreIconVisible={false}
58+
<Flex width={'100%'} alignItems={'center'} UNSAFE_className={classes.tabWrapper} gap={'size-200'}>
59+
<div className={classes.tabListScrollContainer}>
60+
<TabList UNSAFE_className={classes.tabList}>
61+
{(item: TabItem) => (
62+
<Item textValue={item.name as string} key={item.key}>
63+
<>
64+
<Flex alignItems={'center'}>
65+
{selectedWorkspaceId === item.key && FEATURE_FLAG_WORKSPACE_ACTIONS ? (
66+
<HasPermission
67+
operations={[OPERATION.WORKSPACE_MANAGEMENT]}
68+
resources={[{ type: RESOURCE_TYPE.WORKSPACE, id: item.id }]}
69+
specialCondition={
70+
activeUser !== undefined &&
71+
isOrganizationAdmin(activeUser, organizationId)
72+
}
73+
Fallback={
74+
<CustomTabItem
75+
name={item.name as string}
76+
isMoreIconVisible={false}
77+
/>
78+
}
79+
>
80+
<CustomTabItemWithMenu
81+
workspace={selectedWorkspace as WorkspaceEntity}
82+
isMoreIconVisible={item.key === selectedWorkspaceId}
83+
workspaces={workspaces}
84+
selectWorkspace={selectWorkspace}
6885
/>
69-
}
70-
>
71-
<CustomTabItemWithMenu
72-
workspace={selectedWorkspace as WorkspaceEntity}
73-
isMoreIconVisible={item.key === selectedWorkspaceId}
74-
workspaces={workspaces}
75-
selectWorkspace={selectWorkspace}
76-
/>
77-
</HasPermission>
78-
) : (
79-
<CustomTabItem name={item.name as string} isMoreIconVisible={false} />
80-
)}
81-
</Flex>
82-
</>
83-
</Item>
84-
)}
85-
</TabList>
86+
</HasPermission>
87+
) : (
88+
<CustomTabItem name={item.name as string} isMoreIconVisible={false} />
89+
)}
90+
</Flex>
91+
</>
92+
</Item>
93+
)}
94+
</TabList>
95+
</div>
8696

8797
{FEATURE_FLAG_WORKSPACE_ACTIONS && (
8898
<HasPermission operations={[OPERATION.WORKSPACE_CREATION]}>

web_ui/src/pages/user-management/users/workspace-users/actions/roles-validation.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ export const getAvailableWorkspaceRoles = ({
2020
const isActiveUserWorkspaceContributor = isWorkspaceContributor(activeMember, workspaceId);
2121
const isActiveUserOrgAdmin = isOrganizationAdmin(activeMember, organizationId);
2222

23-
if (isActiveUserWorkspaceContributor && !isActiveUserOrgAdmin) {
24-
return [];
23+
if (isActiveUserOrgAdmin) {
24+
return [USER_ROLE.WORKSPACE_ADMIN, USER_ROLE.WORKSPACE_CONTRIBUTOR];
2525
}
2626

27-
if (members.length === 1) {
27+
if (isActiveUserWorkspaceContributor) {
2828
return [];
2929
}
3030

31-
const isActiveUserAdmin = isActiveUserOrgAdmin || isWorkspaceAdmin(activeMember, workspaceId);
31+
const isActiveUserAdmin = isWorkspaceAdmin(activeMember, workspaceId);
3232
const isAccountOwner = activeMember.id === targetMember.id;
3333
const isTargetMemberWorkspaceContributor = isWorkspaceContributor(targetMember, workspaceId);
3434
const atLeastTwoAdminsExist = members.filter((user) => isWorkspaceAdmin(user, workspaceId)).length >= 2;

web_ui/src/pages/user-management/users/workspace-users/available-workspace-users.component.tsx

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useFeatureFlags } from '@geti/core/src/feature-flags/hooks/use-feature-
77
import { useUsers } from '@geti/core/src/users/hook/use-users.hook';
88
import { getRoleCreationPayload } from '@geti/core/src/users/services/utils';
99
import { RESOURCE_TYPE, User, USER_ROLE } from '@geti/core/src/users/users.interface';
10-
import { ActionButton, Flex, Heading, Loading, View } from '@geti/ui';
10+
import { ActionButton, Heading, Loading, View } from '@geti/ui';
1111
import { Add } from '@geti/ui/icons';
1212

1313
import { useOrganizationIdentifier } from '../../../../hooks/use-organization-identifier/use-organization-identifier.hook';
@@ -104,34 +104,32 @@ export const AvailableWorkspaceUsers = ({ workspaceId, activeUser }: AvailableWo
104104
operations={[OPERATION.ADD_USER_TO_WORKSPACE]}
105105
resources={[{ type: RESOURCE_TYPE.WORKSPACE, id: workspaceId }]}
106106
>
107-
<Flex direction={'column'} gap={'size-200'}>
107+
<View marginTop={'size-200'}>
108108
<Heading level={3}>Available users to add to this workspace</Heading>
109-
<View>
110-
<UsersTable
111-
tableId={'available-workspace-users-table-id'}
112-
isFetchingNextPage={isFetchingNextPage}
113-
isLoading={isLoading}
114-
totalCount={orgTotal}
115-
users={availableUsers}
116-
hasFilters={false}
117-
activeUser={activeUser}
118-
getNextPage={async () => {
119-
// Load more from both lists to keep difference accurate
120-
await Promise.all([getNextOrgPage(), getNextWsPage()]);
121-
}}
122-
usersQueryParams={{}}
123-
setUsersQueryParams={() => {}}
124-
UserActions={({ user }) => <AddContributorAction user={user} />}
125-
ignoredColumns={[
126-
USERS_TABLE_COLUMNS.LAST_LOGIN,
127-
USERS_TABLE_COLUMNS.REGISTRATION_STATUS,
128-
USERS_TABLE_COLUMNS.ROLES,
129-
]}
130-
resourceId={workspaceId}
131-
usersTableType={RESOURCE_TYPE.WORKSPACE}
132-
/>
133-
</View>
134-
</Flex>
109+
<UsersTable
110+
tableId={'available-workspace-users-table-id'}
111+
isFetchingNextPage={isFetchingNextPage}
112+
isLoading={isLoading}
113+
totalCount={orgTotal}
114+
users={availableUsers}
115+
hasFilters={false}
116+
activeUser={activeUser}
117+
getNextPage={async () => {
118+
// Load more from both lists to keep difference accurate
119+
await Promise.all([getNextOrgPage(), getNextWsPage()]);
120+
}}
121+
usersQueryParams={{}}
122+
setUsersQueryParams={() => {}}
123+
UserActions={({ user }) => <AddContributorAction user={user} />}
124+
ignoredColumns={[
125+
USERS_TABLE_COLUMNS.LAST_LOGIN,
126+
USERS_TABLE_COLUMNS.REGISTRATION_STATUS,
127+
USERS_TABLE_COLUMNS.ROLES,
128+
]}
129+
resourceId={workspaceId}
130+
usersTableType={RESOURCE_TYPE.WORKSPACE}
131+
/>
132+
</View>
135133
</HasPermission>
136134
);
137135
};

web_ui/src/pages/user-management/workspaces/workspace-users-toolbar.component.tsx

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -65,34 +65,36 @@ export const WorkspaceUsersToolbar = ({
6565
orientation='vertical'
6666
>
6767
<Flex alignItems={'center'} gap={'size-200'} UNSAFE_className={classes.tabWrapper}>
68-
<TabList UNSAFE_className={classes.tabList}>
69-
{(item: { key: string; name: string }) => {
70-
return (
71-
<Item key={item.key} textValue={item.name}>
72-
{item.key === selectedWorkspaceId && FEATURE_FLAG_WORKSPACE_ACTIONS ? (
73-
<HasPermission
74-
operations={[OPERATION.WORKSPACE_MANAGEMENT]}
75-
resources={[{ type: RESOURCE_TYPE.WORKSPACE, id: item.key }]}
76-
specialCondition={
77-
activeUser !== undefined &&
78-
isOrganizationAdmin(activeUser, organizationId)
79-
}
80-
Fallback={<CustomTabItem name={item.name} isMoreIconVisible={false} />}
81-
>
82-
<CustomTabItemWithMenu
83-
workspace={selectedWorkspace as WorkspaceEntity}
84-
isMoreIconVisible={item.key === selectedWorkspaceId}
85-
workspaces={workspaces}
86-
selectWorkspace={(id: string) => handleSelection(id)}
87-
/>
88-
</HasPermission>
89-
) : (
90-
<CustomTabItem isMoreIconVisible={false} name={item.name} />
91-
)}
92-
</Item>
93-
);
94-
}}
95-
</TabList>
68+
<div className={classes.tabListScrollContainer}>
69+
<TabList UNSAFE_className={classes.tabList}>
70+
{(item: { key: string; name: string }) => {
71+
return (
72+
<Item key={item.key} textValue={item.name}>
73+
{item.key === selectedWorkspaceId && FEATURE_FLAG_WORKSPACE_ACTIONS ? (
74+
<HasPermission
75+
operations={[OPERATION.WORKSPACE_MANAGEMENT]}
76+
resources={[{ type: RESOURCE_TYPE.WORKSPACE, id: item.key }]}
77+
specialCondition={
78+
activeUser !== undefined &&
79+
isOrganizationAdmin(activeUser, organizationId)
80+
}
81+
Fallback={<CustomTabItem name={item.name} isMoreIconVisible={false} />}
82+
>
83+
<CustomTabItemWithMenu
84+
workspace={selectedWorkspace as WorkspaceEntity}
85+
isMoreIconVisible={item.key === selectedWorkspaceId}
86+
workspaces={workspaces}
87+
selectWorkspace={(id: string) => handleSelection(id)}
88+
/>
89+
</HasPermission>
90+
) : (
91+
<CustomTabItem isMoreIconVisible={false} name={item.name} />
92+
)}
93+
</Item>
94+
);
95+
}}
96+
</TabList>
97+
</div>
9698
{FEATURE_FLAG_WORKSPACE_ACTIONS && (
9799
<HasPermission operations={[OPERATION.WORKSPACE_CREATION]}>
98100
<TooltipTrigger placement={'bottom'}>

web_ui/src/shared/components/custom-tab-item/custom-tab-item.module.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,12 @@
100100
border-bottom: var(--spectrum-global-dimension-size-10) solid
101101
var(--spectrum-tabs-rule-color, var(--spectrum-global-color-gray-200)) !important;
102102
box-sizing: border-box !important;
103+
display: flex;
104+
align-items: center;
105+
}
106+
107+
.tabListScrollContainer {
108+
flex: 1 1 auto;
109+
min-width: 0;
103110
overflow: auto hidden;
104111
}

0 commit comments

Comments
 (0)