mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-25 02:04:39 +00:00
Work on UI Feedback 0.10 (#4382)
This commit is contained in:
parent
b5b42e1ca9
commit
bca22514f3
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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) && (
|
||||||
|
@ -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}?`}
|
||||||
|
@ -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;
|
||||||
|
@ -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}
|
||||||
|
@ -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 && (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user