mirror of
https://github.com/umami-software/umami.git
synced 2026-02-15 10:05:36 +01:00
fix(sessions): add defensive null checks for dates to prevent crashes
- Add null validation in SessionsTable, SessionInfo, SessionActivity, and DateDistance - Log missing date fields in development mode only - Display '—' placeholder when dates are null instead of crashing - Addresses RangeError: Invalid time value on Sessions tab
This commit is contained in:
parent
7ac5913c86
commit
ffd6fd666c
5 changed files with 49 additions and 5 deletions
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
|
|
@ -364,8 +364,6 @@ importers:
|
||||||
specifier: ^5.9.3
|
specifier: ^5.9.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
|
|
||||||
dist: {}
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@ampproject/remapping@2.3.0':
|
'@ampproject/remapping@2.3.0':
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,19 @@ export function SessionActivity({
|
||||||
<LoadingPanel data={data} isLoading={isLoading} error={error}>
|
<LoadingPanel data={data} isLoading={isLoading} error={error}>
|
||||||
<Column gap>
|
<Column gap>
|
||||||
{data?.map(({ eventId, createdAt, urlPath, eventName, visitId, hasData }) => {
|
{data?.map(({ eventId, createdAt, urlPath, eventName, visitId, hasData }) => {
|
||||||
|
if (!createdAt) {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('[SessionActivity] Event missing createdAt', {
|
||||||
|
eventId,
|
||||||
|
visitId,
|
||||||
|
urlPath,
|
||||||
|
eventName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const showHeader = !lastDay || !isSameDay(new Date(lastDay), new Date(createdAt));
|
const showHeader = !lastDay || !isSameDay(new Date(lastDay), new Date(createdAt));
|
||||||
lastDay = createdAt;
|
lastDay = createdAt;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,18 @@ export function SessionInfo({ data }) {
|
||||||
const { formatValue } = useFormat();
|
const { formatValue } = useFormat();
|
||||||
const { getRegionName } = useRegionNames(locale);
|
const { getRegionName } = useRegionNames(locale);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
if (!data.lastAt || !data.firstAt) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('[SessionInfo] Session missing date fields', {
|
||||||
|
sessionId: data.id,
|
||||||
|
hasLastAt: !!data.lastAt,
|
||||||
|
hasFirstAt: !!data.firstAt,
|
||||||
|
distinctId: data.distinctId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid columns="repeat(auto-fit, minmax(200px, 1fr)" gap>
|
<Grid columns="repeat(auto-fit, minmax(200px, 1fr)" gap>
|
||||||
<Info label={formatMessage(labels.distinctId)} icon={<KeyRound />}>
|
<Info label={formatMessage(labels.distinctId)} icon={<KeyRound />}>
|
||||||
|
|
@ -18,11 +30,11 @@ export function SessionInfo({ data }) {
|
||||||
</Info>
|
</Info>
|
||||||
|
|
||||||
<Info label={formatMessage(labels.lastSeen)} icon={<Calendar />}>
|
<Info label={formatMessage(labels.lastSeen)} icon={<Calendar />}>
|
||||||
<DateDistance date={new Date(data.lastAt)} />
|
{data.lastAt ? <DateDistance date={new Date(data.lastAt)} /> : '—'}
|
||||||
</Info>
|
</Info>
|
||||||
|
|
||||||
<Info label={formatMessage(labels.firstSeen)} icon={<Calendar />}>
|
<Info label={formatMessage(labels.firstSeen)} icon={<Calendar />}>
|
||||||
<DateDistance date={new Date(data.firstAt)} />
|
{data.firstAt ? <DateDistance date={new Date(data.firstAt)} /> : '—'}
|
||||||
</Info>
|
</Info>
|
||||||
|
|
||||||
<Info
|
<Info
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,20 @@ export function SessionsTable(props: DataTableProps) {
|
||||||
)}
|
)}
|
||||||
</DataColumn>
|
</DataColumn>
|
||||||
<DataColumn id="lastAt" label={formatMessage(labels.lastSeen)}>
|
<DataColumn id="lastAt" label={formatMessage(labels.lastSeen)}>
|
||||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
{(row: any) => {
|
||||||
|
if (!row.createdAt) {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('[SessionsTable] Session missing createdAt', {
|
||||||
|
sessionId: row.id,
|
||||||
|
visits: row.visits,
|
||||||
|
views: row.views,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return '—';
|
||||||
|
}
|
||||||
|
return <DateDistance date={new Date(row.createdAt)} />;
|
||||||
|
}}
|
||||||
</DataColumn>
|
</DataColumn>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,14 @@ export function DateDistance({ date }: { date: Date }) {
|
||||||
const { formatTimezoneDate } = useTimezone();
|
const { formatTimezoneDate } = useTimezone();
|
||||||
const { dateLocale } = useLocale();
|
const { dateLocale } = useLocale();
|
||||||
|
|
||||||
|
if (!date || isNaN(date.getTime())) {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('[DateDistance] Invalid date received', { date });
|
||||||
|
}
|
||||||
|
return <Text>—</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text title={formatTimezoneDate(date.toISOString(), 'PPPpp')}>
|
<Text title={formatTimezoneDate(date.toISOString(), 'PPPpp')}>
|
||||||
{formatDistanceToNow(date, { addSuffix: true, locale: dateLocale })}
|
{formatDistanceToNow(date, { addSuffix: true, locale: dateLocale })}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue