diff --git a/src/api/user.ts b/src/api/user.ts index 95dac96d1..31dd166d4 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -2,6 +2,7 @@ import { mdiEmailLock, mdiGithub, mdiMicrosoft } from '@mdi/js'; import api from './base'; import { AxiosPromise } from 'axios'; import { IfmColors } from '@tdev-components/shared/Colors'; +import { Session as BetterAuthSession } from 'better-auth'; export enum Role { STUDENT = 'student', @@ -45,6 +46,8 @@ export const AuthProviderColor = { [AuthProvider.GITHUB]: IfmColors.black }; +export type Session = Omit; + export type User = { id: string; email: string; @@ -53,6 +56,7 @@ export type User = { lastName: string; role: Role; authProviders?: AuthProvider[]; + sessions?: Session[]; banned?: boolean; banReason?: string; banExpires?: Date; diff --git a/src/components/Admin/UserTable/User.tsx b/src/components/Admin/UserTable/User.tsx index 32f5843fd..1993186be 100644 --- a/src/components/Admin/UserTable/User.tsx +++ b/src/components/Admin/UserTable/User.tsx @@ -10,7 +10,7 @@ import { AuthProviderColor, AuthProviderIcons, RoleColors, RoleNames } from '@td import { useStore } from '@tdev-hooks/useStore'; import LiveStatusIndicator from '@tdev-components/LiveStatusIndicator'; import Icon from '@mdi/react'; -import { mdiAccountCancel, mdiAccountEdit, mdiCloudQuestion, mdiDatabaseExport } from '@mdi/js'; +import { mdiAccountCancel, mdiAccountEdit, mdiCloudQuestion } from '@mdi/js'; import { SIZE_S, SIZE_XS } from '@tdev-components/shared/iconSizes'; import Button from '@tdev-components/shared/Button'; import Popup from 'reactjs-popup'; @@ -20,6 +20,8 @@ import Badge from '@tdev-components/shared/Badge'; import NavReloadRequest from '../ActionRequest/NavReloadRequest'; import { IfmColors } from '@tdev-components/shared/Colors'; import ExportModal from '../ExportPanel/ExportModal'; +import Card from '@tdev-components/shared/Card'; +import DefinitionList from '@tdev-components/DefinitionList'; interface Props { user: UserModel; @@ -28,7 +30,6 @@ interface Props { const UserTableRow = observer((props: Props) => { const { user } = props; const userStore = useStore('userStore'); - const adminStore = useStore('adminStore'); const { current } = userStore; const ref = React.useRef(null); if (!current) { @@ -86,8 +87,41 @@ const UserTableRow = observer((props: Props) => { /> ))} - {formatDateTime(user.createdAt)} - {formatDateTime(user.updatedAt)} + {formatDateTime(user.createdAt, true)} + {formatDateTime(user.updatedAt, true)} + + {user.lastSeen ? ( + + {formatDateTime(user.lastSeen, true)} + + } + on="hover" + position={['top left', 'left center']} + keepTooltipInside="#__docusaurus" + mouseEnterDelay={200} + repositionOnResize + > + + +
Expires
+
{formatDateTime(user.lastSession!.expiresAt, true)}
+
IP
+
{user.lastSession?.ipAddress ?? '-'}
+
Client
+
+
+                                        
+                                            {(user.lastSession?.userAgent ?? '-').split(') ').join(')\n')}
+                                        
+                                    
+
+
+
+
+ ) : null} + {user.studentGroups.map((group, idx) => ( diff --git a/src/components/Admin/UserTable/index.tsx b/src/components/Admin/UserTable/index.tsx index 41a5c24c4..6cfcf7f98 100644 --- a/src/components/Admin/UserTable/index.tsx +++ b/src/components/Admin/UserTable/index.tsx @@ -19,7 +19,9 @@ type SortColumn = | 'linkedAccounts' | 'createdAt' | 'updatedAt' - | 'groups' + | 'authProviderNames' + | 'lastSeen' + | 'studentGroupNames' | 'id' | 'connectedClients'; interface Props { @@ -137,7 +139,15 @@ const UserTable = observer((props: Props) => { onClick={() => setSortColumn('lastName')} /> - Auth Provider + +