From 822ddee9ae355298627bab4b4aa26370f45fdd0a Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 12 Aug 2025 09:15:42 -0700 Subject: [PATCH 1/3] update ch schema for custom data numbers --- db/clickhouse/schema.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index be277743..d6294d44 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -57,7 +57,7 @@ CREATE TABLE umami.event_data event_name String, data_key String, string_value Nullable(String), - number_value Nullable(Decimal64(22, 4)), + number_value Nullable(Decimal(22, 4)), date_value Nullable(DateTime('UTC')), data_type UInt32, created_at DateTime('UTC'), @@ -73,7 +73,7 @@ CREATE TABLE umami.session_data session_id UUID, data_key String, string_value Nullable(String), - number_value Nullable(Decimal64(22, 4)), + number_value Nullable(Decimal(22, 4)), date_value Nullable(DateTime('UTC')), data_type UInt32, distinct_id String, From 6829d968625321a4a297636e7702fb68a266aec1 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 12 Aug 2025 11:30:46 -0700 Subject: [PATCH 2/3] update UTM report to use new UTM columns --- .../[websiteId]/(reports)/utm/UTM.tsx | 38 +++++++------------ .../websites/[websiteId]/WebsiteLayout.tsx | 2 +- src/app/api/reports/utm/route.ts | 13 ++++++- src/queries/sql/reports/getUTM.ts | 21 ++++++---- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx index f2aadec9..47c17b6a 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx @@ -1,12 +1,10 @@ -import { Grid, Column, Heading, Text } from '@umami/react-zen'; -import { firstBy } from 'thenby'; -import { CHART_COLORS, UTM_PARAMS } from '@/lib/constants'; -import { useResultQuery } from '@/components/hooks'; import { PieChart } from '@/components/charts/PieChart'; -import { ListTable } from '@/components/metrics/ListTable'; -import { useMessages } from '@/components/hooks'; -import { Panel } from '@/components/common/Panel'; import { LoadingPanel } from '@/components/common/LoadingPanel'; +import { Panel } from '@/components/common/Panel'; +import { useMessages, useResultQuery } from '@/components/hooks'; +import { ListTable } from '@/components/metrics/ListTable'; +import { CHART_COLORS, UTM_PARAMS } from '@/lib/constants'; +import { Column, Grid, Heading, Text } from '@umami/react-zen'; export interface UTMProps { websiteId: string; @@ -27,19 +25,19 @@ export function UTM({ websiteId, startDate, endDate }: UTMProps) { {data && ( {UTM_PARAMS.map(param => { - const items = toArray(data?.[param]); + const items = data?.[param]; const chartData = { - labels: items.map(({ name }) => name), + labels: items.map(({ utm }) => utm), datasets: [ { - data: items.map(({ value }) => value), + data: items.map(({ views }) => views), backgroundColor: CHART_COLORS, borderWidth: 0, }, ], }; - const total = items.reduce((sum, { value }) => { - return +sum + +value; + const total = items.reduce((sum, { views }) => { + return +sum + +views; }, 0); return ( @@ -51,10 +49,10 @@ export function UTM({ websiteId, startDate, endDate }: UTMProps) { ({ - x: name, - y: value, - z: (value / total) * 100, + data={items.map(({ utm, views }) => ({ + x: utm, + y: views, + z: (views / total) * 100, }))} /> @@ -70,11 +68,3 @@ export function UTM({ websiteId, startDate, endDate }: UTMProps) { ); } - -function toArray(data: Record = {}) { - return Object.keys(data) - .map(key => { - return { name: key, value: data[key] }; - }) - .sort(firstBy('value', -1)); -} diff --git a/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx b/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx index b095afdb..152c2a8f 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx @@ -10,7 +10,7 @@ export function WebsiteLayout({ websiteId, children }: { websiteId: string; chil return ( - + diff --git a/src/app/api/reports/utm/route.ts b/src/app/api/reports/utm/route.ts index 150773f7..9da8390f 100644 --- a/src/app/api/reports/utm/route.ts +++ b/src/app/api/reports/utm/route.ts @@ -3,6 +3,7 @@ import { unauthorized, json } from '@/lib/response'; import { getQueryFilters, parseRequest, setWebsiteDate } from '@/lib/request'; import { getUTM, UTMParameters } from '@/queries'; import { reportResultSchema } from '@/lib/schema'; +import { UTM_PARAMS } from '@/lib/constants'; export async function POST(request: Request) { const { auth, body, error } = await parseRequest(request, reportResultSchema); @@ -20,7 +21,17 @@ export async function POST(request: Request) { const filters = await getQueryFilters(body.filters, websiteId); const parameters = await setWebsiteDate(websiteId, body.parameters); - const data = await getUTM(websiteId, parameters as UTMParameters, filters); + const data = { + utm_source: [], + utm_medium: [], + utm_campaign: [], + utm_term: [], + utm_content: [], + }; + + for (const key of UTM_PARAMS) { + data[key] = await getUTM(websiteId, { column: key, ...parameters } as UTMParameters, filters); + } return json(data); } diff --git a/src/queries/sql/reports/getUTM.ts b/src/queries/sql/reports/getUTM.ts index f690be1c..3c7636f3 100644 --- a/src/queries/sql/reports/getUTM.ts +++ b/src/queries/sql/reports/getUTM.ts @@ -4,6 +4,7 @@ import prisma from '@/lib/prisma'; import { QueryFilters } from '@/lib/types'; export interface UTMParameters { + column: string; startDate: Date; endDate: Date; } @@ -22,10 +23,10 @@ async function relationalQuery( parameters: UTMParameters, filters: QueryFilters, ) { - const { startDate, endDate } = parameters; + const { column, startDate, endDate } = parameters; const { parseFilters, rawQuery } = prisma; - const { filterQuery, queryParams } = parseFilters({ + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, startDate, @@ -34,14 +35,16 @@ async function relationalQuery( return rawQuery( ` - select url_query, count(*) as "num" + select ${column} utm, count(*) as views from website_event + ${cohortQuery} where website_id = {{websiteId::uuid}} and created_at between {{startDate}} and {{endDate}} - and coalesce(url_query, '') != '' + and coalesce(${column}, '') != '' and event_type = 1 ${filterQuery} group by 1 + order by 2 desc `, queryParams, ); @@ -52,9 +55,9 @@ async function clickhouseQuery( parameters: UTMParameters, filters: QueryFilters, ) { - const { startDate, endDate } = parameters; + const { column, startDate, endDate } = parameters; const { parseFilters, rawQuery } = clickhouse; - const { filterQuery, queryParams } = parseFilters({ + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, startDate, @@ -63,14 +66,16 @@ async function clickhouseQuery( return rawQuery( ` - select url_query, count(*) as "num" + select ${column} utm, count(*) as views from website_event + ${cohortQuery} where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and url_query != '' + and ${column} != '' and event_type = 1 ${filterQuery} group by 1 + order by 2 desc `, queryParams, ); From 69aa4ca03598fe11ac227db54c82bcfff5324172 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 12 Aug 2025 16:13:44 -0700 Subject: [PATCH 3/3] cleanup cohort/filtering for some queries --- .../websites/[websiteId]/events/EventProperties.tsx | 2 +- .../websites/[websiteId]/metrics/expanded/route.ts | 2 +- src/queries/sql/events/getEventMetrics.ts | 10 +++++----- src/queries/sql/getChannelExpandedMetrics.ts | 13 ++++--------- src/queries/sql/pageviews/getPageviewMetrics.ts | 4 ++-- src/queries/sql/reports/getUTM.ts | 5 +++-- src/queries/sql/sessions/getSessionStats.ts | 1 + 7 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx index 25e65405..26d2f265 100644 --- a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx +++ b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx @@ -36,7 +36,7 @@ export function EventProperties({ websiteId }: { websiteId: string }) { gap="6" > {data && ( - +