add event type filter button and implementation to journeys Close #2803
Some checks failed
Node.js CI / build (push) Has been cancelled

This commit is contained in:
Francis Cao 2026-01-24 10:09:10 -08:00
parent 355fa1e9a9
commit 128217c0f4
5 changed files with 39 additions and 4 deletions

View file

@ -21,9 +21,15 @@ export interface JourneyProps {
steps: number; steps: number;
startStep?: string; startStep?: string;
endStep?: string; endStep?: string;
view: string;
} }
export function Journey({ websiteId, steps, startStep, endStep }: JourneyProps) { const EVENT_TYPES = {
views: 1,
events: 2,
};
export function Journey({ websiteId, steps, startStep, endStep, view }: JourneyProps) {
const [selectedNode, setSelectedNode] = useState(null); const [selectedNode, setSelectedNode] = useState(null);
const [activeNode, setActiveNode] = useState(null); const [activeNode, setActiveNode] = useState(null);
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
@ -32,6 +38,8 @@ export function Journey({ websiteId, steps, startStep, endStep }: JourneyProps)
steps, steps,
startStep, startStep,
endStep, endStep,
view,
eventType: EVENT_TYPES[view],
}); });
useEscapeKey(() => setSelectedNode(null)); useEscapeKey(() => setSelectedNode(null));

View file

@ -1,5 +1,6 @@
'use client'; 'use client';
import { Column, Grid, ListItem, SearchField, Select } from '@umami/react-zen'; import { Column, Grid, ListItem, Row, SearchField, Select } from '@umami/react-zen';
import { FilterButtons } from 'dist';
import { useState } from 'react'; import { useState } from 'react';
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls'; import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
import { Panel } from '@/components/common/Panel'; import { Panel } from '@/components/common/Panel';
@ -14,10 +15,26 @@ export function JourneysPage({ websiteId }: { websiteId: string }) {
const { const {
dateRange: { startDate, endDate }, dateRange: { startDate, endDate },
} = useDateRange(); } = useDateRange();
const [view, setView] = useState('all');
const [steps, setSteps] = useState(DEFAULT_STEP); const [steps, setSteps] = useState(DEFAULT_STEP);
const [startStep, setStartStep] = useState(''); const [startStep, setStartStep] = useState('');
const [endStep, setEndStep] = useState(''); const [endStep, setEndStep] = useState('');
const buttons = [
{
id: 'all',
label: formatMessage(labels.all),
},
{
id: 'views',
label: formatMessage(labels.views),
},
{
id: 'events',
label: formatMessage(labels.events),
},
];
return ( return (
<Column gap> <Column gap>
<WebsiteControls websiteId={websiteId} /> <WebsiteControls websiteId={websiteId} />
@ -52,6 +69,9 @@ export function JourneysPage({ websiteId }: { websiteId: string }) {
/> />
</Column> </Column>
</Grid> </Grid>
<Row justifyContent="flex-end">
<FilterButtons items={buttons} value={view} onChange={setView} />
</Row>
<Panel height="900px" allowFullscreen> <Panel height="900px" allowFullscreen>
<Journey <Journey
websiteId={websiteId} websiteId={websiteId}
@ -60,6 +80,7 @@ export function JourneysPage({ websiteId }: { websiteId: string }) {
steps={steps} steps={steps}
startStep={startStep} startStep={startStep}
endStep={endStep} endStep={endStep}
view={view}
/> />
</Panel> </Panel>
</Column> </Column>

View file

@ -12,11 +12,16 @@ export async function POST(request: Request) {
} }
const { websiteId, parameters, filters } = body; const { websiteId, parameters, filters } = body;
const { eventType } = parameters;
if (!(await canViewWebsite(auth, websiteId))) { if (!(await canViewWebsite(auth, websiteId))) {
return unauthorized(); return unauthorized();
} }
if (eventType) {
filters.eventType = eventType;
}
const queryFilters = await getQueryFilters(filters, websiteId); const queryFilters = await getQueryFilters(filters, websiteId);
const data = await getJourney(websiteId, parameters, queryFilters); const data = await getJourney(websiteId, parameters, queryFilters);

View file

@ -166,6 +166,7 @@ export const journeyReportSchema = z.object({
steps: z.coerce.number().min(2).max(7), steps: z.coerce.number().min(2).max(7),
startStep: z.string().optional(), startStep: z.string().optional(),
endStep: z.string().optional(), endStep: z.string().optional(),
eventType: z.coerce.number().int().positive().optional(),
}), }),
}); });

View file

@ -60,7 +60,7 @@ async function relationalQuery(
endStepQuery: string; endStepQuery: string;
params: Record<string, string>; params: Record<string, string>;
} { } {
const params = {}; const params: { startStep?: string; endStep?: string } = {};
let sequenceQuery = ''; let sequenceQuery = '';
let startStepQuery = ''; let startStepQuery = '';
let endStepQuery = ''; let endStepQuery = '';
@ -172,7 +172,7 @@ async function clickhouseQuery(
endStepQuery: string; endStepQuery: string;
params: Record<string, string>; params: Record<string, string>;
} { } {
const params = {}; const params: { startStep?: string; endStep?: string } = {};
let sequenceQuery = ''; let sequenceQuery = '';
let startStepQuery = ''; let startStepQuery = '';
let endStepQuery = ''; let endStepQuery = '';