diff --git a/prisma/migrations/15_add_share/migration.sql b/prisma/migrations/15_add_share/migration.sql
index 3971b54c..89aece1e 100644
--- a/prisma/migrations/15_add_share/migration.sql
+++ b/prisma/migrations/15_add_share/migration.sql
@@ -2,8 +2,8 @@
CREATE TABLE "share" (
"share_id" UUID NOT NULL,
"entity_id" UUID NOT NULL,
- "share_type" INTEGER NOT NULL,
"name" VARCHAR(200) NOT NULL,
+ "share_type" INTEGER NOT NULL,
"slug" VARCHAR(100) NOT NULL,
"parameters" JSONB NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
@@ -12,9 +12,6 @@ CREATE TABLE "share" (
CONSTRAINT "share_pkey" PRIMARY KEY ("share_id")
);
--- CreateIndex
-CREATE UNIQUE INDEX "share_share_id_key" ON "share"("share_id");
-
-- CreateIndex
CREATE UNIQUE INDEX "share_slug_key" ON "share"("slug");
@@ -28,7 +25,7 @@ SELECT gen_random_uuid(),
name,
1,
share_id,
- '{}'::jsonb,
+ '{"overview":true}'::jsonb,
now()
FROM "website"
WHERE share_id IS NOT NULL;
diff --git a/prisma/migrations/16_boards/migration.sql b/prisma/migrations/16_boards/migration.sql
index ef0b28dc..ad8ee172 100644
--- a/prisma/migrations/16_boards/migration.sql
+++ b/prisma/migrations/16_boards/migration.sql
@@ -14,9 +14,6 @@ CREATE TABLE "board" (
CONSTRAINT "board_pkey" PRIMARY KEY ("board_id")
);
--- CreateIndex
-CREATE UNIQUE INDEX "board_board_id_key" ON "board"("board_id");
-
-- CreateIndex
CREATE UNIQUE INDEX "board_slug_key" ON "board"("slug");
diff --git a/prisma/migrations/17_remove_duplicate_key/migration.sql b/prisma/migrations/17_remove_duplicate_key/migration.sql
index a49eed8f..75f7191e 100644
--- a/prisma/migrations/17_remove_duplicate_key/migration.sql
+++ b/prisma/migrations/17_remove_duplicate_key/migration.sql
@@ -1,6 +1,3 @@
--- DropIndex
-DROP INDEX "board_board_id_key";
-
-- DropIndex
DROP INDEX "link_link_id_key";
@@ -19,9 +16,6 @@ DROP INDEX "segment_segment_id_key";
-- DropIndex
DROP INDEX "session_session_id_key";
--- DropIndex
-DROP INDEX "share_share_id_key";
-
-- DropIndex
DROP INDEX "team_team_id_key";
diff --git a/src/app/(main)/admin/teams/AdminTeamsPage.tsx b/src/app/(main)/admin/teams/AdminTeamsPage.tsx
index 41e6f4af..7905f7f6 100644
--- a/src/app/(main)/admin/teams/AdminTeamsPage.tsx
+++ b/src/app/(main)/admin/teams/AdminTeamsPage.tsx
@@ -3,14 +3,19 @@ import { Column } from '@umami/react-zen';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
import { useMessages } from '@/components/hooks';
+import { TeamsAddButton } from '../../teams/TeamsAddButton';
import { AdminTeamsDataTable } from './AdminTeamsDataTable';
export function AdminTeamsPage() {
const { formatMessage, labels } = useMessages();
+ const handleSave = () => {};
+
return (
-
+
+
+
diff --git a/src/app/(main)/teams/TeamAddForm.tsx b/src/app/(main)/teams/TeamAddForm.tsx
index c95259f4..3b827776 100644
--- a/src/app/(main)/teams/TeamAddForm.tsx
+++ b/src/app/(main)/teams/TeamAddForm.tsx
@@ -7,8 +7,17 @@ import {
TextField,
} from '@umami/react-zen';
import { useMessages, useUpdateQuery } from '@/components/hooks';
+import { UserSelect } from '@/components/input/UserSelect';
-export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) {
+export function TeamAddForm({
+ onSave,
+ onClose,
+ isAdmin,
+}: {
+ onSave: () => void;
+ onClose: () => void;
+ isAdmin: boolean;
+}) {
const { formatMessage, labels, getErrorMessage } = useMessages();
const { mutateAsync, error, isPending } = useUpdateQuery('/teams');
@@ -26,6 +35,11 @@ export function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose:
+ {isAdmin && (
+
+
+
+ )}
diff --git a/src/app/(main)/teams/TeamsMemberAddButton.tsx b/src/app/(main)/teams/TeamsMemberAddButton.tsx
new file mode 100644
index 00000000..f1bbf258
--- /dev/null
+++ b/src/app/(main)/teams/TeamsMemberAddButton.tsx
@@ -0,0 +1,40 @@
+import { Button, Dialog, DialogTrigger, Icon, Modal, Text, useToast } from '@umami/react-zen';
+import { useMessages, useModified } from '@/components/hooks';
+import { Plus } from '@/components/icons';
+import { messages } from '@/components/messages';
+import { TeamMemberAddForm } from './TeamMemberAddForm';
+
+export function TeamsMemberAddButton({
+ teamId,
+ onSave,
+}: {
+ teamId: string;
+ onSave?: () => void;
+ isAdmin?: boolean;
+}) {
+ const { formatMessage, labels } = useMessages();
+ const { toast } = useToast();
+ const { touch } = useModified();
+
+ const handleSave = async () => {
+ toast(formatMessage(messages.saved));
+ touch('teams:members');
+ onSave?.();
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/teams/[teamId]/TeamSettings.tsx b/src/app/(main)/teams/[teamId]/TeamSettings.tsx
index 3ddbe000..4bbb8905 100644
--- a/src/app/(main)/teams/[teamId]/TeamSettings.tsx
+++ b/src/app/(main)/teams/[teamId]/TeamSettings.tsx
@@ -1,10 +1,12 @@
-import { Column } from '@umami/react-zen';
+import { Column, Heading, Row } from '@umami/react-zen';
import { TeamLeaveButton } from '@/app/(main)/teams/TeamLeaveButton';
import { PageHeader } from '@/components/common/PageHeader';
import { Panel } from '@/components/common/Panel';
-import { useLoginQuery, useNavigation, useTeam } from '@/components/hooks';
+import { useLoginQuery, useMessages, useNavigation, useTeam } from '@/components/hooks';
import { Users } from '@/components/icons';
+import { labels } from '@/components/messages';
import { ROLES } from '@/lib/constants';
+import { TeamsMemberAddButton } from '../TeamsMemberAddButton';
import { TeamEditForm } from './TeamEditForm';
import { TeamManage } from './TeamManage';
import { TeamMembersDataTable } from './TeamMembersDataTable';
@@ -13,6 +15,7 @@ export function TeamSettings({ teamId }: { teamId: string }) {
const team: any = useTeam();
const { user } = useLoginQuery();
const { pathname } = useNavigation();
+ const { formatMessage } = useMessages();
const isAdmin = pathname.includes('/admin');
@@ -37,6 +40,10 @@ export function TeamSettings({ teamId }: { teamId: string }) {
+
+ {formatMessage(labels.members)}
+ {isAdmin && }
+
{isTeamOwner && (
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx b/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx
index 3327a425..1b893d27 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx
@@ -21,9 +21,15 @@ export interface JourneyProps {
steps: number;
startStep?: 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 [activeNode, setActiveNode] = useState(null);
const { formatMessage, labels } = useMessages();
@@ -32,6 +38,8 @@ export function Journey({ websiteId, steps, startStep, endStep }: JourneyProps)
steps,
startStep,
endStep,
+ view,
+ eventType: EVENT_TYPES[view],
});
useEscapeKey(() => setSelectedNode(null));
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
index 14b8341d..c2dd8349 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
@@ -1,5 +1,6 @@
'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 { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
import { Panel } from '@/components/common/Panel';
@@ -14,10 +15,26 @@ export function JourneysPage({ websiteId }: { websiteId: string }) {
const {
dateRange: { startDate, endDate },
} = useDateRange();
+ const [view, setView] = useState('all');
const [steps, setSteps] = useState(DEFAULT_STEP);
const [startStep, setStartStep] = 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 (
@@ -52,6 +69,9 @@ export function JourneysPage({ websiteId }: { websiteId: string }) {
/>
+
+
+
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
index b2ea2a83..896c733a 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
@@ -21,30 +21,28 @@ export function WebsiteChart({
const { pageviews, sessions, compare } = (data || {}) as any;
const chartData = useMemo(() => {
- if (data) {
- const result = {
- pageviews,
- sessions,
- };
+ if (!data) {
+ return { pageviews: [], sessions: [] };
+ }
- if (compare) {
- result.compare = {
- pageviews: result.pageviews.map(({ x }, i) => ({
+ return {
+ pageviews,
+ sessions,
+ ...(compare && {
+ compare: {
+ pageviews: pageviews.map(({ x }, i) => ({
x,
y: compare.pageviews[i]?.y,
d: compare.pageviews[i]?.x,
})),
- sessions: result.sessions.map(({ x }, i) => ({
+ sessions: sessions.map(({ x }, i) => ({
x,
y: compare.sessions[i]?.y,
d: compare.sessions[i]?.x,
})),
- };
- }
-
- return result;
- }
- return { pageviews: [], sessions: [] };
+ },
+ }),
+ };
}, [data, startDate, endDate, unit]);
return (
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx
index 29c3954f..4bac4ff6 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx
@@ -169,6 +169,12 @@ export function WebsiteExpandedMenu({
path: updateParams({ view: 'hostname' }),
icon: ,
},
+ {
+ id: 'distinctId',
+ label: formatMessage(labels.distinctId),
+ path: updateParams({ view: 'distinctId' }),
+ icon: ,
+ },
{
id: 'tag',
label: formatMessage(labels.tag),
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx
index 30189534..132d3b14 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx
@@ -10,7 +10,7 @@ import {
} from '@umami/react-zen';
import { Fragment } from 'react';
import { useMessages, useNavigation } from '@/components/hooks';
-import { Edit, More, Share } from '@/components/icons';
+import { Edit, MoreHorizontal, Share } from '@/components/icons';
export function WebsiteMenu({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
@@ -33,7 +33,7 @@ export function WebsiteMenu({ websiteId }: { websiteId: string }) {
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx
index 6c91ba6d..605ee385 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx
@@ -7,14 +7,18 @@ import { formatLongNumber, formatShortTime } from '@/lib/format';
export function WebsiteMetricsBar({
websiteId,
+ compareMode,
}: {
websiteId: string;
showChange?: boolean;
compareMode?: boolean;
}) {
- const { isAllTime } = useDateRange();
+ const { isAllTime, dateCompare } = useDateRange();
const { formatMessage, labels, getErrorMessage } = useMessages();
- const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(websiteId);
+ const { data, isLoading, isFetching, error } = useWebsiteStatsQuery({
+ websiteId,
+ compare: compareMode ? dateCompare?.compare : undefined,
+ });
const { pageviews, visitors, visits, bounces, totaltime, comparison } = data || {};
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx b/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx
index ad05b706..9f72c303 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx
@@ -29,6 +29,7 @@ export function WebsiteNav({
event: undefined,
compare: undefined,
view: undefined,
+ unit: undefined,
});
const items = [
diff --git a/src/app/(main)/websites/[websiteId]/WebsitePage.tsx b/src/app/(main)/websites/[websiteId]/WebsitePage.tsx
index f587e112..5acc9e68 100644
--- a/src/app/(main)/websites/[websiteId]/WebsitePage.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsitePage.tsx
@@ -1,7 +1,8 @@
'use client';
-import { Column } from '@umami/react-zen';
+import { Column, Row } from '@umami/react-zen';
import { ExpandedViewModal } from '@/app/(main)/websites/[websiteId]/ExpandedViewModal';
import { Panel } from '@/components/common/Panel';
+import { UnitFilter } from '@/components/input/UnitFilter';
import { WebsiteChart } from './WebsiteChart';
import { WebsiteControls } from './WebsiteControls';
import { WebsiteMetricsBar } from './WebsiteMetricsBar';
@@ -13,6 +14,9 @@ export function WebsitePage({ websiteId }: { websiteId: string }) {
+
+
+
diff --git a/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx b/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx
index bca8d244..32d641b0 100644
--- a/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx
+++ b/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx
@@ -10,7 +10,7 @@ export function ComparePage({ websiteId }: { websiteId: string }) {
return (
-
+
diff --git a/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx b/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx
index 13c05160..4daf17fc 100644
--- a/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx
+++ b/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx
@@ -93,6 +93,11 @@ export function CompareTables({ websiteId }: { websiteId: string }) {
label: formatMessage(labels.hostname),
path: renderPath('hostname'),
},
+ {
+ id: 'distinctId',
+ label: formatMessage(labels.distinctId),
+ path: renderPath('distinctId'),
+ },
{
id: 'tag',
label: formatMessage(labels.tags),
diff --git a/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx b/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
index 7fb2eb41..41c2b1e8 100644
--- a/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
+++ b/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
@@ -25,6 +25,19 @@ export function EventsTable(props: DataTableProps) {
const { updateParams } = useNavigation();
const { formatValue } = useFormat();
+ const renderLink = (label: string, hostname: string) => {
+ return (
+
+ {label}
+
+ );
+ };
+
return (
@@ -43,7 +56,7 @@ export function EventsTable(props: DataTableProps) {
title={row.eventName || row.urlPath}
truncate
>
- {row.eventName || row.urlPath}
+ {row.eventName || renderLink(row.urlPath, row.hostname)}
{row.hasData > 0 && }
diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
index 10763618..9cbbd371 100644
--- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
+++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
@@ -74,8 +74,9 @@ export function RealtimeLog({ data }: { data: any }) {
os: string;
country: string;
device: string;
+ hostname: string;
}) => {
- const { __type, eventName, urlPath, browser, os, country, device } = log;
+ const { __type, eventName, urlPath, browser, os, country, device, hostname } = log;
if (__type === TYPE_EVENT) {
return (
@@ -86,7 +87,8 @@ export function RealtimeLog({ data }: { data: any }) {
url: (
@@ -100,7 +102,12 @@ export function RealtimeLog({ data }: { data: any }) {
if (__type === TYPE_PAGEVIEW) {
return (
-
+
{urlPath}
);
diff --git a/src/app/(main)/websites/[websiteId]/sessions/SessionActivity.tsx b/src/app/(main)/websites/[websiteId]/sessions/SessionActivity.tsx
index cbb28108..df0ef834 100644
--- a/src/app/(main)/websites/[websiteId]/sessions/SessionActivity.tsx
+++ b/src/app/(main)/websites/[websiteId]/sessions/SessionActivity.tsx
@@ -39,10 +39,23 @@ export function SessionActivity({
const { isMobile } = useMobile();
let lastDay = null;
+ const renderLink = (label: string, hostname: string) => {
+ return (
+
+ {label}
+
+ );
+ };
+
return (
- {data?.map(({ eventId, createdAt, urlPath, eventName, visitId, hasData }) => {
+ {data?.map(({ eventId, createdAt, urlPath, eventName, visitId, hostname, hasData }) => {
const showHeader = !lastDay || !isSameDay(new Date(lastDay), new Date(createdAt));
lastDay = createdAt;
@@ -61,7 +74,7 @@ export function SessionActivity({
: formatMessage(labels.viewedPage)}
- {eventName || urlPath}
+ {eventName || renderLink(urlPath, hostname)}
{hasData > 0 && }
diff --git a/src/app/api/reports/journey/route.ts b/src/app/api/reports/journey/route.ts
index 29e85319..b53d225d 100644
--- a/src/app/api/reports/journey/route.ts
+++ b/src/app/api/reports/journey/route.ts
@@ -12,11 +12,16 @@ export async function POST(request: Request) {
}
const { websiteId, parameters, filters } = body;
+ const { eventType } = parameters;
if (!(await canViewWebsite(auth, websiteId))) {
return unauthorized();
}
+ if (eventType) {
+ filters.eventType = eventType;
+ }
+
const queryFilters = await getQueryFilters(filters, websiteId);
const data = await getJourney(websiteId, parameters, queryFilters);
diff --git a/src/app/api/teams/route.ts b/src/app/api/teams/route.ts
index 53ef5923..c571f405 100644
--- a/src/app/api/teams/route.ts
+++ b/src/app/api/teams/route.ts
@@ -28,6 +28,7 @@ export async function GET(request: Request) {
export async function POST(request: Request) {
const schema = z.object({
name: z.string().max(50),
+ ownerId: z.uuid().optional(),
});
const { auth, body, error } = await parseRequest(request, schema);
@@ -40,7 +41,7 @@ export async function POST(request: Request) {
return unauthorized();
}
- const { name } = body;
+ const { name, ownerId } = body;
const team = await createTeam(
{
@@ -48,7 +49,7 @@ export async function POST(request: Request) {
name,
accessCode: `team_${getRandomChars(16)}`,
},
- auth.user.id,
+ ownerId ?? auth.user.id,
);
return json(team);
diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts
index b7177b5d..9d21f4f5 100644
--- a/src/app/api/websites/[websiteId]/stats/route.ts
+++ b/src/app/api/websites/[websiteId]/stats/route.ts
@@ -31,9 +31,11 @@ export async function GET(
const data = await getWebsiteStats(websiteId, filters);
- const compare = filters.compare ?? 'prev';
-
- const { startDate, endDate } = getCompareDate(compare, filters.startDate, filters.endDate);
+ const { startDate, endDate } = getCompareDate(
+ filters.compare ?? 'prev',
+ filters.startDate,
+ filters.endDate,
+ );
const comparison = await getWebsiteStats(websiteId, {
...filters,
diff --git a/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts b/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts
index b2e90199..1611c7f8 100644
--- a/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts
+++ b/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts
@@ -19,7 +19,7 @@ export function useWebsiteExpandedMetricsQuery(
options?: ReactQueryOptions,
) {
const { get, useQuery } = useApi();
- const { startAt, endAt, unit, timezone } = useDateParameters();
+ const { startAt, endAt } = useDateParameters();
const filters = useFilterParameters();
return useQuery({
@@ -29,8 +29,6 @@ export function useWebsiteExpandedMetricsQuery(
websiteId,
startAt,
endAt,
- unit,
- timezone,
...filters,
...params,
},
@@ -39,8 +37,6 @@ export function useWebsiteExpandedMetricsQuery(
get(`/websites/${websiteId}/metrics/expanded`, {
startAt,
endAt,
- unit,
- timezone,
...filters,
...params,
}),
diff --git a/src/components/hooks/queries/useWebsiteMetricsQuery.ts b/src/components/hooks/queries/useWebsiteMetricsQuery.ts
index 67c5e4d4..cd064af6 100644
--- a/src/components/hooks/queries/useWebsiteMetricsQuery.ts
+++ b/src/components/hooks/queries/useWebsiteMetricsQuery.ts
@@ -15,7 +15,7 @@ export function useWebsiteMetricsQuery(
options?: ReactQueryOptions,
) {
const { get, useQuery } = useApi();
- const { startAt, endAt, unit, timezone } = useDateParameters();
+ const { startAt, endAt } = useDateParameters();
const filters = useFilterParameters();
return useQuery({
@@ -25,8 +25,6 @@ export function useWebsiteMetricsQuery(
websiteId,
startAt,
endAt,
- unit,
- timezone,
...filters,
...params,
},
@@ -35,8 +33,6 @@ export function useWebsiteMetricsQuery(
get(`/websites/${websiteId}/metrics`, {
startAt,
endAt,
- unit,
- timezone,
...filters,
...params,
}),
diff --git a/src/components/hooks/queries/useWebsiteStatsQuery.ts b/src/components/hooks/queries/useWebsiteStatsQuery.ts
index 69bae09f..48484a07 100644
--- a/src/components/hooks/queries/useWebsiteStatsQuery.ts
+++ b/src/components/hooks/queries/useWebsiteStatsQuery.ts
@@ -1,6 +1,5 @@
import type { UseQueryOptions } from '@tanstack/react-query';
import { useDateParameters } from '@/components/hooks/useDateParameters';
-import { useDateRange } from '@/components/hooks/useDateRange';
import { useApi } from '../useApi';
import { useFilterParameters } from '../useFilterParameters';
@@ -20,21 +19,16 @@ export interface WebsiteStatsData {
}
export function useWebsiteStatsQuery(
- websiteId: string,
+ { websiteId, compare }: { websiteId: string; compare?: string },
options?: UseQueryOptions,
) {
const { get, useQuery } = useApi();
- const { startAt, endAt, unit, timezone } = useDateParameters();
- const { compare } = useDateRange();
+ const { startAt, endAt } = useDateParameters();
const filters = useFilterParameters();
return useQuery({
- queryKey: [
- 'websites:stats',
- { websiteId, startAt, endAt, unit, timezone, compare, ...filters },
- ],
- queryFn: () =>
- get(`/websites/${websiteId}/stats`, { startAt, endAt, unit, timezone, compare, ...filters }),
+ queryKey: ['websites:stats', { websiteId, compare, startAt, endAt, ...filters }],
+ queryFn: () => get(`/websites/${websiteId}/stats`, { compare, startAt, endAt, ...filters }),
enabled: !!websiteId,
...options,
});
diff --git a/src/components/hooks/queries/useWeeklyTrafficQuery.ts b/src/components/hooks/queries/useWeeklyTrafficQuery.ts
index a76ebb3d..df729ffd 100644
--- a/src/components/hooks/queries/useWeeklyTrafficQuery.ts
+++ b/src/components/hooks/queries/useWeeklyTrafficQuery.ts
@@ -12,13 +12,12 @@ export function useWeeklyTrafficQuery(websiteId: string, params?: Record {
return get(`/websites/${websiteId}/sessions/weekly`, {
startAt,
endAt,
- unit,
timezone,
...params,
...filters,
diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts
index 755f36ee..5090bd3d 100644
--- a/src/components/hooks/useDateRange.ts
+++ b/src/components/hooks/useDateRange.ts
@@ -7,13 +7,13 @@ import { getItem } from '@/lib/storage';
export function useDateRange(options: { ignoreOffset?: boolean; timezone?: string } = {}) {
const {
- query: { date = '', offset = 0, compare = 'prev' },
+ query: { date = '', unit = '', offset = 0, compare = 'prev' },
} = useNavigation();
const { locale } = useLocale();
-
const dateRange = useMemo(() => {
const dateRangeObject = parseDateRange(
date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE,
+ unit,
locale,
options.timezone,
);
@@ -21,12 +21,13 @@ export function useDateRange(options: { ignoreOffset?: boolean; timezone?: strin
return !options.ignoreOffset && offset
? getOffsetDateRange(dateRangeObject, +offset)
: dateRangeObject;
- }, [date, offset, options]);
+ }, [date, unit, offset, options]);
const dateCompare = getCompareDate(compare, dateRange.startDate, dateRange.endDate);
return {
date,
+ unit,
offset,
compare,
isAllTime: date.endsWith(`:all`),
diff --git a/src/components/hooks/useFields.ts b/src/components/hooks/useFields.ts
index 22a1dcf3..039b7157 100644
--- a/src/components/hooks/useFields.ts
+++ b/src/components/hooks/useFields.ts
@@ -15,6 +15,7 @@ export function useFields() {
{ name: 'region', type: 'string', label: formatMessage(labels.region) },
{ name: 'city', type: 'string', label: formatMessage(labels.city) },
{ name: 'hostname', type: 'string', label: formatMessage(labels.hostname) },
+ { name: 'distinctId', type: 'string', label: formatMessage(labels.distinctId) },
{ name: 'tag', type: 'string', label: formatMessage(labels.tag) },
{ name: 'event', type: 'string', label: formatMessage(labels.event) },
];
diff --git a/src/components/hooks/useFilterParameters.ts b/src/components/hooks/useFilterParameters.ts
index 54032120..c141a3be 100644
--- a/src/components/hooks/useFilterParameters.ts
+++ b/src/components/hooks/useFilterParameters.ts
@@ -18,6 +18,7 @@ export function useFilterParameters() {
event,
tag,
hostname,
+ distinctId,
page,
pageSize,
search,
@@ -42,6 +43,7 @@ export function useFilterParameters() {
event,
tag,
hostname,
+ distinctId,
search,
segment,
cohort,
@@ -61,6 +63,7 @@ export function useFilterParameters() {
event,
tag,
hostname,
+ distinctId,
page,
pageSize,
search,
diff --git a/src/components/input/FilterEditForm.tsx b/src/components/input/FilterEditForm.tsx
index 44f43844..9221e3a2 100644
--- a/src/components/input/FilterEditForm.tsx
+++ b/src/components/input/FilterEditForm.tsx
@@ -61,7 +61,9 @@ export function FilterEditForm({ websiteId, onChange, onClose }: FilterEditFormP
websiteId={websiteId}
value={currentFilters}
onChange={setCurrentFilters}
- exclude={excludeFilters ? ['path', 'title', 'hostname', 'tag', 'event'] : []}
+ exclude={
+ excludeFilters ? ['path', 'title', 'hostname', 'distinctId', 'tag', 'event'] : []
+ }
/>
diff --git a/src/components/input/UnitFilter.tsx b/src/components/input/UnitFilter.tsx
new file mode 100644
index 00000000..84a15f35
--- /dev/null
+++ b/src/components/input/UnitFilter.tsx
@@ -0,0 +1,71 @@
+import { ListItem, Row, Select } from '@umami/react-zen';
+import { useMessages, useNavigation } from '@/components/hooks';
+import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
+import { getItem } from '@/lib/storage';
+
+export function UnitFilter() {
+ const { formatMessage, labels } = useMessages();
+ const { router, query, updateParams } = useNavigation();
+
+ const DATE_RANGE_UNIT_CONFIG = {
+ '0week': {
+ defaultUnit: 'day',
+ availableUnits: ['day', 'hour'],
+ },
+ '7day': {
+ defaultUnit: 'day',
+ availableUnits: ['day', 'hour'],
+ },
+ '0month': {
+ defaultUnit: 'day',
+ availableUnits: ['day', 'hour'],
+ },
+ '30day': {
+ defaultUnit: 'day',
+ availableUnits: ['day', 'hour'],
+ },
+ '90day': {
+ defaultUnit: 'day',
+ availableUnits: ['day', 'month'],
+ },
+ '6month': {
+ defaultUnit: 'month',
+ availableUnits: ['month', 'day'],
+ },
+ };
+
+ const unitConfig =
+ DATE_RANGE_UNIT_CONFIG[query.date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE];
+
+ if (!unitConfig) {
+ return null;
+ }
+
+ const handleChange = (value: string) => {
+ router.push(updateParams({ unit: value }));
+ };
+
+ const options = unitConfig.availableUnits.map(unit => ({
+ id: unit,
+ label: formatMessage(labels[unit]),
+ }));
+
+ const selectedUnit = query.unit ?? unitConfig.defaultUnit;
+
+ return (
+
+
+
+ );
+}
diff --git a/src/components/input/UserSelect.tsx b/src/components/input/UserSelect.tsx
new file mode 100644
index 00000000..ccb3d432
--- /dev/null
+++ b/src/components/input/UserSelect.tsx
@@ -0,0 +1,71 @@
+import { ListItem, Row, Select, type SelectProps, Text } from '@umami/react-zen';
+import { useMemo, useState } from 'react';
+import { Empty } from '@/components/common/Empty';
+import { useMessages, useTeamMembersQuery, useUsersQuery } from '@/components/hooks';
+
+export function UserSelect({
+ teamId,
+ onChange,
+ ...props
+}: {
+ teamId?: string;
+} & SelectProps) {
+ const { formatMessage, messages } = useMessages();
+ const { data: users, isLoading: usersLoading } = useUsersQuery();
+ const { data: teamMembers, isLoading: teamMembersLoading } = useTeamMembersQuery(teamId);
+ const [username, setUsername] = useState();
+ const [search, setSearch] = useState('');
+
+ const listItems = useMemo(() => {
+ if (!users) {
+ return [];
+ }
+ if (!teamId || !teamMembers) {
+ return users.data;
+ }
+ const teamMemberIds = teamMembers.data.map(({ userId }) => userId);
+ return users.data.filter(({ id }) => !teamMemberIds.includes(id));
+ }, [users, teamMembers, teamId]);
+
+ const handleSearch = (value: string) => {
+ setSearch(value);
+ };
+
+ const handleOpenChange = () => {
+ setSearch('');
+ };
+
+ const handleChange = (id: string) => {
+ setUsername(listItems.find(item => item.id === id)?.username);
+ onChange(id);
+ };
+
+ const renderValue = () => {
+ return (
+
+ {username}
+
+ );
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/input/WebsiteDateFilter.tsx b/src/components/input/WebsiteDateFilter.tsx
index 18b4f13b..a76058ec 100644
--- a/src/components/input/WebsiteDateFilter.tsx
+++ b/src/components/input/WebsiteDateFilter.tsx
@@ -41,7 +41,7 @@ export function WebsiteDateFilter({
}),
);
} else {
- router.push(updateParams({ date, offset: undefined }));
+ router.push(updateParams({ date, offset: undefined, unit: undefined }));
}
};
diff --git a/src/components/messages.ts b/src/components/messages.ts
index 712495d8..3d7388cd 100644
--- a/src/components/messages.ts
+++ b/src/components/messages.ts
@@ -245,7 +245,10 @@ export const labels = defineMessages({
tag: { id: 'label.tag', defaultMessage: 'Tag' },
segment: { id: 'label.segment', defaultMessage: 'Segment' },
cohort: { id: 'label.cohort', defaultMessage: 'Cohort' },
+ minute: { id: 'label.minute', defaultMessage: 'Minute' },
+ hour: { id: 'label.hour', defaultMessage: 'Hour' },
day: { id: 'label.day', defaultMessage: 'Day' },
+ month: { id: 'label.month', defaultMessage: 'Month' },
date: { id: 'label.date', defaultMessage: 'Date' },
pageOf: { id: 'label.page-of', defaultMessage: 'Page {current} of {total}' },
create: { id: 'label.create', defaultMessage: 'Create' },
diff --git a/src/components/metrics/MetricCard.tsx b/src/components/metrics/MetricCard.tsx
index d15bcf13..590fd5ac 100644
--- a/src/components/metrics/MetricCard.tsx
+++ b/src/components/metrics/MetricCard.tsx
@@ -25,7 +25,7 @@ export const MetricCard = ({
showChange = false,
}: MetricCardProps) => {
const diff = value - change;
- const pct = ((value - diff) / diff) * 100;
+ const pct = diff !== 0 ? ((value - diff) / diff) * 100 : value !== 0 ? 100 : 0;
const props = useSpring({ x: Number(value) || 0, from: { x: 0 } });
const changeProps = useSpring({ x: Number(pct) || 0, from: { x: 0 } });
diff --git a/src/index.ts b/src/index.ts
index 907c5623..df164b9d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,11 +19,13 @@ export * from '@/app/(main)/teams/TeamAddForm';
export * from '@/app/(main)/teams/TeamJoinForm';
export * from '@/app/(main)/teams/TeamLeaveButton';
export * from '@/app/(main)/teams/TeamLeaveForm';
+export * from '@/app/(main)/teams/TeamMemberAddForm';
export * from '@/app/(main)/teams/TeamProvider';
export * from '@/app/(main)/teams/TeamsAddButton';
export * from '@/app/(main)/teams/TeamsDataTable';
export * from '@/app/(main)/teams/TeamsHeader';
export * from '@/app/(main)/teams/TeamsJoinButton';
+export * from '@/app/(main)/teams/TeamsMemberAddButton';
export * from '@/app/(main)/teams/TeamsTable';
export * from '@/app/(main)/websites/[websiteId]/settings/WebsiteData';
export * from '@/app/(main)/websites/[websiteId]/settings/WebsiteDeleteForm';
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index bfc80a13..3da177c0 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -55,6 +55,7 @@ export const SESSION_COLUMNS = [
'country',
'city',
'region',
+ 'distinctId',
];
export const SEGMENT_TYPES = {
@@ -69,6 +70,7 @@ export const FILTER_COLUMNS = {
referrer: 'referrer_domain',
domain: 'referrer_domain',
hostname: 'hostname',
+ distinctId: 'distinct_id',
title: 'page_title',
query: 'url_query',
os: 'os',
diff --git a/src/lib/date.ts b/src/lib/date.ts
index 3c1fd1b7..91af88f6 100644
--- a/src/lib/date.ts
+++ b/src/lib/date.ts
@@ -9,6 +9,7 @@ import {
differenceInCalendarMonths,
differenceInCalendarWeeks,
differenceInCalendarYears,
+ differenceInDays,
differenceInHours,
differenceInMinutes,
endOfDay,
@@ -136,7 +137,12 @@ export function parseDateValue(value: string) {
return { num: +num, unit };
}
-export function parseDateRange(value: string, locale = 'en-US', timezone?: string): DateRange {
+export function parseDateRange(
+ value: string,
+ unitValue?: string,
+ locale = 'en-US',
+ timezone?: string,
+): DateRange {
if (typeof value !== 'string') {
return null;
}
@@ -146,7 +152,7 @@ export function parseDateRange(value: string, locale = 'en-US', timezone?: strin
const startDate = new Date(+startTime);
const endDate = new Date(+endTime);
- const unit = getMinimumUnit(startDate, endDate);
+ const unit = getMinimumUnit(startDate, endDate, true);
return {
startDate,
@@ -169,14 +175,14 @@ export function parseDateRange(value: string, locale = 'en-US', timezone?: strin
endDate: endOfHour(now),
offset: 0,
num: num || 1,
- unit,
+ unit: unitValue || unit,
value,
};
case 'day':
return {
startDate: num ? subDays(startOfDay(now), num) : startOfDay(now),
endDate: endOfDay(now),
- unit: num ? 'day' : 'hour',
+ unit: unitValue ? unitValue : num ? 'day' : 'hour',
offset: 0,
num: num || 1,
value,
@@ -187,7 +193,7 @@ export function parseDateRange(value: string, locale = 'en-US', timezone?: strin
? subWeeks(startOfWeek(now, { locale: dateLocale }), num)
: startOfWeek(now, { locale: dateLocale }),
endDate: endOfWeek(now, { locale: dateLocale }),
- unit: 'day',
+ unit: unitValue || 'day',
offset: 0,
num: num || 1,
value,
@@ -196,7 +202,7 @@ export function parseDateRange(value: string, locale = 'en-US', timezone?: strin
return {
startDate: num ? subMonths(startOfMonth(now), num) : startOfMonth(now),
endDate: endOfMonth(now),
- unit: num ? 'month' : 'day',
+ unit: unitValue ? unitValue : num ? 'month' : 'day',
offset: 0,
num: num || 1,
value,
@@ -205,7 +211,7 @@ export function parseDateRange(value: string, locale = 'en-US', timezone?: strin
return {
startDate: num ? subYears(startOfYear(now), num) : startOfYear(now),
endDate: endOfYear(now),
- unit: 'month',
+ unit: unitValue || 'month',
offset: 0,
num: num || 1,
value,
@@ -273,12 +279,20 @@ export function getAllowedUnits(startDate: Date, endDate: Date) {
return index >= 0 ? units.splice(index) : [];
}
-export function getMinimumUnit(startDate: number | Date, endDate: number | Date) {
+export function getMinimumUnit(
+ startDate: number | Date,
+ endDate: number | Date,
+ isDateRange: boolean = false,
+) {
if (differenceInMinutes(endDate, startDate) <= 60) {
return 'minute';
- } else if (differenceInHours(endDate, startDate) <= 48) {
+ } else if (
+ isDateRange
+ ? differenceInHours(endDate, startDate) <= 48
+ : differenceInDays(endDate, startDate) <= 30
+ ) {
return 'hour';
- } else if (differenceInCalendarMonths(endDate, startDate) <= 6) {
+ } else if (differenceInCalendarMonths(endDate, startDate) <= 7) {
return 'day';
} else if (differenceInCalendarMonths(endDate, startDate) <= 24) {
return 'month';
diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts
index bfd007d1..cbabe03b 100644
--- a/src/lib/prisma.ts
+++ b/src/lib/prisma.ts
@@ -20,14 +20,6 @@ const PRISMA_LOG_OPTIONS = {
};
const DATE_FORMATS = {
- minute: 'YYYY-MM-DD HH24:MI:00',
- hour: 'YYYY-MM-DD HH24:00:00',
- day: 'YYYY-MM-DD HH24:00:00',
- month: 'YYYY-MM-01 HH24:00:00',
- year: 'YYYY-01-01 HH24:00:00',
-};
-
-const DATE_FORMATS_UTC = {
minute: 'YYYY-MM-DD"T"HH24:MI:00"Z"',
hour: 'YYYY-MM-DD"T"HH24:00:00"Z"',
day: 'YYYY-MM-DD"T"HH24:00:00"Z"',
@@ -52,7 +44,7 @@ function getDateSQL(field: string, unit: string, timezone?: string): string {
return `to_char(date_trunc('${unit}', ${field} at time zone '${timezone}'), '${DATE_FORMATS[unit]}')`;
}
- return `to_char(date_trunc('${unit}', ${field}), '${DATE_FORMATS_UTC[unit]}')`;
+ return `to_char(date_trunc('${unit}', ${field}), '${DATE_FORMATS[unit]}')`;
}
function getDateWeeklySQL(field: string, timezone?: string) {
diff --git a/src/lib/schema.ts b/src/lib/schema.ts
index ac360a8e..a3c56a0f 100644
--- a/src/lib/schema.ts
+++ b/src/lib/schema.ts
@@ -36,6 +36,7 @@ export const filterParams = {
city: z.string().optional(),
tag: z.string().optional(),
hostname: z.string().optional(),
+ distinctId: z.string().optional(),
language: z.string().optional(),
event: z.string().optional(),
segment: z.uuid().optional(),
@@ -89,6 +90,7 @@ export const fieldsParam = z.enum([
'city',
'tag',
'hostname',
+ 'distinctId',
'language',
'event',
]);
@@ -166,6 +168,7 @@ export const journeyReportSchema = z.object({
steps: z.coerce.number().min(2).max(7),
startStep: z.string().optional(),
endStep: z.string().optional(),
+ eventType: z.coerce.number().int().positive().optional(),
}),
});
diff --git a/src/queries/sql/events/getEventExpandedMetrics.ts b/src/queries/sql/events/getEventExpandedMetrics.ts
index f03a347d..86bda850 100644
--- a/src/queries/sql/events/getEventExpandedMetrics.ts
+++ b/src/queries/sql/events/getEventExpandedMetrics.ts
@@ -58,7 +58,7 @@ async function relationalQuery(
sum(${getTimestampDiffSQL('t.min_time', 't.max_time')}) as "totaltime"
from (
select
- ${column} name,
+ ${column} as "name",
website_event.session_id,
website_event.visit_id,
count(*) as "c",
@@ -72,6 +72,7 @@ async function relationalQuery(
${filterQuery}
group by name, website_event.session_id, website_event.visit_id
) as t
+ where name != ''
group by name
order by visitors desc, visits desc
limit ${limit}
diff --git a/src/queries/sql/getChannelExpandedMetrics.ts b/src/queries/sql/getChannelExpandedMetrics.ts
index 33640d59..f674d182 100644
--- a/src/queries/sql/getChannelExpandedMetrics.ts
+++ b/src/queries/sql/getChannelExpandedMetrics.ts
@@ -89,7 +89,7 @@ async function relationalQuery(
when ${toPostgresPositionClause('referrer_domain', EMAIL_DOMAINS)} or utm_medium ilike '%mail%' then 'email'
when ${toPostgresPositionClause('referrer_domain', SHOPPING_DOMAINS)} or utm_medium ilike '%shop%' then concat(prefix, 'Shopping')
when ${toPostgresPositionClause('referrer_domain', VIDEO_DOMAINS)} or utm_medium ilike '%video%' then concat(prefix, 'Video')
- else '' end AS name,
+ else '' end as "name",
session_id,
visit_id,
c,
diff --git a/src/queries/sql/getRealtimeActivity.ts b/src/queries/sql/getRealtimeActivity.ts
index 075b65e2..c847b6f7 100644
--- a/src/queries/sql/getRealtimeActivity.ts
+++ b/src/queries/sql/getRealtimeActivity.ts
@@ -30,7 +30,8 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
session.device,
session.country,
website_event.url_path as "urlPath",
- website_event.referrer_domain as "referrerDomain"
+ website_event.referrer_domain as "referrerDomain",
+ website_event.hostname
from website_event
${cohortQuery}
inner join session
@@ -65,7 +66,8 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters): Promis
device,
country,
url_path as urlPath,
- referrer_domain as referrerDomain
+ referrer_domain as referrerDomain,
+ hostname
from website_event
${cohortQuery}
where website_id = {websiteId:UUID}
diff --git a/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts b/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts
index 986d7d5a..ccb0be53 100644
--- a/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts
+++ b/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts
@@ -86,7 +86,7 @@ async function relationalQuery(
sum(${getTimestampDiffSQL('t.min_time', 't.max_time')}) as "totaltime"
from (
select
- ${column} as name,
+ ${column} as "name",
website_event.session_id,
website_event.visit_id,
count(*) as "c",
diff --git a/src/queries/sql/reports/getAttribution.ts b/src/queries/sql/reports/getAttribution.ts
index 1d040781..29068f7d 100644
--- a/src/queries/sql/reports/getAttribution.ts
+++ b/src/queries/sql/reports/getAttribution.ts
@@ -52,8 +52,8 @@ async function relationalQuery(
function getUTMQuery(utmColumn: string) {
return `
select
- coalesce(we.${utmColumn}, '') name,
- ${currency ? 'sum(e.value)' : 'count(distinct we.session_id)'} value
+ coalesce(we.${utmColumn}, '') as "name",
+ ${currency ? 'sum(e.value)' : 'count(distinct we.session_id)'} as "value"
from model m
join website_event we
on we.created_at = m.created_at
@@ -128,7 +128,7 @@ async function relationalQuery(
`
${currency ? revenueEventQuery : eventQuery}
${getModelQuery(model)}
- select coalesce(we.referrer_domain, '') name,
+ select coalesce(we.referrer_domain, '') as "name",
${currency ? 'sum(e.value)' : 'count(distinct we.session_id)'} value
from model m
join website_event we
@@ -166,8 +166,8 @@ async function relationalQuery(
when coalesce(li_fat_id, '') != '' then 'LinkedIn Ads'
when coalesce(twclid, '') != '' then 'Twitter Ads (X)'
else ''
- end name,
- ${currency ? 'sum(e.value)' : 'count(distinct we.session_id)'} value
+ end as "name",
+ ${currency ? 'sum(e.value)' : 'count(distinct we.session_id)'} as "value"
from model m
join website_event we
on we.created_at = m.created_at
diff --git a/src/queries/sql/reports/getJourney.ts b/src/queries/sql/reports/getJourney.ts
index 21a7f22d..d12d371b 100644
--- a/src/queries/sql/reports/getJourney.ts
+++ b/src/queries/sql/reports/getJourney.ts
@@ -60,7 +60,7 @@ async function relationalQuery(
endStepQuery: string;
params: Record;
} {
- const params = {};
+ const params: { startStep?: string; endStep?: string } = {};
let sequenceQuery = '';
let startStepQuery = '';
let endStepQuery = '';
@@ -172,7 +172,7 @@ async function clickhouseQuery(
endStepQuery: string;
params: Record;
} {
- const params = {};
+ const params: { startStep?: string; endStep?: string } = {};
let sequenceQuery = '';
let startStepQuery = '';
let endStepQuery = '';
diff --git a/src/queries/sql/reports/getRevenue.ts b/src/queries/sql/reports/getRevenue.ts
index d3bff6c9..30d7d7f1 100644
--- a/src/queries/sql/reports/getRevenue.ts
+++ b/src/queries/sql/reports/getRevenue.ts
@@ -76,8 +76,8 @@ async function relationalQuery(
const country = await rawQuery(
`
select
- session.country as name,
- sum(revenue) value
+ session.country as "name",
+ sum(revenue) as "value"
from revenue
${joinQuery}
join session
@@ -176,8 +176,8 @@ async function clickhouseQuery(
>(
`
select
- website_event.country as name,
- sum(website_revenue.revenue) as value
+ website_event.country as "name",
+ sum(website_revenue.revenue) as "value"
from website_revenue
any left join (
select *
diff --git a/src/queries/sql/sessions/getSessionActivity.ts b/src/queries/sql/sessions/getSessionActivity.ts
index af31fca6..1ac7e6ff 100644
--- a/src/queries/sql/sessions/getSessionActivity.ts
+++ b/src/queries/sql/sessions/getSessionActivity.ts
@@ -29,6 +29,7 @@ async function relationalQuery(websiteId: string, sessionId: string, filters: Qu
event_type as "eventType",
event_name as "eventName",
visit_id as "visitId",
+ hostname,
event_id IN (select website_event_id
from event_data
where website_id = {{websiteId::uuid}}
@@ -60,6 +61,7 @@ async function clickhouseQuery(websiteId: string, sessionId: string, filters: Qu
event_type as eventType,
event_name as eventName,
visit_id as visitId,
+ hostname,
event_id IN (select event_id
from event_data
where website_id = {websiteId:UUID}
diff --git a/src/queries/sql/sessions/getSessionExpandedMetrics.ts b/src/queries/sql/sessions/getSessionExpandedMetrics.ts
index 85c12939..6b85cd45 100644
--- a/src/queries/sql/sessions/getSessionExpandedMetrics.ts
+++ b/src/queries/sql/sessions/getSessionExpandedMetrics.ts
@@ -65,7 +65,7 @@ async function relationalQuery(
sum(${getTimestampDiffSQL('t.min_time', 't.max_time')}) as "totaltime"
from (
select
- ${column} name,
+ ${column} as "name",
${includeCountry ? 'country,' : ''}
website_event.session_id,
website_event.visit_id,
@@ -82,6 +82,7 @@ async function relationalQuery(
group by name, website_event.session_id, website_event.visit_id
${includeCountry ? ', country' : ''}
) as t
+ where name != ''
group by name
${includeCountry ? ', country' : ''}
order by visitors desc, visits desc