diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TeamDetails/TeamDetails.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TeamDetails/TeamDetails.tsx
index ecc9adac708..58cdb829ed2 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TeamDetails/TeamDetails.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TeamDetails/TeamDetails.tsx
@@ -17,10 +17,11 @@ import { compare } from 'fast-json-patch';
import { cloneDeep, orderBy } from 'lodash';
import { ExtraInfo, TableDetail } from 'Models';
import React, { Fragment, useEffect, useState } from 'react';
-import { Link } from 'react-router-dom';
+import { Link, useHistory } from 'react-router-dom';
import AppState from '../../AppState';
import {
getTeamAndUserDetailsPath,
+ getUserPath,
PAGE_SIZE_MEDIUM,
TITLE_FOR_NON_ADMIN_ACTION,
} from '../../constants/constants';
@@ -45,6 +46,7 @@ import NextPrevious from '../common/next-previous/NextPrevious';
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import Searchbar from '../common/searchbar/Searchbar';
import TabsPane from '../common/TabsPane/TabsPane';
+import Loader from '../Loader/Loader';
import ManageTab from '../ManageTab/ManageTab.component';
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
import FormModal from '../Modals/FormModal';
@@ -61,6 +63,7 @@ const TeamDetails = ({
isDescriptionEditable,
errorNewTeamData,
isAddingTeam,
+ isTeamMemberLoading,
handleAddTeam,
createNewTeam,
onNewTeamDataChange,
@@ -76,6 +79,7 @@ const TeamDetails = ({
handleAddUser,
removeUserFromTeam,
}: TeamDetailsProp) => {
+ const history = useHistory();
const DELETE_USER_INITIAL_STATE = {
user: undefined,
state: false,
@@ -127,7 +131,11 @@ const TeamDetails = ({
{
name: 'Manage',
isProtected: false,
- isHidden: isOwner() || userPermissions[Operation.UpdateOwner],
+ isHidden: !(
+ hasAccess ||
+ isOwner() ||
+ userPermissions[Operation.UpdateOwner]
+ ),
position: 4,
},
];
@@ -218,6 +226,14 @@ const TeamDetails = ({
return Promise.reject();
};
+ /**
+ * Redirects user to profile page.
+ * @param name user name
+ */
+ const handleUserRedirection = (name: string) => {
+ history.push(getUserPath(name));
+ };
+
useEffect(() => {
if (currentTeam) {
setHeading(currentTeam.displayName);
@@ -284,64 +300,71 @@ const TeamDetails = ({
)}
- {currentTeamUsers.length <= 0 ? (
-
-
- There are no users{' '}
- {teamUsersSearchText
- ? `as ${teamUsersSearchText}.`
- : `added yet.`}
-
- {isActionAllowed(userPermissions[Operation.UpdateTeam]) ? (
- <>
-
Would like to start adding some?
-
- >
- ) : null}
-
+ {isTeamMemberLoading ? (
+
) : (
-
-
- {sortedUser.map((user, index) => {
- const User = {
- displayName: user.displayName || user.name,
- fqn: user.name || '',
- type: 'user',
- id: user.id,
- name: user.name,
- };
+
+ {currentTeamUsers.length <= 0 ? (
+
+
+ There are no users{' '}
+ {teamUsersSearchText
+ ? `as ${teamUsersSearchText}.`
+ : `added yet.`}
+
+ {isActionAllowed(userPermissions[Operation.UpdateTeam]) ? (
+ <>
+
Would like to start adding some?
+
+ >
+ ) : null}
+
+ ) : (
+
+
+ {sortedUser.map((user, index) => {
+ const User = {
+ displayName: user.displayName || user.name,
+ fqn: user.name || '',
+ type: 'user',
+ id: user.id,
+ name: user.name,
+ };
- return (
-
+ );
+ })}
+
+ {teamUserPagin.total > PAGE_SIZE_MEDIUM && (
+
- );
- })}
-
- {teamUserPagin.total > PAGE_SIZE_MEDIUM && (
-
+ )}
+
)}
-
+
)}
);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TeamsAndUsers/TeamsAndUsers.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TeamsAndUsers/TeamsAndUsers.component.tsx
index d54130cc3e9..ea1821a1b0f 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TeamsAndUsers/TeamsAndUsers.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TeamsAndUsers/TeamsAndUsers.component.tsx
@@ -18,20 +18,22 @@ import { TeamsAndUsersProps } from '../../interface/teamsAndUsers.interface';
import { getActiveCatClass, getCountBadge } from '../../utils/CommonUtils';
import { getActiveUsers } from '../../utils/TeamUtils';
import PageLayout from '../containers/PageLayout';
+import Loader from '../Loader/Loader';
import TeamDetails from '../TeamDetails/TeamDetails';
import UserDetails from '../UserDetails/UserDetails';
const TeamsAndUsers = ({
users,
+ isUsersLoading,
admins,
bots,
activeUserTab,
userSearchTerm,
selectedUserList,
- updateUser,
handleUserSearchTerm,
handleDeleteUser,
handleJoinTeamClick,
+ isRightPannelLoading,
hasAccess,
isTeamVisible,
teams,
@@ -54,6 +56,7 @@ const TeamsAndUsers = ({
teamUserPaginHandler,
changeCurrentTeam,
isAddingUsers,
+ isTeamMemberLoading,
getUniqueUserList,
addUsersToTeam,
handleAddUser,
@@ -145,47 +148,52 @@ const TeamsAndUsers = ({
return (
-
- {!isTeamVisible ? (
-
- ) : (
-
- )}
-
+ {isRightPannelLoading ? (
+
+ ) : (
+
+ {!isTeamVisible ? (
+
+ ) : (
+
+ )}
+
+ )}
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/UserDataCard/UserDataCard.tsx b/openmetadata-ui/src/main/resources/ui/src/components/UserDataCard/UserDataCard.tsx
index 43f41b472bd..4df7304854f 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/UserDataCard/UserDataCard.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/UserDataCard/UserDataCard.tsx
@@ -23,18 +23,19 @@ type Item = {
name: string;
id?: string;
email: string;
- isActiveUser: boolean;
- profilePhoto: string;
- teamCount: string;
+ isActiveUser?: boolean;
+ profilePhoto?: string;
+ teamCount?: string;
};
type Props = {
item: Item;
- onClick: (value: string) => void;
+ showTeams?: boolean;
+ onClick?: (value: string) => void;
onDelete?: (id: string, name: string) => void;
};
-const UserDataCard = ({ item, onClick, onDelete }: Props) => {
+const UserDataCard = ({ item, onClick, onDelete, showTeams = true }: Props) => {
return (
{
{
- onClick(item.id as string);
+ onClick?.(item.name);
}}>
{item.description}
- {!item.isActiveUser && (
+ {!item?.isActiveUser && (
Inactive
)}
{item.email}
-
Teams: {item.teamCount}
+ {showTeams &&
Teams: {item.teamCount}
}
{!isNil(onDelete) && (
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/UserDetails/UserDetails.tsx b/openmetadata-ui/src/main/resources/ui/src/components/UserDetails/UserDetails.tsx
index 20dea620f69..9c3957d12ea 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/UserDetails/UserDetails.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/UserDetails/UserDetails.tsx
@@ -11,27 +11,28 @@
* limitations under the License.
*/
-import { compare, Operation } from 'fast-json-patch';
import { isUndefined } from 'lodash';
-import React, { useEffect, useState } from 'react';
-import AppState from '../../AppState';
-import { TITLE_FOR_NON_ADMIN_ACTION } from '../../constants/constants';
-import { Role } from '../../generated/entity/teams/role';
+import React, { useState } from 'react';
+import { useHistory } from 'react-router-dom';
+import {
+ getUserPath,
+ TITLE_FOR_NON_ADMIN_ACTION,
+} from '../../constants/constants';
import { EntityReference, User } from '../../generated/entity/teams/user';
import { getEntityName } from '../../utils/CommonUtils';
import { Button } from '../buttons/Button/Button';
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import Searchbar from '../common/searchbar/Searchbar';
+import Loader from '../Loader/Loader';
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
-import UserDetailsModal from '../Modals/UserDetailsModal/UserDetailsModal';
import UserDataCard from '../UserDataCard/UserDataCard';
type UserDetailsProps = {
selectedUserList: User[];
handleUserSearchTerm: (value: string) => void;
userSearchTerm: string;
- updateUser: (id: string, data: Operation[], updatedUser: User) => void;
+ isUsersLoading: boolean;
handleDeleteUser: (id: string) => void;
handleAddNewUser: () => void;
};
@@ -44,45 +45,14 @@ interface DeleteUserInfo {
const UserDetails = ({
selectedUserList,
userSearchTerm,
+ isUsersLoading,
handleDeleteUser,
handleUserSearchTerm,
- updateUser,
handleAddNewUser,
}: UserDetailsProps) => {
- const [selectedUser, setSelectedUser] = useState();
- const [roles, setRoles] = useState([]);
+ const history = useHistory();
const [deletingUser, setDeletingUser] = useState();
- const selectUser = (id: string) => {
- const user = selectedUserList.find((user) => user.id === id);
- if (user) {
- setSelectedUser(user);
- } else {
- setSelectedUser(undefined);
- }
- };
-
- const handleSave = (rolesData: Array) => {
- if (selectedUser) {
- const updatedData: User = {
- ...selectedUser,
- isAdmin: Boolean(rolesData.find((role) => role === 'admin')),
- roles: roles
- .filter((role) => rolesData.includes(role.id))
- .map((role) => ({
- id: role.id,
- type: 'role',
- href: role.href,
- displayName: role.displayName,
- })),
- };
- const jsonPatch = compare(selectedUser, updatedData);
- updateUser(selectedUser.id, jsonPatch, updatedData);
-
- setSelectedUser(undefined);
- }
- };
-
const handleDeleteUserModal = (id: string, name: string) => {
setDeletingUser({
name,
@@ -90,18 +60,24 @@ const UserDetails = ({
});
};
+ /**
+ * Redirects user to profile page.
+ * @param name user name
+ */
+ const handleUserRedirection = (name: string) => {
+ history.push(getUserPath(name));
+ };
+
const onConfirmDeleteUser = (id: string) => {
handleDeleteUser(id);
setDeletingUser(undefined);
};
- useEffect(() => {
- setRoles(AppState.userRoles);
- }, [AppState.userRoles]);
-
const getUserCards = () => {
- return (
- <>
+ return isUsersLoading ? (
+
+ ) : (
+
{selectedUserList.length > 0 ? (
selectUser(User.id)}>
+
@@ -141,7 +114,7 @@ const UserDetails = ({
No user available
)}
- >
+
);
};
@@ -173,16 +146,6 @@ const UserDetails = ({
{getUserCards()}
- {!isUndefined(selectedUser) && (
- setSelectedUser(undefined)}
- onSave={handleSave}
- />
- )}
-
{!isUndefined(deletingUser) && (
void;
@@ -42,9 +44,9 @@ export interface TeamsAndUsersProps {
currentTeamUserPage: number;
teamUsersSearchText: string;
isDescriptionEditable: boolean;
+ isRightPannelLoading: boolean;
errorNewTeamData: FormErrorData | undefined;
isAddingTeam: boolean;
- updateUser: (id: string, data: Operation[], updatedUser: User) => void;
createNewTeam: (data: Team) => void;
handleAddTeam: (value: boolean) => void;
onNewTeamDataChange: (
@@ -82,6 +84,7 @@ export interface TeamDetailsProp {
currentTeamUserPage: number;
teamUsersSearchText: string;
isDescriptionEditable: boolean;
+ isTeamMemberLoading: boolean;
hasAccess: boolean;
errorNewTeamData: FormErrorData | undefined;
isAddingTeam: boolean;
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TeamsAndUsersPage/TeamsAndUsersPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TeamsAndUsersPage/TeamsAndUsersPage.component.tsx
index d2aa73860d1..e70db988143 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TeamsAndUsersPage/TeamsAndUsersPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TeamsAndUsersPage/TeamsAndUsersPage.component.tsx
@@ -61,7 +61,10 @@ const TeamsAndUsersPage = () => {
const { isAuthDisabled } = useAuthContext();
const history = useHistory();
const [isLoading, setIsLoading] = useState(true);
+ const [isRightPannelLoading, setIsRightPannelLoading] = useState(true);
+ const [isTeamMemberLoading, setIsTeamMemberLoading] = useState(true);
const [isTeamVisible, setIsTeamVisible] = useState(true);
+ const [isUsersLoading, setIsUsersLoading] = useState(true);
const [teams, setTeams] = useState([]);
const [currentTeam, setCurrentTeam] = useState();
const [currentTeamUsers, setCurrentTeamUsers] = useState([]);
@@ -84,6 +87,10 @@ const TeamsAndUsersPage = () => {
setIsDescriptionEditable(value);
};
+ const handleRightPannelLoading = (value: boolean) => {
+ setIsRightPannelLoading(value);
+ };
+
const handleAddTeam = (value: boolean) => {
setIsAddingTeam(value);
};
@@ -101,6 +108,7 @@ const TeamsAndUsersPage = () => {
};
const setAllTabList = (users: User[], type = '') => {
+ setIsUsersLoading(true);
const dBots = users.filter((user) => user.isBot);
const dUsers = users.filter((user) => !user.isBot);
const dAdmins = users.filter((user) => user.isAdmin);
@@ -126,9 +134,11 @@ const TeamsAndUsersPage = () => {
break;
}
}
+ setIsUsersLoading(false);
};
const handleUserSearchTerm = (value: string) => {
+ setIsUsersLoading(true);
setUserSearchTerm(value);
if (value) {
let updatedList: User[] = [];
@@ -160,42 +170,15 @@ const TeamsAndUsersPage = () => {
} else {
setAllTabList(userList, activeUserTab);
}
+ setIsUsersLoading(false);
};
const handleAddNewUser = () => {
history.push(ROUTES.CREATE_USER);
};
- const updateUser = (id: string, data: Operation[], updatedUser: User) => {
- setIsLoading(true);
- updateUserDetail(id, data)
- .then((res) => {
- if (res.data) {
- const updatedData = (userList || []).map((user) => {
- if (user.id === id) {
- return updatedUser;
- }
-
- return user;
- });
- setAllTabList(updatedData, activeUserTab);
- setUserList(updatedData);
- } else {
- throw jsonData['api-error-messages']['unexpected-server-response'];
- }
- })
- .catch((err: AxiosError) => {
- showErrorToast(
- err,
- jsonData['api-error-messages']['update-user-error']
- );
- })
- .finally(() => {
- setIsLoading(false);
- });
- };
const handleDeleteUser = (id: string) => {
- setIsLoading(true);
+ setIsUsersLoading(true);
deleteUser(id)
.then(() => {
AppState.updateUsers((userList || []).filter((item) => item.id !== id));
@@ -208,6 +191,7 @@ const TeamsAndUsersPage = () => {
})
.finally(() => {
setIsLoading(false);
+ setIsUsersLoading(false);
});
};
@@ -218,21 +202,25 @@ const TeamsAndUsersPage = () => {
team: string,
pagin = {} as { [key: string]: string }
) => {
- getUsers('', PAGE_SIZE_MEDIUM, { team, ...pagin }).then(
- (res: AxiosResponse) => {
+ setIsTeamMemberLoading(true);
+ getUsers('', PAGE_SIZE_MEDIUM, { team, ...pagin })
+ .then((res: AxiosResponse) => {
if (res.data) {
setCurrentTeamUsers(res.data.data);
setTeamUserPagin(res.data.paging);
}
- }
- );
+ })
+ .catch(() => {
+ setCurrentTeamUsers([]);
+ setTeamUserPagin({ total: 0 });
+ })
+ .finally(() => setIsTeamMemberLoading(false));
};
/**
* Make API call to fetch all the teams
*/
const fetchTeams = () => {
- setIsLoading(true);
getTeams(['users', 'owns', 'defaultRoles', 'owner'])
.then((res: AxiosResponse) => {
if (res.data) {
@@ -255,6 +243,7 @@ const TeamsAndUsersPage = () => {
})
.finally(() => {
setIsLoading(false);
+ handleRightPannelLoading(false);
});
};
@@ -263,7 +252,6 @@ const TeamsAndUsersPage = () => {
*/
const fetchCurrentTeam = (name: string, update = false) => {
if (currentTeam?.name !== name || update) {
- // setIsLoading(true);
getTeamByName(name, ['users', 'owns', 'defaultRoles', 'owner'])
.then((res: AxiosResponse) => {
if (res.data) {
@@ -299,6 +287,7 @@ const TeamsAndUsersPage = () => {
};
const searchUsers = (text: string, currentPage: number) => {
+ setIsTeamMemberLoading(true);
searchData(
text,
currentPage,
@@ -317,7 +306,8 @@ const TeamsAndUsersPage = () => {
})
.catch(() => {
setCurrentTeamUsers([]);
- });
+ })
+ .finally(() => setIsTeamMemberLoading(false));
};
const teamUserPaginHandler = (cursorValue: string | number) => {
@@ -418,6 +408,7 @@ const TeamsAndUsersPage = () => {
* @param name - team name
*/
const changeCurrentTeam = (name: string, isUsersCategory: boolean) => {
+ handleRightPannelLoading(true);
history.push(getTeamAndUserDetailsPath(name));
if (isUsersCategory) {
setIsTeamVisible(false);
@@ -635,7 +626,10 @@ const TeamsAndUsersPage = () => {
isAddingTeam={isAddingTeam}
isAddingUsers={isAddingUsers}
isDescriptionEditable={isDescriptionEditable}
+ isRightPannelLoading={isRightPannelLoading}
+ isTeamMemberLoading={isTeamMemberLoading}
isTeamVisible={isTeamVisible}
+ isUsersLoading={isUsersLoading}
removeUserFromTeam={removeUserFromTeam}
selectedUserList={selectedUserList}
teamUserPagin={teamUserPagin}
@@ -643,7 +637,6 @@ const TeamsAndUsersPage = () => {
teamUsersSearchText={teamUsersSearchText}
teams={teams}
updateTeamHandler={updateTeamHandler}
- updateUser={updateUser}
userSearchTerm={userSearchTerm}
users={users}
onDescriptionUpdate={onDescriptionUpdate}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/teams/UserCard.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/teams/UserCard.tsx
index 08d56110356..99f0135e15a 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/teams/UserCard.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/teams/UserCard.tsx
@@ -43,6 +43,7 @@ interface Props {
isDataset?: boolean;
isCheckBoxes?: boolean;
isOwner?: boolean;
+ onTitleClick?: (value: string) => void;
onSelect?: (value: string) => void;
onRemove?: (value: string) => void;
}
@@ -54,6 +55,7 @@ const UserCard = ({
isDataset = false,
isCheckBoxes = false,
isOwner = false,
+ onTitleClick,
onSelect,
onRemove,
}: Props) => {
@@ -172,9 +174,16 @@ const UserCard = ({
+ title={item.displayName}
+ onClick={() => {
+ onTitleClick?.(item.fqn);
+ }}>
{item.displayName}
{item.name && (