Work on UI Feedback 0.10 (#4382)

This commit is contained in:
Shailesh Parmar 2022-04-23 01:38:24 +05:30 committed by GitHub
parent b5b42e1ca9
commit bca22514f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 209 additions and 209 deletions

View File

@ -17,10 +17,11 @@ import { compare } from 'fast-json-patch';
import { cloneDeep, orderBy } from 'lodash'; import { cloneDeep, orderBy } from 'lodash';
import { ExtraInfo, TableDetail } from 'Models'; import { ExtraInfo, TableDetail } from 'Models';
import React, { Fragment, useEffect, useState } from 'react'; 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 AppState from '../../AppState';
import { import {
getTeamAndUserDetailsPath, getTeamAndUserDetailsPath,
getUserPath,
PAGE_SIZE_MEDIUM, PAGE_SIZE_MEDIUM,
TITLE_FOR_NON_ADMIN_ACTION, TITLE_FOR_NON_ADMIN_ACTION,
} from '../../constants/constants'; } from '../../constants/constants';
@ -45,6 +46,7 @@ import NextPrevious from '../common/next-previous/NextPrevious';
import NonAdminAction from '../common/non-admin-action/NonAdminAction'; import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import Searchbar from '../common/searchbar/Searchbar'; import Searchbar from '../common/searchbar/Searchbar';
import TabsPane from '../common/TabsPane/TabsPane'; import TabsPane from '../common/TabsPane/TabsPane';
import Loader from '../Loader/Loader';
import ManageTab from '../ManageTab/ManageTab.component'; import ManageTab from '../ManageTab/ManageTab.component';
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal'; import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
import FormModal from '../Modals/FormModal'; import FormModal from '../Modals/FormModal';
@ -61,6 +63,7 @@ const TeamDetails = ({
isDescriptionEditable, isDescriptionEditable,
errorNewTeamData, errorNewTeamData,
isAddingTeam, isAddingTeam,
isTeamMemberLoading,
handleAddTeam, handleAddTeam,
createNewTeam, createNewTeam,
onNewTeamDataChange, onNewTeamDataChange,
@ -76,6 +79,7 @@ const TeamDetails = ({
handleAddUser, handleAddUser,
removeUserFromTeam, removeUserFromTeam,
}: TeamDetailsProp) => { }: TeamDetailsProp) => {
const history = useHistory();
const DELETE_USER_INITIAL_STATE = { const DELETE_USER_INITIAL_STATE = {
user: undefined, user: undefined,
state: false, state: false,
@ -127,7 +131,11 @@ const TeamDetails = ({
{ {
name: 'Manage', name: 'Manage',
isProtected: false, isProtected: false,
isHidden: isOwner() || userPermissions[Operation.UpdateOwner], isHidden: !(
hasAccess ||
isOwner() ||
userPermissions[Operation.UpdateOwner]
),
position: 4, position: 4,
}, },
]; ];
@ -218,6 +226,14 @@ const TeamDetails = ({
return Promise.reject(); return Promise.reject();
}; };
/**
* Redirects user to profile page.
* @param name user name
*/
const handleUserRedirection = (name: string) => {
history.push(getUserPath(name));
};
useEffect(() => { useEffect(() => {
if (currentTeam) { if (currentTeam) {
setHeading(currentTeam.displayName); setHeading(currentTeam.displayName);
@ -284,64 +300,71 @@ const TeamDetails = ({
</div> </div>
)} )}
</div> </div>
{currentTeamUsers.length <= 0 ? ( {isTeamMemberLoading ? (
<div className="tw-flex tw-flex-col tw-items-center tw-place-content-center tw-mt-40 tw-gap-1"> <Loader />
<p>
There are no users{' '}
{teamUsersSearchText
? `as ${teamUsersSearchText}.`
: `added yet.`}
</p>
{isActionAllowed(userPermissions[Operation.UpdateTeam]) ? (
<>
<p>Would like to start adding some?</p>
<Button
className="tw-h-8 tw-rounded tw-my-2"
size="small"
theme="primary"
variant="contained"
onClick={() => handleAddUser(true)}>
Add new user
</Button>
</>
) : null}
</div>
) : ( ) : (
<Fragment> <div>
<div {currentTeamUsers.length <= 0 ? (
className="tw-grid xxl:tw-grid-cols-4 lg:tw-grid-cols-3 md:tw-grid-cols-2 tw-gap-4" <div className="tw-flex tw-flex-col tw-items-center tw-place-content-center tw-mt-40 tw-gap-1">
data-testid="user-card-container"> <p>
{sortedUser.map((user, index) => { There are no users{' '}
const User = { {teamUsersSearchText
displayName: user.displayName || user.name, ? `as ${teamUsersSearchText}.`
fqn: user.name || '', : `added yet.`}
type: 'user', </p>
id: user.id, {isActionAllowed(userPermissions[Operation.UpdateTeam]) ? (
name: user.name, <>
}; <p>Would like to start adding some?</p>
<Button
className="tw-h-8 tw-rounded tw-my-2"
size="small"
theme="primary"
variant="contained"
onClick={() => handleAddUser(true)}>
Add new user
</Button>
</>
) : null}
</div>
) : (
<Fragment>
<div
className="tw-grid xxl:tw-grid-cols-4 lg:tw-grid-cols-3 md:tw-grid-cols-2 tw-gap-4"
data-testid="user-card-container">
{sortedUser.map((user, index) => {
const User = {
displayName: user.displayName || user.name,
fqn: user.name || '',
type: 'user',
id: user.id,
name: user.name,
};
return ( return (
<UserCard <UserCard
isActionVisible isActionVisible
isIconVisible isIconVisible
item={User} item={User}
key={index} key={index}
onRemove={deleteUserHandler} onRemove={deleteUserHandler}
onTitleClick={handleUserRedirection}
/>
);
})}
</div>
{teamUserPagin.total > PAGE_SIZE_MEDIUM && (
<NextPrevious
currentPage={currentTeamUserPage}
isNumberBased={Boolean(teamUsersSearchText)}
pageSize={PAGE_SIZE_MEDIUM}
paging={teamUserPagin}
pagingHandler={teamUserPaginHandler}
totalCount={teamUserPagin.total}
/> />
); )}
})} </Fragment>
</div>
{teamUserPagin.total > PAGE_SIZE_MEDIUM && (
<NextPrevious
currentPage={currentTeamUserPage}
isNumberBased={Boolean(teamUsersSearchText)}
pageSize={PAGE_SIZE_MEDIUM}
paging={teamUserPagin}
pagingHandler={teamUserPaginHandler}
totalCount={teamUserPagin.total}
/>
)} )}
</Fragment> </div>
)} )}
</div> </div>
); );

View File

@ -18,20 +18,22 @@ import { TeamsAndUsersProps } from '../../interface/teamsAndUsers.interface';
import { getActiveCatClass, getCountBadge } from '../../utils/CommonUtils'; import { getActiveCatClass, getCountBadge } from '../../utils/CommonUtils';
import { getActiveUsers } from '../../utils/TeamUtils'; import { getActiveUsers } from '../../utils/TeamUtils';
import PageLayout from '../containers/PageLayout'; import PageLayout from '../containers/PageLayout';
import Loader from '../Loader/Loader';
import TeamDetails from '../TeamDetails/TeamDetails'; import TeamDetails from '../TeamDetails/TeamDetails';
import UserDetails from '../UserDetails/UserDetails'; import UserDetails from '../UserDetails/UserDetails';
const TeamsAndUsers = ({ const TeamsAndUsers = ({
users, users,
isUsersLoading,
admins, admins,
bots, bots,
activeUserTab, activeUserTab,
userSearchTerm, userSearchTerm,
selectedUserList, selectedUserList,
updateUser,
handleUserSearchTerm, handleUserSearchTerm,
handleDeleteUser, handleDeleteUser,
handleJoinTeamClick, handleJoinTeamClick,
isRightPannelLoading,
hasAccess, hasAccess,
isTeamVisible, isTeamVisible,
teams, teams,
@ -54,6 +56,7 @@ const TeamsAndUsers = ({
teamUserPaginHandler, teamUserPaginHandler,
changeCurrentTeam, changeCurrentTeam,
isAddingUsers, isAddingUsers,
isTeamMemberLoading,
getUniqueUserList, getUniqueUserList,
addUsersToTeam, addUsersToTeam,
handleAddUser, handleAddUser,
@ -145,47 +148,52 @@ const TeamsAndUsers = ({
return ( return (
<PageLayout classes="tw-h-full tw-p-4" leftPanel={fetchLeftPanel()}> <PageLayout classes="tw-h-full tw-p-4" leftPanel={fetchLeftPanel()}>
<div {isRightPannelLoading ? (
className="tw-pb-3 tw-w-full tw-h-full tw-flex tw-flex-col" <Loader />
data-testid="team-and-user-container"> ) : (
{!isTeamVisible ? ( <div
<UserDetails className="tw-pb-3 tw-w-full tw-h-full tw-flex tw-flex-col"
handleAddNewUser={handleAddNewUser} data-testid="team-and-user-container">
handleDeleteUser={handleDeleteUser} {!isTeamVisible ? (
handleUserSearchTerm={handleUserSearchTerm} <UserDetails
selectedUserList={selectedUserList} handleAddNewUser={handleAddNewUser}
updateUser={updateUser} handleDeleteUser={handleDeleteUser}
userSearchTerm={userSearchTerm} handleUserSearchTerm={handleUserSearchTerm}
/> isUsersLoading={isUsersLoading}
) : ( selectedUserList={selectedUserList}
<TeamDetails userSearchTerm={userSearchTerm}
addUsersToTeam={addUsersToTeam} />
createNewTeam={createNewTeam} ) : (
currentTeam={currentTeam} <TeamDetails
currentTeamUserPage={currentTeamUserPage} addUsersToTeam={addUsersToTeam}
currentTeamUsers={currentTeamUsers} createNewTeam={createNewTeam}
descriptionHandler={descriptionHandler} currentTeam={currentTeam}
errorNewTeamData={errorNewTeamData} currentTeamUserPage={currentTeamUserPage}
getUniqueUserList={getUniqueUserList} currentTeamUsers={currentTeamUsers}
handleAddTeam={handleAddTeam} descriptionHandler={descriptionHandler}
handleAddUser={handleAddUser} errorNewTeamData={errorNewTeamData}
handleJoinTeamClick={handleJoinTeamClick} getUniqueUserList={getUniqueUserList}
handleTeamUsersSearchAction={handleTeamUsersSearchAction} handleAddTeam={handleAddTeam}
hasAccess={hasAccess} handleAddUser={handleAddUser}
isAddingTeam={isAddingTeam} handleJoinTeamClick={handleJoinTeamClick}
isAddingUsers={isAddingUsers} handleTeamUsersSearchAction={handleTeamUsersSearchAction}
isDescriptionEditable={isDescriptionEditable} hasAccess={hasAccess}
removeUserFromTeam={removeUserFromTeam} isAddingTeam={isAddingTeam}
teamUserPagin={teamUserPagin} isAddingUsers={isAddingUsers}
teamUserPaginHandler={teamUserPaginHandler} isDescriptionEditable={isDescriptionEditable}
teamUsersSearchText={teamUsersSearchText} isTeamMemberLoading={isTeamMemberLoading}
teams={teams} removeUserFromTeam={removeUserFromTeam}
updateTeamHandler={updateTeamHandler} teamUserPagin={teamUserPagin}
onDescriptionUpdate={onDescriptionUpdate} teamUserPaginHandler={teamUserPaginHandler}
onNewTeamDataChange={onNewTeamDataChange} teamUsersSearchText={teamUsersSearchText}
/> teams={teams}
)} updateTeamHandler={updateTeamHandler}
</div> onDescriptionUpdate={onDescriptionUpdate}
onNewTeamDataChange={onNewTeamDataChange}
/>
)}
</div>
)}
</PageLayout> </PageLayout>
); );
}; };

View File

@ -23,18 +23,19 @@ type Item = {
name: string; name: string;
id?: string; id?: string;
email: string; email: string;
isActiveUser: boolean; isActiveUser?: boolean;
profilePhoto: string; profilePhoto?: string;
teamCount: string; teamCount?: string;
}; };
type Props = { type Props = {
item: Item; item: Item;
onClick: (value: string) => void; showTeams?: boolean;
onClick?: (value: string) => void;
onDelete?: (id: string, name: string) => void; onDelete?: (id: string, name: string) => void;
}; };
const UserDataCard = ({ item, onClick, onDelete }: Props) => { const UserDataCard = ({ item, onClick, onDelete, showTeams = true }: Props) => {
return ( return (
<div <div
className="tw-card tw-flex tw-justify-between tw-py-2 tw-px-3 tw-group" className="tw-card tw-flex tw-justify-between tw-py-2 tw-px-3 tw-group"
@ -58,21 +59,21 @@ const UserDataCard = ({ item, onClick, onDelete }: Props) => {
<div className="tw-flex tw-justify-between"> <div className="tw-flex tw-justify-between">
<p <p
className={classNames('tw-font-normal', { className={classNames('tw-font-normal', {
'tw-cursor-pointer': Boolean(onClick), 'tw-cursor-pointer hover:tw-underline': Boolean(onClick),
})} })}
onClick={() => { onClick={() => {
onClick(item.id as string); onClick?.(item.name);
}}> }}>
{item.description} {item.description}
</p> </p>
{!item.isActiveUser && ( {!item?.isActiveUser && (
<span className="tw-text-xs tw-bg-badge tw-border tw-px-2 tw-py-0.5 tw-rounded"> <span className="tw-text-xs tw-bg-badge tw-border tw-px-2 tw-py-0.5 tw-rounded">
Inactive Inactive
</span> </span>
)} )}
</div> </div>
<p className="tw-truncate">{item.email}</p> <p className="tw-truncate">{item.email}</p>
<p>Teams: {item.teamCount}</p> {showTeams && <p>Teams: {item.teamCount}</p>}
</div> </div>
</div> </div>
{!isNil(onDelete) && ( {!isNil(onDelete) && (

View File

@ -11,27 +11,28 @@
* limitations under the License. * limitations under the License.
*/ */
import { compare, Operation } from 'fast-json-patch';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';
import React, { useEffect, useState } from 'react'; import React, { useState } from 'react';
import AppState from '../../AppState'; import { useHistory } from 'react-router-dom';
import { TITLE_FOR_NON_ADMIN_ACTION } from '../../constants/constants'; import {
import { Role } from '../../generated/entity/teams/role'; getUserPath,
TITLE_FOR_NON_ADMIN_ACTION,
} from '../../constants/constants';
import { EntityReference, User } from '../../generated/entity/teams/user'; import { EntityReference, User } from '../../generated/entity/teams/user';
import { getEntityName } from '../../utils/CommonUtils'; import { getEntityName } from '../../utils/CommonUtils';
import { Button } from '../buttons/Button/Button'; import { Button } from '../buttons/Button/Button';
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder'; import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
import NonAdminAction from '../common/non-admin-action/NonAdminAction'; import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import Searchbar from '../common/searchbar/Searchbar'; import Searchbar from '../common/searchbar/Searchbar';
import Loader from '../Loader/Loader';
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal'; import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
import UserDetailsModal from '../Modals/UserDetailsModal/UserDetailsModal';
import UserDataCard from '../UserDataCard/UserDataCard'; import UserDataCard from '../UserDataCard/UserDataCard';
type UserDetailsProps = { type UserDetailsProps = {
selectedUserList: User[]; selectedUserList: User[];
handleUserSearchTerm: (value: string) => void; handleUserSearchTerm: (value: string) => void;
userSearchTerm: string; userSearchTerm: string;
updateUser: (id: string, data: Operation[], updatedUser: User) => void; isUsersLoading: boolean;
handleDeleteUser: (id: string) => void; handleDeleteUser: (id: string) => void;
handleAddNewUser: () => void; handleAddNewUser: () => void;
}; };
@ -44,45 +45,14 @@ interface DeleteUserInfo {
const UserDetails = ({ const UserDetails = ({
selectedUserList, selectedUserList,
userSearchTerm, userSearchTerm,
isUsersLoading,
handleDeleteUser, handleDeleteUser,
handleUserSearchTerm, handleUserSearchTerm,
updateUser,
handleAddNewUser, handleAddNewUser,
}: UserDetailsProps) => { }: UserDetailsProps) => {
const [selectedUser, setSelectedUser] = useState<User>(); const history = useHistory();
const [roles, setRoles] = useState<Role[]>([]);
const [deletingUser, setDeletingUser] = useState<DeleteUserInfo>(); const [deletingUser, setDeletingUser] = useState<DeleteUserInfo>();
const selectUser = (id: string) => {
const user = selectedUserList.find((user) => user.id === id);
if (user) {
setSelectedUser(user);
} else {
setSelectedUser(undefined);
}
};
const handleSave = (rolesData: Array<string>) => {
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) => { const handleDeleteUserModal = (id: string, name: string) => {
setDeletingUser({ setDeletingUser({
name, 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) => { const onConfirmDeleteUser = (id: string) => {
handleDeleteUser(id); handleDeleteUser(id);
setDeletingUser(undefined); setDeletingUser(undefined);
}; };
useEffect(() => {
setRoles(AppState.userRoles);
}, [AppState.userRoles]);
const getUserCards = () => { const getUserCards = () => {
return ( return isUsersLoading ? (
<> <Loader />
) : (
<div>
{selectedUserList.length > 0 ? ( {selectedUserList.length > 0 ? (
<div <div
className="tw-grid xxl:tw-grid-cols-3 lg:tw-grid-cols-2 tw-gap-4" className="tw-grid xxl:tw-grid-cols-3 lg:tw-grid-cols-2 tw-gap-4"
@ -123,13 +99,10 @@ const UserDetails = ({
}; };
return ( return (
<div <div key={index}>
className="tw-cursor-pointer"
key={index}
onClick={() => selectUser(User.id)}>
<UserDataCard <UserDataCard
item={User} item={User}
onClick={selectUser} onClick={handleUserRedirection}
onDelete={handleDeleteUserModal} onDelete={handleDeleteUserModal}
/> />
</div> </div>
@ -141,7 +114,7 @@ const UserDetails = ({
<p>No user available</p> <p>No user available</p>
</ErrorPlaceHolder> </ErrorPlaceHolder>
)} )}
</> </div>
); );
}; };
@ -173,16 +146,6 @@ const UserDetails = ({
</div> </div>
{getUserCards()} {getUserCards()}
{!isUndefined(selectedUser) && (
<UserDetailsModal
header="Update user"
roles={roles}
userData={selectedUser}
onCancel={() => setSelectedUser(undefined)}
onSave={handleSave}
/>
)}
{!isUndefined(deletingUser) && ( {!isUndefined(deletingUser) && (
<ConfirmationModal <ConfirmationModal
bodyText={`Are you sure you want to delete ${deletingUser.name}?`} bodyText={`Are you sure you want to delete ${deletingUser.name}?`}

View File

@ -28,6 +28,8 @@ export type TeamDeleteType = {
export interface TeamsAndUsersProps { export interface TeamsAndUsersProps {
hasAccess: boolean; hasAccess: boolean;
isUsersLoading: boolean;
isTeamMemberLoading: boolean;
isTeamVisible: boolean; isTeamVisible: boolean;
activeUserTab: UserType | undefined; activeUserTab: UserType | undefined;
activeUserTabHandler: (value: UserType | undefined) => void; activeUserTabHandler: (value: UserType | undefined) => void;
@ -42,9 +44,9 @@ export interface TeamsAndUsersProps {
currentTeamUserPage: number; currentTeamUserPage: number;
teamUsersSearchText: string; teamUsersSearchText: string;
isDescriptionEditable: boolean; isDescriptionEditable: boolean;
isRightPannelLoading: boolean;
errorNewTeamData: FormErrorData | undefined; errorNewTeamData: FormErrorData | undefined;
isAddingTeam: boolean; isAddingTeam: boolean;
updateUser: (id: string, data: Operation[], updatedUser: User) => void;
createNewTeam: (data: Team) => void; createNewTeam: (data: Team) => void;
handleAddTeam: (value: boolean) => void; handleAddTeam: (value: boolean) => void;
onNewTeamDataChange: ( onNewTeamDataChange: (
@ -82,6 +84,7 @@ export interface TeamDetailsProp {
currentTeamUserPage: number; currentTeamUserPage: number;
teamUsersSearchText: string; teamUsersSearchText: string;
isDescriptionEditable: boolean; isDescriptionEditable: boolean;
isTeamMemberLoading: boolean;
hasAccess: boolean; hasAccess: boolean;
errorNewTeamData: FormErrorData | undefined; errorNewTeamData: FormErrorData | undefined;
isAddingTeam: boolean; isAddingTeam: boolean;

View File

@ -61,7 +61,10 @@ const TeamsAndUsersPage = () => {
const { isAuthDisabled } = useAuthContext(); const { isAuthDisabled } = useAuthContext();
const history = useHistory(); const history = useHistory();
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [isRightPannelLoading, setIsRightPannelLoading] = useState(true);
const [isTeamMemberLoading, setIsTeamMemberLoading] = useState(true);
const [isTeamVisible, setIsTeamVisible] = useState(true); const [isTeamVisible, setIsTeamVisible] = useState(true);
const [isUsersLoading, setIsUsersLoading] = useState(true);
const [teams, setTeams] = useState<Team[]>([]); const [teams, setTeams] = useState<Team[]>([]);
const [currentTeam, setCurrentTeam] = useState<Team>(); const [currentTeam, setCurrentTeam] = useState<Team>();
const [currentTeamUsers, setCurrentTeamUsers] = useState<User[]>([]); const [currentTeamUsers, setCurrentTeamUsers] = useState<User[]>([]);
@ -84,6 +87,10 @@ const TeamsAndUsersPage = () => {
setIsDescriptionEditable(value); setIsDescriptionEditable(value);
}; };
const handleRightPannelLoading = (value: boolean) => {
setIsRightPannelLoading(value);
};
const handleAddTeam = (value: boolean) => { const handleAddTeam = (value: boolean) => {
setIsAddingTeam(value); setIsAddingTeam(value);
}; };
@ -101,6 +108,7 @@ const TeamsAndUsersPage = () => {
}; };
const setAllTabList = (users: User[], type = '') => { const setAllTabList = (users: User[], type = '') => {
setIsUsersLoading(true);
const dBots = users.filter((user) => user.isBot); const dBots = users.filter((user) => user.isBot);
const dUsers = users.filter((user) => !user.isBot); const dUsers = users.filter((user) => !user.isBot);
const dAdmins = users.filter((user) => user.isAdmin); const dAdmins = users.filter((user) => user.isAdmin);
@ -126,9 +134,11 @@ const TeamsAndUsersPage = () => {
break; break;
} }
} }
setIsUsersLoading(false);
}; };
const handleUserSearchTerm = (value: string) => { const handleUserSearchTerm = (value: string) => {
setIsUsersLoading(true);
setUserSearchTerm(value); setUserSearchTerm(value);
if (value) { if (value) {
let updatedList: User[] = []; let updatedList: User[] = [];
@ -160,42 +170,15 @@ const TeamsAndUsersPage = () => {
} else { } else {
setAllTabList(userList, activeUserTab); setAllTabList(userList, activeUserTab);
} }
setIsUsersLoading(false);
}; };
const handleAddNewUser = () => { const handleAddNewUser = () => {
history.push(ROUTES.CREATE_USER); 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) => { const handleDeleteUser = (id: string) => {
setIsLoading(true); setIsUsersLoading(true);
deleteUser(id) deleteUser(id)
.then(() => { .then(() => {
AppState.updateUsers((userList || []).filter((item) => item.id !== id)); AppState.updateUsers((userList || []).filter((item) => item.id !== id));
@ -208,6 +191,7 @@ const TeamsAndUsersPage = () => {
}) })
.finally(() => { .finally(() => {
setIsLoading(false); setIsLoading(false);
setIsUsersLoading(false);
}); });
}; };
@ -218,21 +202,25 @@ const TeamsAndUsersPage = () => {
team: string, team: string,
pagin = {} as { [key: string]: string } pagin = {} as { [key: string]: string }
) => { ) => {
getUsers('', PAGE_SIZE_MEDIUM, { team, ...pagin }).then( setIsTeamMemberLoading(true);
(res: AxiosResponse) => { getUsers('', PAGE_SIZE_MEDIUM, { team, ...pagin })
.then((res: AxiosResponse) => {
if (res.data) { if (res.data) {
setCurrentTeamUsers(res.data.data); setCurrentTeamUsers(res.data.data);
setTeamUserPagin(res.data.paging); setTeamUserPagin(res.data.paging);
} }
} })
); .catch(() => {
setCurrentTeamUsers([]);
setTeamUserPagin({ total: 0 });
})
.finally(() => setIsTeamMemberLoading(false));
}; };
/** /**
* Make API call to fetch all the teams * Make API call to fetch all the teams
*/ */
const fetchTeams = () => { const fetchTeams = () => {
setIsLoading(true);
getTeams(['users', 'owns', 'defaultRoles', 'owner']) getTeams(['users', 'owns', 'defaultRoles', 'owner'])
.then((res: AxiosResponse) => { .then((res: AxiosResponse) => {
if (res.data) { if (res.data) {
@ -255,6 +243,7 @@ const TeamsAndUsersPage = () => {
}) })
.finally(() => { .finally(() => {
setIsLoading(false); setIsLoading(false);
handleRightPannelLoading(false);
}); });
}; };
@ -263,7 +252,6 @@ const TeamsAndUsersPage = () => {
*/ */
const fetchCurrentTeam = (name: string, update = false) => { const fetchCurrentTeam = (name: string, update = false) => {
if (currentTeam?.name !== name || update) { if (currentTeam?.name !== name || update) {
// setIsLoading(true);
getTeamByName(name, ['users', 'owns', 'defaultRoles', 'owner']) getTeamByName(name, ['users', 'owns', 'defaultRoles', 'owner'])
.then((res: AxiosResponse) => { .then((res: AxiosResponse) => {
if (res.data) { if (res.data) {
@ -299,6 +287,7 @@ const TeamsAndUsersPage = () => {
}; };
const searchUsers = (text: string, currentPage: number) => { const searchUsers = (text: string, currentPage: number) => {
setIsTeamMemberLoading(true);
searchData( searchData(
text, text,
currentPage, currentPage,
@ -317,7 +306,8 @@ const TeamsAndUsersPage = () => {
}) })
.catch(() => { .catch(() => {
setCurrentTeamUsers([]); setCurrentTeamUsers([]);
}); })
.finally(() => setIsTeamMemberLoading(false));
}; };
const teamUserPaginHandler = (cursorValue: string | number) => { const teamUserPaginHandler = (cursorValue: string | number) => {
@ -418,6 +408,7 @@ const TeamsAndUsersPage = () => {
* @param name - team name * @param name - team name
*/ */
const changeCurrentTeam = (name: string, isUsersCategory: boolean) => { const changeCurrentTeam = (name: string, isUsersCategory: boolean) => {
handleRightPannelLoading(true);
history.push(getTeamAndUserDetailsPath(name)); history.push(getTeamAndUserDetailsPath(name));
if (isUsersCategory) { if (isUsersCategory) {
setIsTeamVisible(false); setIsTeamVisible(false);
@ -635,7 +626,10 @@ const TeamsAndUsersPage = () => {
isAddingTeam={isAddingTeam} isAddingTeam={isAddingTeam}
isAddingUsers={isAddingUsers} isAddingUsers={isAddingUsers}
isDescriptionEditable={isDescriptionEditable} isDescriptionEditable={isDescriptionEditable}
isRightPannelLoading={isRightPannelLoading}
isTeamMemberLoading={isTeamMemberLoading}
isTeamVisible={isTeamVisible} isTeamVisible={isTeamVisible}
isUsersLoading={isUsersLoading}
removeUserFromTeam={removeUserFromTeam} removeUserFromTeam={removeUserFromTeam}
selectedUserList={selectedUserList} selectedUserList={selectedUserList}
teamUserPagin={teamUserPagin} teamUserPagin={teamUserPagin}
@ -643,7 +637,6 @@ const TeamsAndUsersPage = () => {
teamUsersSearchText={teamUsersSearchText} teamUsersSearchText={teamUsersSearchText}
teams={teams} teams={teams}
updateTeamHandler={updateTeamHandler} updateTeamHandler={updateTeamHandler}
updateUser={updateUser}
userSearchTerm={userSearchTerm} userSearchTerm={userSearchTerm}
users={users} users={users}
onDescriptionUpdate={onDescriptionUpdate} onDescriptionUpdate={onDescriptionUpdate}

View File

@ -43,6 +43,7 @@ interface Props {
isDataset?: boolean; isDataset?: boolean;
isCheckBoxes?: boolean; isCheckBoxes?: boolean;
isOwner?: boolean; isOwner?: boolean;
onTitleClick?: (value: string) => void;
onSelect?: (value: string) => void; onSelect?: (value: string) => void;
onRemove?: (value: string) => void; onRemove?: (value: string) => void;
} }
@ -54,6 +55,7 @@ const UserCard = ({
isDataset = false, isDataset = false,
isCheckBoxes = false, isCheckBoxes = false,
isOwner = false, isOwner = false,
onTitleClick,
onSelect, onSelect,
onRemove, onRemove,
}: Props) => { }: Props) => {
@ -172,9 +174,16 @@ const UserCard = ({
<p <p
className={classNames( className={classNames(
'tw-font-normal', 'tw-font-normal',
isActionVisible ? 'tw-truncate tw-w-32' : null isActionVisible ? 'tw-truncate tw-w-32' : null,
{
'tw-cursor-pointer hover:tw-underline':
Boolean(onTitleClick),
}
)} )}
title={item.displayName}> title={item.displayName}
onClick={() => {
onTitleClick?.(item.fqn);
}}>
{item.displayName} {item.displayName}
</p> </p>
{item.name && ( {item.name && (