Skip to content

Commit 9a81ec9

Browse files
committed
feat: add long table query events logic and improve display of event list page
1 parent 13e3fb8 commit 9a81ec9

File tree

3 files changed

+83
-27
lines changed

3 files changed

+83
-27
lines changed

src/client/routes/insights/events.tsx

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { routeAuthBeforeLoad } from '@/utils/route';
33
import { useCurrentWorkspaceId } from '@/store/user';
44
import { InsightType, useInsightsStore } from '@/store/insights';
55
import { trpc } from '@/api/trpc';
6-
import dayjs, { Dayjs } from 'dayjs';
6+
import dayjs from 'dayjs';
77
import { useMemo, useState } from 'react';
8-
import { Collapse, DatePicker, Empty, Spin } from 'antd';
8+
import { Collapse, Empty } from 'antd';
99
import { FilterSection } from '@/components/insights/FilterSection';
1010
import { useTranslation } from '@i18next-toolkit/react';
1111
import { Layout } from '@/components/layout';
@@ -30,6 +30,9 @@ import { getUserTimezone } from '@/api/model/user';
3030
import { LuChevronDown } from 'react-icons/lu';
3131
import { cn } from '@/utils/style';
3232
import { get } from 'lodash-es';
33+
import { DelayRender } from '@/components/DelayRender';
34+
import { SearchLoadingView } from '@/components/loading/Searching';
35+
import { DateRangeSelection } from '@/components/insights/DateRangeSelection';
3336

3437
export const Route = createFileRoute('/insights/events')({
3538
beforeLoad: routeAuthBeforeLoad,
@@ -44,16 +47,15 @@ function PageComponent() {
4447
const filters = useInsightsStore((state) =>
4548
state.currentFilters.filter((f): f is NonNullable<typeof f> => !!f)
4649
);
50+
const dateKey = useInsightsStore((state) => state.currentDateKey);
51+
const dateRange = useInsightsStore((state) => state.currentDateRange);
52+
const setDateKey = useInsightsStore((state) => state.setCurrentDateKey);
53+
const setDateRange = useInsightsStore((state) => state.setCurrentDateRange);
54+
4755
const { data: websites = [] } = trpc.website.all.useQuery({ workspaceId });
4856
const { data: warehouseApplicationIds = [] } =
4957
trpc.insights.warehouseApplications.useQuery({ workspaceId });
5058

51-
// Date range state
52-
const [dateRange, setDateRange] = useState<[Dayjs, Dayjs]>([
53-
dayjs().subtract(7, 'day').startOf('day'),
54-
dayjs().endOf('day'),
55-
]);
56-
5759
// JSON mode state
5860
const [jsonMode, setJsonMode] = useState(false);
5961

@@ -170,18 +172,12 @@ function PageComponent() {
170172
<div className="mx-auto flex h-full flex-col overflow-hidden p-4">
171173
<div className="mb-4 flex items-center gap-2 md:flex-row">
172174
<div className="flex items-center gap-2">
173-
<span>{t('Date Range')}</span>
174-
<DatePicker.RangePicker
175-
value={dateRange}
176-
onChange={(val) => {
177-
if (val && val[0] && val[1]) {
178-
setDateRange([
179-
dayjs(val[0]).startOf('day'),
180-
dayjs(val[1]).endOf('day'),
181-
]);
182-
}
175+
<DateRangeSelection
176+
value={dateKey}
177+
onChange={(key, range) => {
178+
setDateKey(key);
179+
setDateRange(range);
183180
}}
184-
allowClear={false}
185181
/>
186182
</div>
187183

@@ -201,9 +197,11 @@ function PageComponent() {
201197

202198
<ScrollArea className="flex-1 overflow-hidden">
203199
{isFetching ? (
204-
<div className="flex h-40 items-center justify-center">
205-
<Spin />
206-
</div>
200+
<DelayRender>
201+
<div className="flex h-40 items-center justify-center">
202+
<SearchLoadingView className="pt-4" />
203+
</div>
204+
</DelayRender>
207205
) : data.length === 0 ? (
208206
<Empty description={t('No event data yet')} />
209207
) : (
@@ -291,9 +289,12 @@ function PageComponent() {
291289
<TabsTrigger value="event">
292290
{t('Event')}
293291
</TabsTrigger>
294-
<TabsTrigger value="session">
295-
{t('Session')}
296-
</TabsTrigger>
292+
293+
{Object.keys(cleanedSessions).length > 0 && (
294+
<TabsTrigger value="session">
295+
{t('Session')}
296+
</TabsTrigger>
297+
)}
297298
</TabsList>
298299
<TabsContent value="all">
299300
{renderGrid({

src/server/model/insights/warehouse/longTable.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
import { Prisma } from '@prisma/client';
6-
import { InsightsSqlBuilder } from '../shared.js';
6+
import { InsightEvent, InsightsSqlBuilder } from '../shared.js';
77
import { insightsQuerySchema } from '../../../utils/schema.js';
88
import { z } from 'zod';
99
import dayjs from 'dayjs';
@@ -58,6 +58,14 @@ export class WarehouseLongTableInsightsSqlBuilder extends InsightsSqlBuilder {
5858
return this.getEventTable().name;
5959
}
6060

61+
protected getCreateAtFieldName(): string {
62+
return this.getEventTable().createdAtField;
63+
}
64+
65+
protected getDistinctFieldName(): string {
66+
return this.getEventTable().eventNameField;
67+
}
68+
6169
private getValueField(type: FilterInfoType): Prisma.Sql {
6270
const eventParametersTable = this.getEventParametersTable();
6371

@@ -364,6 +372,53 @@ export class WarehouseLongTableInsightsSqlBuilder extends InsightsSqlBuilder {
364372

365373
return rows as any[];
366374
}
375+
376+
public buildFetchEventsQuery(cursor: string | undefined): Prisma.Sql {
377+
return super.buildFetchEventsQuery(cursor);
378+
}
379+
380+
public async queryEvents(
381+
cursor: string | undefined
382+
): Promise<InsightEvent[]> {
383+
const allEventsSql = this.buildFetchEventsQuery(cursor);
384+
const rows = await this.executeQuery(allEventsSql);
385+
386+
const createdAtType =
387+
this.getEventTable().createdAtFieldType ?? 'timestampMs';
388+
389+
function normalizeCreatedAt(val: any): Date {
390+
if (val == null) return new Date(0);
391+
if (createdAtType === 'timestamp') {
392+
const num = typeof val === 'string' ? Number(val) : val;
393+
return new Date(Number(num) * 1000);
394+
}
395+
if (createdAtType === 'timestampMs') {
396+
const num = typeof val === 'string' ? Number(val) : val;
397+
return new Date(Number(num));
398+
}
399+
// 'date' or 'datetime'
400+
return new Date(val);
401+
}
402+
403+
return rows.map((row) => {
404+
const distinctId = String(
405+
row.distinctId ?? row[this.getDistinctFieldName()] ?? ''
406+
);
407+
const createdAt = normalizeCreatedAt(
408+
row.createdAt ?? row[this.getCreateAtFieldName()]
409+
);
410+
const eventName = String(
411+
row[this.getEventTable().eventNameField] ?? distinctId
412+
);
413+
414+
return {
415+
id: distinctId || `${eventName}-${createdAt.getTime()}`,
416+
name: eventName,
417+
createdAt,
418+
properties: { ...row },
419+
};
420+
});
421+
}
367422
}
368423

369424
export async function insightsLongTableWarehouse(

src/server/model/insights/warehouse/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const dateTypeSchema = z.enum([
2121
const warehouseLongTableInsightsApplicationSchema = z.object({
2222
databaseUrl: z.string().optional(),
2323
name: z.string(),
24-
type: z.literal('longTable').optional(), // long table, default
24+
type: z.literal('longTable'), // long table
2525
eventTable: z.object({
2626
name: z.string(),
2727
eventNameField: z.string(),

0 commit comments

Comments
 (0)