mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 12:47:13 +01:00
Merge branch 'dev' into jajaja
# Conflicts: # pnpm-lock.yaml # postcss.config.js # src/app/(main)/websites/[websiteId]/sessions/SessionsDataTable.tsx # src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionInfo.tsx
This commit is contained in:
commit
c0ccffeab4
21 changed files with 382 additions and 1281 deletions
|
|
@ -14,7 +14,7 @@ export function SessionsDataTable({
|
|||
const queryResult = useWebsiteSessionsQuery(websiteId);
|
||||
|
||||
return (
|
||||
<DataGrid queryResult={queryResult} allowSearch={false} renderEmpty={() => children}>
|
||||
<DataGrid queryResult={queryResult} allowSearch={true} renderEmpty={() => children}>
|
||||
{({ data }) => <SessionsTable data={data} showDomain={!websiteId} />}
|
||||
</DataGrid>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@ export function SessionInfo({ data }) {
|
|||
<TextField value={data?.id} allowCopy />
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Label>{formatMessage(labels.distinctId)}</Label>
|
||||
<Row>{data?.distinctId}</Row>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Label>{formatMessage(labels.lastSeen)}</Label>
|
||||
<Row>{formatTimezoneDate(data?.lastAt, 'PPPPpp')}</Row>
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ export async function POST(request: Request) {
|
|||
country,
|
||||
region,
|
||||
city,
|
||||
distinctId: id,
|
||||
});
|
||||
} catch (e: any) {
|
||||
if (!e.message.toLowerCase().includes('unique constraint')) {
|
||||
|
|
@ -144,7 +145,7 @@ export async function POST(request: Request) {
|
|||
const base = hostname ? `https://${hostname}` : 'https://localhost';
|
||||
const currentUrl = new URL(url, base);
|
||||
|
||||
let urlPath = currentUrl.pathname;
|
||||
let urlPath = currentUrl.pathname === '/undefined' ? '' : currentUrl.pathname;
|
||||
const urlQuery = currentUrl.search.substring(1);
|
||||
const urlDomain = currentUrl.hostname.replace(/^www./, '');
|
||||
|
||||
|
|
@ -215,6 +216,7 @@ export async function POST(request: Request) {
|
|||
region,
|
||||
city,
|
||||
tag,
|
||||
distinctId: id,
|
||||
createdAt,
|
||||
});
|
||||
}
|
||||
|
|
@ -228,6 +230,7 @@ export async function POST(request: Request) {
|
|||
websiteId,
|
||||
sessionId,
|
||||
sessionData: data,
|
||||
distinctId: id,
|
||||
createdAt,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ export const labels = defineMessages({
|
|||
all: { id: 'label.all', defaultMessage: 'All' },
|
||||
session: { id: 'label.session', defaultMessage: 'Session' },
|
||||
sessions: { id: 'label.sessions', defaultMessage: 'Sessions' },
|
||||
distinctId: { id: 'label.distinct-id', defaultMessage: 'Distinct ID' },
|
||||
pageNotFound: { id: 'message.page-not-found', defaultMessage: 'Page not found' },
|
||||
activity: { id: 'label.activity', defaultMessage: 'Activity' },
|
||||
dismiss: { id: 'label.dismiss', defaultMessage: 'Dismiss' },
|
||||
|
|
|
|||
|
|
@ -33,17 +33,7 @@ export const FILTER_REFERRERS = 'filter-referrers';
|
|||
export const FILTER_PAGES = 'filter-pages';
|
||||
|
||||
export const UNIT_TYPES = ['year', 'month', 'hour', 'day', 'minute'];
|
||||
export const EVENT_COLUMNS = [
|
||||
'url',
|
||||
'entry',
|
||||
'exit',
|
||||
'referrer',
|
||||
'title',
|
||||
'query',
|
||||
'event',
|
||||
'tag',
|
||||
'region',
|
||||
];
|
||||
export const EVENT_COLUMNS = ['url', 'entry', 'exit', 'referrer', 'title', 'query', 'event', 'tag'];
|
||||
|
||||
export const SESSION_COLUMNS = [
|
||||
'browser',
|
||||
|
|
@ -53,6 +43,7 @@ export const SESSION_COLUMNS = [
|
|||
'language',
|
||||
'country',
|
||||
'city',
|
||||
'region',
|
||||
'host',
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export async function saveEvent(args: {
|
|||
region?: string;
|
||||
city?: string;
|
||||
tag?: string;
|
||||
distinctId?: string;
|
||||
createdAt?: Date;
|
||||
}) {
|
||||
return runQuery({
|
||||
|
|
@ -182,6 +183,7 @@ async function clickhouseQuery(data: {
|
|||
region?: string;
|
||||
city?: string;
|
||||
tag?: string;
|
||||
distinctId?: string;
|
||||
createdAt?: Date;
|
||||
}) {
|
||||
const {
|
||||
|
|
@ -211,6 +213,7 @@ async function clickhouseQuery(data: {
|
|||
region,
|
||||
city,
|
||||
tag,
|
||||
distinctId,
|
||||
createdAt,
|
||||
...args
|
||||
} = data;
|
||||
|
|
@ -247,6 +250,7 @@ async function clickhouseQuery(data: {
|
|||
event_type: eventName ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
|
||||
event_name: eventName ? eventName?.substring(0, EVENT_NAME_LENGTH) : null,
|
||||
tag: tag,
|
||||
distinct_id: distinctId,
|
||||
created_at: getUTCString(createdAt),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,19 @@ import { Prisma } from '@prisma/client';
|
|||
import prisma from '@/lib/prisma';
|
||||
|
||||
export async function createSession(data: Prisma.SessionCreateInput) {
|
||||
const { id, websiteId, browser, os, device, screen, language, country, region, city } = data;
|
||||
const {
|
||||
id,
|
||||
websiteId,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
region,
|
||||
city,
|
||||
distinctId,
|
||||
} = data;
|
||||
|
||||
return prisma.client.session.create({
|
||||
data: {
|
||||
|
|
@ -16,6 +28,7 @@ export async function createSession(data: Prisma.SessionCreateInput) {
|
|||
country,
|
||||
region,
|
||||
city,
|
||||
distinctId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ async function relationalQuery(websiteId: string, sessionId: string) {
|
|||
return rawQuery(
|
||||
`
|
||||
select id,
|
||||
distinct_id as "distinctId",
|
||||
website_id as "websiteId",
|
||||
hostname,
|
||||
browser,
|
||||
|
|
@ -33,6 +34,7 @@ async function relationalQuery(websiteId: string, sessionId: string) {
|
|||
sum(${getTimestampDiffSQL('min_time', 'max_time')}) as "totaltime"
|
||||
from (select
|
||||
session.session_id as id,
|
||||
session.distinct_id,
|
||||
website_event.visit_id,
|
||||
session.website_id,
|
||||
website_event.hostname,
|
||||
|
|
@ -52,8 +54,8 @@ async function relationalQuery(websiteId: string, sessionId: string) {
|
|||
join website_event on website_event.session_id = session.session_id
|
||||
where session.website_id = {{websiteId::uuid}}
|
||||
and session.session_id = {{sessionId::uuid}}
|
||||
group by session.session_id, visit_id, session.website_id, website_event.hostname, session.browser, session.os, session.device, session.screen, session.language, session.country, session.region, session.city) t
|
||||
group by id, website_id, hostname, browser, os, device, screen, language, country, region, city;
|
||||
group by session.session_id, session.distinct_id, visit_id, session.website_id, website_event.hostname, session.browser, session.os, session.device, session.screen, session.language, session.country, session.region, session.city) t
|
||||
group by id, distinct_id, website_id, hostname, browser, os, device, screen, language, country, region, city;
|
||||
`,
|
||||
{ websiteId, sessionId },
|
||||
).then(result => result?.[0]);
|
||||
|
|
@ -66,6 +68,7 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
|
|||
`
|
||||
select id,
|
||||
websiteId,
|
||||
distinctId,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
|
|
@ -83,6 +86,7 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
|
|||
sum(max_time-min_time) as totaltime
|
||||
from (select
|
||||
session_id as id,
|
||||
distinct_id as distinctId,
|
||||
visit_id,
|
||||
website_id as websiteId,
|
||||
hostname,
|
||||
|
|
@ -101,8 +105,8 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
|
|||
from website_event_stats_hourly
|
||||
where website_id = {websiteId:UUID}
|
||||
and session_id = {sessionId:UUID}
|
||||
group by session_id, visit_id, website_id, hostname, browser, os, device, screen, language, country, region, city) t
|
||||
group by id, websiteId, hostname, browser, os, device, screen, language, country, region, city;
|
||||
group by session_id, distinct_id, visit_id, website_id, hostname, browser, os, device, screen, language, country, region, city) t
|
||||
group by id, websiteId, distinctId, hostname, browser, os, device, screen, language, country, region, city;
|
||||
`,
|
||||
{ websiteId, sessionId },
|
||||
).then(result => result?.[0]);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import clickhouse from '@/lib/clickhouse';
|
||||
import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db';
|
||||
import { CLICKHOUSE, getDatabaseType, POSTGRESQL, PRISMA, runQuery } from '@/lib/db';
|
||||
import prisma from '@/lib/prisma';
|
||||
import { PageParams, QueryFilters } from '@/lib/types';
|
||||
|
||||
|
|
@ -14,10 +14,14 @@ export async function getWebsiteSessions(
|
|||
|
||||
async function relationalQuery(websiteId: string, filters: QueryFilters, pageParams: PageParams) {
|
||||
const { pagedRawQuery, parseFilters } = prisma;
|
||||
const { search } = pageParams;
|
||||
const { filterQuery, params } = await parseFilters(websiteId, {
|
||||
...filters,
|
||||
});
|
||||
|
||||
const db = getDatabaseType();
|
||||
const like = db === POSTGRESQL ? 'ilike' : 'like';
|
||||
|
||||
return pagedRawQuery(
|
||||
`
|
||||
with sessions as (
|
||||
|
|
@ -43,6 +47,15 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
where website_event.website_id = {{websiteId::uuid}}
|
||||
and website_event.created_at between {{startDate}} and {{endDate}}
|
||||
${filterQuery}
|
||||
${
|
||||
search
|
||||
? `and (distinct_id ${like} {{search}}
|
||||
or city ${like} {{search}}
|
||||
or browser ${like} {{search}}
|
||||
or os ${like} {{search}}
|
||||
or device ${like} {{search}})`
|
||||
: ''
|
||||
}
|
||||
group by session.session_id,
|
||||
session.website_id,
|
||||
website_event.hostname,
|
||||
|
|
@ -58,7 +71,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
limit 1000)
|
||||
select * from sessions
|
||||
`,
|
||||
params,
|
||||
{ ...params, search: `%${search}%` },
|
||||
pageParams,
|
||||
);
|
||||
}
|
||||
|
|
@ -66,6 +79,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
async function clickhouseQuery(websiteId: string, filters: QueryFilters, pageParams?: PageParams) {
|
||||
const { pagedQuery, parseFilters, getDateStringSQL } = clickhouse;
|
||||
const { params, dateQuery, filterQuery } = await parseFilters(websiteId, filters);
|
||||
const { search } = pageParams;
|
||||
|
||||
return pagedQuery(
|
||||
`
|
||||
|
|
@ -91,12 +105,21 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar
|
|||
where website_id = {websiteId:UUID}
|
||||
${dateQuery}
|
||||
${filterQuery}
|
||||
${
|
||||
search
|
||||
? `and ((positionCaseInsensitive(distinct_id, {search:String}) > 0)
|
||||
or (positionCaseInsensitive(city, {search:String}) > 0)
|
||||
or (positionCaseInsensitive(browser, {search:String}) > 0)
|
||||
or (positionCaseInsensitive(os, {search:String}) > 0)
|
||||
or (positionCaseInsensitive(device, {search:String}) > 0))`
|
||||
: ''
|
||||
}
|
||||
group by session_id, website_id, hostname, browser, os, device, screen, language, country, region, city
|
||||
order by lastAt desc
|
||||
limit 1000)
|
||||
select * from sessions
|
||||
`,
|
||||
params,
|
||||
{ ...params, search },
|
||||
pageParams,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export async function saveSessionData(data: {
|
|||
websiteId: string;
|
||||
sessionId: string;
|
||||
sessionData: DynamicData;
|
||||
distinctId?: string;
|
||||
createdAt?: Date;
|
||||
}) {
|
||||
return runQuery({
|
||||
|
|
@ -23,10 +24,11 @@ export async function relationalQuery(data: {
|
|||
websiteId: string;
|
||||
sessionId: string;
|
||||
sessionData: DynamicData;
|
||||
distinctId?: string;
|
||||
createdAt?: Date;
|
||||
}) {
|
||||
const { client } = prisma;
|
||||
const { websiteId, sessionId, sessionData, createdAt } = data;
|
||||
const { websiteId, sessionId, sessionData, distinctId, createdAt } = data;
|
||||
|
||||
const jsonKeys = flattenJSON(sessionData);
|
||||
|
||||
|
|
@ -39,6 +41,7 @@ export async function relationalQuery(data: {
|
|||
numberValue: a.dataType === DATA_TYPE.number ? a.value : null,
|
||||
dateValue: a.dataType === DATA_TYPE.date ? new Date(a.value) : null,
|
||||
dataType: a.dataType,
|
||||
distinctId,
|
||||
createdAt,
|
||||
}));
|
||||
|
||||
|
|
@ -80,9 +83,10 @@ async function clickhouseQuery(data: {
|
|||
websiteId: string;
|
||||
sessionId: string;
|
||||
sessionData: DynamicData;
|
||||
distinctId?: string;
|
||||
createdAt?: Date;
|
||||
}) {
|
||||
const { websiteId, sessionId, sessionData, createdAt } = data;
|
||||
const { websiteId, sessionId, sessionData, distinctId, createdAt } = data;
|
||||
|
||||
const { insert, getUTCString } = clickhouse;
|
||||
const { sendMessage } = kafka;
|
||||
|
|
@ -98,6 +102,7 @@ async function clickhouseQuery(data: {
|
|||
string_value: getStringValue(value, dataType),
|
||||
number_value: dataType === DATA_TYPE.number ? value : null,
|
||||
date_value: dataType === DATA_TYPE.date ? getUTCString(value) : null,
|
||||
distinct_id: distinctId,
|
||||
created_at: getUTCString(createdAt),
|
||||
};
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue