mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Detect automated sessions from known data center cities (Council Bluffs, Santa Clara, Ashburn, etc.) with zero session duration, and display them with robot avatars instead of human faces. This provides an instant visual indicator in the Sessions UI without needing to inspect city/duration for each session. Uses both conditions (city match AND zero duration) to minimize false positives while reliably catching obvious bots.
85 lines
2.4 KiB
TypeScript
85 lines
2.4 KiB
TypeScript
import {
|
|
Button,
|
|
Column,
|
|
Icon,
|
|
Row,
|
|
Tab,
|
|
TabList,
|
|
TabPanel,
|
|
Tabs,
|
|
TextField,
|
|
} from '@umami/react-zen';
|
|
import { X } from 'lucide-react';
|
|
import { Avatar } from '@/components/common/Avatar';
|
|
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
|
import { useMessages, useWebsiteSessionQuery } from '@/components/hooks';
|
|
import { isLikelyBot } from '@/lib/botDetection';
|
|
import { SessionActivity } from './SessionActivity';
|
|
import { SessionData } from './SessionData';
|
|
import { SessionInfo } from './SessionInfo';
|
|
import { SessionStats } from './SessionStats';
|
|
|
|
export function SessionProfile({
|
|
websiteId,
|
|
sessionId,
|
|
onClose,
|
|
}: {
|
|
websiteId: string;
|
|
sessionId: string;
|
|
onClose?: () => void;
|
|
}) {
|
|
const { data, isLoading, error } = useWebsiteSessionQuery(websiteId, sessionId);
|
|
const { formatMessage, labels } = useMessages();
|
|
|
|
return (
|
|
<LoadingPanel
|
|
data={data}
|
|
isLoading={isLoading}
|
|
error={error}
|
|
loadingIcon="spinner"
|
|
loadingPlacement="absolute"
|
|
>
|
|
{data && (
|
|
<Column gap>
|
|
{onClose && (
|
|
<Row justifyContent="flex-end">
|
|
<Button onPress={onClose} variant="quiet">
|
|
<Icon>
|
|
<X />
|
|
</Icon>
|
|
</Button>
|
|
</Row>
|
|
)}
|
|
<Column gap="6">
|
|
<Row justifyContent="center" alignItems="center" gap="6">
|
|
<Avatar seed={data?.id} size={128} isBot={isLikelyBot(data)} />
|
|
<Column width="360px">
|
|
<TextField label="ID" value={data?.id} allowCopy />
|
|
</Column>
|
|
</Row>
|
|
<SessionStats data={data} />
|
|
<SessionInfo data={data} />
|
|
|
|
<Tabs>
|
|
<TabList>
|
|
<Tab id="activity">{formatMessage(labels.activity)}</Tab>
|
|
<Tab id="properties">{formatMessage(labels.properties)}</Tab>
|
|
</TabList>
|
|
<TabPanel id="activity">
|
|
<SessionActivity
|
|
websiteId={websiteId}
|
|
sessionId={sessionId}
|
|
startDate={data?.firstAt}
|
|
endDate={data?.lastAt}
|
|
/>
|
|
</TabPanel>
|
|
<TabPanel id="properties">
|
|
<SessionData sessionId={sessionId} websiteId={websiteId} />
|
|
</TabPanel>
|
|
</Tabs>
|
|
</Column>
|
|
</Column>
|
|
)}
|
|
</LoadingPanel>
|
|
);
|
|
}
|