mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: add last seen col to admin users list (#949)
* feat: add last seen col to admin users list * fix: header hover effect, duplicate title from TimeAgo * fix: use YMD format, never logged * fix: small tooltip change * refactor: adapt to review suggestions
This commit is contained in:
parent
1772997d28
commit
004ded8f74
@ -16,12 +16,16 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
fontWeight: 'normal',
|
fontWeight: 'normal',
|
||||||
border: 0,
|
border: 0,
|
||||||
'&:first-of-type': {
|
'&:first-of-type': {
|
||||||
borderTopLeftRadius: '8px',
|
'&, & > button': {
|
||||||
borderBottomLeftRadius: '8px',
|
borderTopLeftRadius: theme.spacing(1),
|
||||||
|
borderBottomLeftRadius: theme.spacing(1),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'&:last-of-type': {
|
'&:last-of-type': {
|
||||||
borderTopRightRadius: '8px',
|
'&, & > button': {
|
||||||
borderBottomRightRadius: '8px',
|
borderTopRightRadius: theme.spacing(1),
|
||||||
|
borderBottomRightRadius: theme.spacing(1),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@ import { ILocationSettings } from 'hooks/useLocationSettings';
|
|||||||
import { formatDateYMD } from 'utils/formatDate';
|
import { formatDateYMD } from 'utils/formatDate';
|
||||||
import { Highlighter } from 'component/common/Highlighter/Highlighter';
|
import { Highlighter } from 'component/common/Highlighter/Highlighter';
|
||||||
import { useStyles } from './UserListItem.styles';
|
import { useStyles } from './UserListItem.styles';
|
||||||
|
import TimeAgo from 'react-timeago';
|
||||||
|
|
||||||
interface IUserListItemProps {
|
interface IUserListItemProps {
|
||||||
user: IUser;
|
user: IUser;
|
||||||
@ -40,6 +41,20 @@ const UserListItem = ({
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { classes: styles } = useStyles();
|
const { classes: styles } = useStyles();
|
||||||
|
|
||||||
|
const renderTimeAgo = (date: string) => (
|
||||||
|
<Tooltip
|
||||||
|
title={`Last seen on: ${formatDateYMD(
|
||||||
|
date,
|
||||||
|
locationSettings.locale
|
||||||
|
)}`}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<Typography noWrap variant="body2" data-loading>
|
||||||
|
<TimeAgo date={new Date(date)} live={false} title={''} />
|
||||||
|
</Typography>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow key={user.id} className={styles.tableRow}>
|
<TableRow key={user.id} className={styles.tableRow}>
|
||||||
<TableCell className={styles.hideSM}>
|
<TableCell className={styles.hideSM}>
|
||||||
@ -77,6 +92,17 @@ const UserListItem = ({
|
|||||||
{renderRole(user.rootRole)}
|
{renderRole(user.rootRole)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className={styles.hideXS}>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(user.seenAt)}
|
||||||
|
show={() => renderTimeAgo(user.seenAt!)}
|
||||||
|
elseShow={
|
||||||
|
<Typography noWrap variant="body2" data-loading>
|
||||||
|
Never logged
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={hasAccess(ADMIN)}
|
condition={hasAccess(ADMIN)}
|
||||||
show={
|
show={
|
||||||
|
@ -186,6 +186,17 @@ const UsersList = ({ search }: IUsersListProps) => {
|
|||||||
>
|
>
|
||||||
Role
|
Role
|
||||||
</TableCellSortable>
|
</TableCellSortable>
|
||||||
|
<TableCellSortable
|
||||||
|
className={classnames(
|
||||||
|
styles.hideXS,
|
||||||
|
styles.shrinkTableCell
|
||||||
|
)}
|
||||||
|
name="last-seen"
|
||||||
|
sort={sort}
|
||||||
|
setSort={setSort}
|
||||||
|
>
|
||||||
|
Last seen
|
||||||
|
</TableCellSortable>
|
||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{hasAccess(ADMIN) ? 'Actions' : ''}
|
{hasAccess(ADMIN) ? 'Actions' : ''}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
@ -3,7 +3,6 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
tableCellHeaderSortable: {
|
tableCellHeaderSortable: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
position: 'relative',
|
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
'& > svg': {
|
'& > svg': {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
@ -5,7 +5,7 @@ import { createPersistentGlobalStateHook } from './usePersistentGlobalState';
|
|||||||
import useUsers from 'hooks/api/getters/useUsers/useUsers';
|
import useUsers from 'hooks/api/getters/useUsers/useUsers';
|
||||||
import IRole from 'interfaces/role';
|
import IRole from 'interfaces/role';
|
||||||
|
|
||||||
export type UsersSortType = 'created' | 'name' | 'role';
|
export type UsersSortType = 'created' | 'name' | 'role' | 'last-seen';
|
||||||
|
|
||||||
export interface IUsersSort {
|
export interface IUsersSort {
|
||||||
type: UsersSortType;
|
type: UsersSortType;
|
||||||
@ -50,6 +50,7 @@ export const createUsersFilterSortOptions = (): IUsersFilterSortOption[] => {
|
|||||||
{ type: 'created', name: 'Created' },
|
{ type: 'created', name: 'Created' },
|
||||||
{ type: 'name', name: 'Name' },
|
{ type: 'name', name: 'Name' },
|
||||||
{ type: 'role', name: 'Role' },
|
{ type: 'role', name: 'Role' },
|
||||||
|
{ type: 'last-seen', name: 'Last seen' },
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,6 +66,8 @@ const sortAscendingUsers = (
|
|||||||
return sortByName(users);
|
return sortByName(users);
|
||||||
case 'role':
|
case 'role':
|
||||||
return sortByRole(users, roles);
|
return sortByRole(users, roles);
|
||||||
|
case 'last-seen':
|
||||||
|
return sortByLastSeen(users);
|
||||||
default:
|
default:
|
||||||
console.error(`Unknown feature sort type: ${sort.type}`);
|
console.error(`Unknown feature sort type: ${sort.type}`);
|
||||||
return users;
|
return users;
|
||||||
@ -112,3 +115,11 @@ const getRoleName = (roleId: number, roles: Readonly<IRole[]>) => {
|
|||||||
const role = roles.find((role: IRole) => role.id === roleId);
|
const role = roles.find((role: IRole) => role.id === roleId);
|
||||||
return role ? role.name : '';
|
return role ? role.name : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sortByLastSeen = (users: Readonly<IUser[]>): IUser[] => {
|
||||||
|
return [...users].sort((a, b) => {
|
||||||
|
const aSeenAt = a.seenAt ?? '';
|
||||||
|
const bSeenAt = b.seenAt ?? '';
|
||||||
|
return bSeenAt.localeCompare(aSeenAt);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user