Skip to content

Commit 04d33df

Browse files
committed
feat: proper types for errors
1 parent bf1848f commit 04d33df

File tree

9 files changed

+129
-74
lines changed

9 files changed

+129
-74
lines changed

apps/api/src/query/builders/errors.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const ErrorsBuilders: Record<string, SimpleQueryConfig> = {
2626
],
2727
where: ["message != ''"],
2828
orderBy: 'timestamp DESC',
29-
limit: 100,
29+
limit: 50,
3030
timeField: 'timestamp',
3131
allowedFilters: [
3232
'path',
@@ -83,7 +83,7 @@ export const ErrorsBuilders: Record<string, SimpleQueryConfig> = {
8383
where: ["message != ''", "path != ''"],
8484
groupBy: ['path'],
8585
orderBy: 'errors DESC',
86-
limit: 25,
86+
limit: 20,
8787
timeField: 'timestamp',
8888
allowedFilters: ['path', 'message', 'browser_name'],
8989
customizable: true,
@@ -106,10 +106,25 @@ export const ErrorsBuilders: Record<string, SimpleQueryConfig> = {
106106
'uniq(message) as uniqueErrorTypes',
107107
'uniq(anonymous_id) as affectedUsers',
108108
'uniq(session_id) as affectedSessions',
109+
'0 as errorRate',
109110
],
110111
where: ["message != ''"],
111112
timeField: 'timestamp',
112113
allowedFilters: ['message', 'path', 'browser_name', 'country'],
113114
customizable: true,
114115
},
116+
117+
error_chart_data: {
118+
table: Analytics.errors,
119+
fields: [
120+
'toDate(timestamp) as date',
121+
'COUNT(*) as totalErrors',
122+
'uniq(anonymous_id) as affectedUsers',
123+
],
124+
where: ["message != ''"],
125+
groupBy: ['toDate(timestamp)'],
126+
orderBy: 'date ASC',
127+
timeField: 'timestamp',
128+
allowedFilters: ['message', 'path', 'browser_name', 'country'],
129+
},
115130
};

apps/dashboard/app/(main)/websites/[id]/errors/_components/error-data-table.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
createPageColumn,
88
errorColumns,
99
} from './error-table-columns';
10+
import type { ErrorType, ErrorByPage } from './types';
1011

1112
const DataTable = dynamic(
1213
() =>
@@ -21,8 +22,8 @@ const DataTable = dynamic(
2122

2223
interface ErrorDataTableProps {
2324
processedData: {
24-
error_types: Record<string, unknown>[];
25-
errors_by_page: Record<string, unknown>[];
25+
error_types: ErrorType[];
26+
errors_by_page: ErrorByPage[];
2627
};
2728
isLoading: boolean;
2829
isRefreshing: boolean;

apps/dashboard/app/(main)/websites/[id]/errors/_components/error-detail-modal.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
getErrorCategory,
2222
getSeverityColor,
2323
} from './utils';
24+
import type { RecentError } from './types';
2425

2526
interface InfoProps {
2627
label: string;
@@ -63,7 +64,7 @@ const IconRow: React.FC<IconProps> = ({ label, value, icon }) => (
6364
);
6465

6566
interface ErrorDetailModalProps {
66-
error: ErrorEvent;
67+
error: RecentError;
6768
isOpen: boolean;
6869
onClose: () => void;
6970
}

apps/dashboard/app/(main)/websites/[id]/errors/_components/error-summary-stats.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import type { ErrorSummary } from '@databuddy/shared';
21
import {
32
ActivityIcon,
43
TrendUpIcon,
54
UsersIcon,
65
WarningCircleIcon,
76
} from '@phosphor-icons/react';
87
import { StatCard } from '@/components/analytics/stat-card';
8+
import type { ErrorSummary } from './types';
99

1010
interface ErrorSummaryStatsProps {
1111
errorSummary: ErrorSummary;

apps/dashboard/app/(main)/websites/[id]/errors/_components/errors-page-content.tsx

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
'use client';
22

3-
import type { ErrorEvent, ErrorSummary } from '@databuddy/shared';
4-
import { ArrowClockwiseIcon, BugIcon } from '@phosphor-icons/react';
3+
import { BugIcon } from '@phosphor-icons/react';
54
import { useAtom } from 'jotai';
65
import { use, useCallback, useEffect } from 'react';
7-
import { toast } from 'sonner';
86
import { Skeleton } from '@/components/ui/skeleton';
9-
import { Button } from '@/components/ui/button';
107
import { useDateFilters } from '@/hooks/use-date-filters';
118
import { useEnhancedErrorData } from '@/hooks/use-dynamic-query';
129
import { formatDateOnly } from '@/lib/formatters';
1310
import { isAnalyticsRefreshingAtom } from '@/stores/jotai/filterAtoms';
11+
import type {
12+
ErrorChartData,
13+
ErrorSummary,
14+
ErrorType,
15+
ErrorByPage,
16+
RecentError,
17+
ProcessedChartData,
18+
} from './types';
1419
import { ErrorDataTable } from './error-data-table';
1520
import { ErrorSummaryStats } from './error-summary-stats';
1621
import { ErrorTrendsChart } from './error-trends-chart';
@@ -51,42 +56,29 @@ export const ErrorsPageContent = ({ params }: ErrorsPageContentProps) => {
5156
handleRefresh();
5257
}, [handleRefresh]);
5358

54-
const getData = (id: string): unknown[] =>
55-
(errorResults?.find((r) => r.queryId === id)?.data?.[id] as unknown[]) ||
56-
[];
59+
const getData = <T,>(id: string): T[] =>
60+
(errorResults?.find((r) => r.queryId === id)?.data?.[id] as T[]) || [];
5761

58-
const recentErrors = getData('recent_errors') as ErrorEvent[];
59-
const errorTypes = getData('error_types');
60-
const errorsByPage = getData('errors_by_page');
61-
const errorTrends = getData('error_trends');
62+
const recentErrors = getData<RecentError>('recent_errors');
63+
const errorTypes = getData<ErrorType>('error_types');
64+
const errorsByPage = getData<ErrorByPage>('errors_by_page');
65+
const errorSummaryData = getData<ErrorSummary>('error_summary');
66+
const errorChartData = getData<ErrorChartData>('error_chart_data');
6267

63-
const totalErrors = (errorTypes as Record<string, unknown>[]).reduce(
64-
(sum: number, type: Record<string, unknown>) =>
65-
sum + ((type.count as number) || 0),
66-
0
67-
);
68-
const totalUsers = (errorTypes as Record<string, unknown>[]).reduce(
69-
(sum: number, type: Record<string, unknown>) =>
70-
sum + ((type.users as number) || 0),
71-
0
72-
);
73-
74-
const errorSummary: ErrorSummary = {
75-
totalErrors,
76-
uniqueErrorTypes: errorTypes.length,
77-
affectedUsers: totalUsers,
78-
affectedSessions: recentErrors.length,
68+
const errorSummary = errorSummaryData[0] || {
69+
totalErrors: 0,
70+
uniqueErrorTypes: 0,
71+
affectedUsers: 0,
72+
affectedSessions: 0,
7973
errorRate: 0,
8074
};
8175

82-
const topError = (errorTypes as Record<string, unknown>[])[0] || null;
83-
const errorChartData = (errorTrends as Record<string, unknown>[]).map(
84-
(point: Record<string, unknown>) => ({
85-
date: formatDateOnly(point.date as string),
86-
'Total Errors': (point.errors as number) || 0,
87-
'Affected Users': (point.users as number) || 0,
88-
})
89-
);
76+
const topError = errorTypes[0] || null;
77+
const processedChartData: ProcessedChartData[] = errorChartData.map((point) => ({
78+
date: formatDateOnly(point.date),
79+
'Total Errors': point.totalErrors || 0,
80+
'Affected Users': point.affectedUsers || 0,
81+
}));
9082

9183
if (error) {
9284
return (
@@ -115,28 +107,20 @@ export const ErrorsPageContent = ({ params }: ErrorsPageContentProps) => {
115107
<div className="space-y-6">
116108
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
117109
<div className="lg:col-span-2">
118-
<ErrorTrendsChart errorChartData={errorChartData} />
110+
<ErrorTrendsChart errorChartData={processedChartData} />
119111
</div>
120112
<div className="space-y-4">
121113
<ErrorSummaryStats errorSummary={errorSummary} />
122-
<TopErrorCard
123-
topError={
124-
topError as {
125-
name: string;
126-
count: number;
127-
users: number;
128-
} | null
129-
}
130-
/>
114+
<TopErrorCard topError={topError} />
131115
</div>
132116
</div>
133117
<RecentErrorsTable recentErrors={recentErrors} />
134118
<ErrorDataTable
135119
isLoading={isLoading}
136120
isRefreshing={isRefreshing}
137121
processedData={{
138-
error_types: errorTypes as Record<string, unknown>[],
139-
errors_by_page: errorsByPage as Record<string, unknown>[],
122+
error_types: errorTypes,
123+
errors_by_page: errorsByPage,
140124
}}
141125
/>
142126
</div>

apps/dashboard/app/(main)/websites/[id]/errors/_components/recent-errors-table.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use client';
22

3-
import type { ErrorEvent } from '@databuddy/shared';
43
import { GlobeIcon } from '@phosphor-icons/react';
54
import { useState } from 'react';
65
import { CountryFlag } from '@/components/analytics/icons/CountryFlag';
@@ -10,16 +9,17 @@ import { Badge } from '@/components/ui/badge';
109
import { ErrorDetailModal } from './error-detail-modal';
1110
import { getErrorTypeIcon } from './error-icons';
1211
import { formatDateTime, getErrorCategory, getSeverityColor } from './utils';
12+
import type { RecentError } from './types';
1313

1414
interface Props {
15-
recentErrors: ErrorEvent[];
15+
recentErrors: RecentError[];
1616
}
1717

1818
export const RecentErrorsTable = ({ recentErrors }: Props) => {
19-
const [selectedError, setSelectedError] = useState<ErrorEvent | null>(null);
19+
const [selectedError, setSelectedError] = useState<RecentError | null>(null);
2020
const [isModalOpen, setIsModalOpen] = useState(false);
2121

22-
const handleViewError = (error: ErrorEvent) => {
22+
const handleViewError = (error: RecentError) => {
2323
setSelectedError(error);
2424
setIsModalOpen(true);
2525
};
@@ -31,7 +31,7 @@ export const RecentErrorsTable = ({ recentErrors }: Props) => {
3131
header: 'Error',
3232
cell: (info: any) => {
3333
const message = info.getValue() as string;
34-
const row = info.row.original as ErrorEvent;
34+
const row = info.row.original as RecentError;
3535
const { type, severity } = getErrorCategory(message);
3636

3737
return (
@@ -121,7 +121,7 @@ export const RecentErrorsTable = ({ recentErrors }: Props) => {
121121
accessorKey: 'country',
122122
header: 'Location',
123123
cell: (info: any) => {
124-
const row = info.row.original as ErrorEvent;
124+
const row = info.row.original as RecentError;
125125
const countryCode = row.country_code;
126126
const countryName = row.country_name || row.country;
127127

apps/dashboard/app/(main)/websites/[id]/errors/_components/top-error-card.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import { BugIcon, UsersIcon, WarningCircleIcon } from '@phosphor-icons/react';
22
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
3+
import type { ErrorType } from './types';
34

45
interface TopErrorCardProps {
5-
topError: {
6-
name: string;
7-
count: number;
8-
users: number;
9-
} | null;
6+
topError: ErrorType | null;
107
}
118

129
export const TopErrorCard = ({ topError }: TopErrorCardProps) => {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Types based on API response structure from errors.ts query builder
2+
3+
export type RecentError = {
4+
id: string;
5+
client_id: string;
6+
event_id?: string;
7+
anonymous_id: string;
8+
session_id: string;
9+
timestamp: string;
10+
path: string;
11+
message: string;
12+
filename?: string;
13+
lineno?: number;
14+
colno?: number;
15+
stack?: string;
16+
error_type?: string;
17+
ip?: string;
18+
user_agent?: string;
19+
// Additional fields from API response
20+
browser_name?: string;
21+
browser_version?: string;
22+
os_name?: string;
23+
os_version?: string;
24+
device_type?: string;
25+
country?: string;
26+
region?: string;
27+
country_code?: string;
28+
country_name?: string;
29+
created_at?: string;
30+
severity?: string;
31+
}
32+
33+
export type ErrorType = {
34+
name: string;
35+
count: number;
36+
users: number;
37+
last_seen: string;
38+
}
39+
40+
export type ErrorByPage = {
41+
name: string;
42+
errors: number;
43+
users: number;
44+
}
45+
46+
export type ErrorSummary = {
47+
totalErrors: number;
48+
uniqueErrorTypes: number;
49+
affectedUsers: number;
50+
affectedSessions: number;
51+
errorRate: number;
52+
}
53+
54+
export type ErrorChartData = {
55+
date: string;
56+
totalErrors: number;
57+
affectedUsers: number;
58+
}
59+
60+
export type ProcessedChartData = {
61+
date: string;
62+
'Total Errors': number;
63+
'Affected Users': number;
64+
}

apps/dashboard/hooks/use-dynamic-query.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -568,23 +568,16 @@ export function useEnhancedErrorData(
568568
{
569569
id: 'recent_errors',
570570
parameters: ['recent_errors'],
571-
limit: 100,
572571
filters,
573572
},
574-
{ id: 'error_types', parameters: ['error_types'], limit: 100, filters },
573+
{ id: 'error_types', parameters: ['error_types'], filters },
575574
{
576575
id: 'errors_by_page',
577576
parameters: ['errors_by_page'],
578-
limit: 25,
579-
filters,
580-
},
581-
{ id: 'error_trends', parameters: ['error_trends'], limit: 30, filters },
582-
{
583-
id: 'error_frequency',
584-
parameters: ['error_frequency'],
585-
limit: 30,
586577
filters,
587578
},
579+
{ id: 'error_summary', parameters: ['error_summary'], filters },
580+
{ id: 'error_chart_data', parameters: ['error_chart_data'], filters },
588581
],
589582
{
590583
...options,

0 commit comments

Comments
 (0)