From 42b475b0619c35301d178822e6114da8065310c4 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 7 May 2024 17:26:15 -0700 Subject: [PATCH 01/18] Remove offset from query parameters. --- src/components/hooks/useFilterParams.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/hooks/useFilterParams.ts b/src/components/hooks/useFilterParams.ts index 4fc36f39..fd76fd47 100644 --- a/src/components/hooks/useFilterParams.ts +++ b/src/components/hooks/useFilterParams.ts @@ -5,7 +5,7 @@ import { zonedTimeToUtc } from 'date-fns-tz'; export function useFilterParams(websiteId: string) { const [dateRange] = useDateRange(websiteId); - const { startDate, endDate, unit, offset } = dateRange; + const { startDate, endDate, unit } = dateRange; const { timezone } = useTimezone(); const { query: { url, referrer, title, query, os, browser, device, country, region, city, event }, @@ -15,7 +15,6 @@ export function useFilterParams(websiteId: string) { startAt: +zonedTimeToUtc(startDate, timezone), endAt: +zonedTimeToUtc(endDate, timezone), unit, - offset, timezone, url, referrer, From 4731c1cca32e6e64ecccab6139f4e39ab117f330 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 9 May 2024 11:55:54 -0700 Subject: [PATCH 02/18] add redis calls to website delete/reset --- src/queries/admin/website.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index 1f513bd4..d191aa65 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -1,4 +1,5 @@ import { Prisma, Website } from '@prisma/client'; +import redis from '@umami/redis-client'; import prisma from 'lib/prisma'; import { PageResult, PageParams } from 'lib/types'; import WebsiteFindManyArgs = Prisma.WebsiteFindManyArgs; @@ -122,6 +123,7 @@ export async function resetWebsite( websiteId: string, ): Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Website]> { const { client, transaction } = prisma; + const cloudMode = !!process.env.cloudMode; return transaction([ client.eventData.deleteMany({ @@ -139,14 +141,20 @@ export async function resetWebsite( resetAt: new Date(), }, }), - ]); + ]).then(async data => { + if (cloudMode) { + await redis.client.set(`website:${websiteId}`, data[3]); + } + + return data; + }); } export async function deleteWebsite( websiteId: string, ): Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Website]> { const { client, transaction } = prisma; - const cloudMode = process.env.CLOUD_MODE; + const cloudMode = !!process.env.CLOUD_MODE; return transaction([ client.eventData.deleteMany({ @@ -173,5 +181,11 @@ export async function deleteWebsite( : client.website.delete({ where: { id: websiteId }, }), - ]); + ]).then(async data => { + if (cloudMode) { + await redis.client.del(`website:${websiteId}`); + } + + return data; + }); } From ab39ae8511166c410d9aa26199ba0ba66b471363 Mon Sep 17 00:00:00 2001 From: Brian Cao Date: Fri, 10 May 2024 23:15:56 -0700 Subject: [PATCH 03/18] fix usage get. --- src/pages/api/users/[userId]/usage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/api/users/[userId]/usage.ts b/src/pages/api/users/[userId]/usage.ts index 806b4128..66e92768 100644 --- a/src/pages/api/users/[userId]/usage.ts +++ b/src/pages/api/users/[userId]/usage.ts @@ -24,7 +24,7 @@ export interface UserUsageRequestResponse { const schema = { GET: yup.object().shape({ - id: yup.string().uuid().required(), + userId: yup.string().uuid().required(), startAt: yup.number().integer().required(), endAt: yup.number().integer().min(yup.ref('startAt')).required(), }), From d057b15460c93077d81aca045e51d1cdf549c17c Mon Sep 17 00:00:00 2001 From: Brian Cao Date: Mon, 13 May 2024 15:43:53 -0700 Subject: [PATCH 04/18] Fix usage. --- src/pages/api/users/[userId]/usage.ts | 4 ++-- src/queries/admin/website.ts | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/pages/api/users/[userId]/usage.ts b/src/pages/api/users/[userId]/usage.ts index 66e92768..9d2bc37e 100644 --- a/src/pages/api/users/[userId]/usage.ts +++ b/src/pages/api/users/[userId]/usage.ts @@ -2,7 +2,7 @@ import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; -import { getAllWebsites, getEventDataUsage, getEventUsage } from 'queries'; +import { getAllUserWebsitesIncludingTeamOwner, getEventDataUsage, getEventUsage } from 'queries'; import * as yup from 'yup'; export interface UserUsageRequestQuery { @@ -50,7 +50,7 @@ export default async ( const startDate = new Date(+startAt); const endDate = new Date(+endAt); - const websites = await getAllWebsites(userId); + const websites = await getAllUserWebsitesIncludingTeamOwner(userId); const websiteIds = websites.map(a => a.id); diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index d191aa65..37dd5f48 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -3,6 +3,7 @@ import redis from '@umami/redis-client'; import prisma from 'lib/prisma'; import { PageResult, PageParams } from 'lib/types'; import WebsiteFindManyArgs = Prisma.WebsiteFindManyArgs; +import { ROLES } from 'lib/constants'; async function findWebsite(criteria: Prisma.WebsiteFindUniqueArgs): Promise { return prisma.client.website.findUnique(criteria); @@ -52,6 +53,27 @@ export async function getAllWebsites(userId: string) { }); } +export async function getAllUserWebsitesIncludingTeamOwner(userId: string) { + return prisma.client.website.findMany({ + where: { + OR: [ + { userId }, + { + team: { + deletedAt: null, + teamUser: { + some: { + role: ROLES.teamOwner, + userId, + }, + }, + }, + }, + ], + }, + }); +} + export async function getUserWebsites( userId: string, filters?: PageParams, From 0d51f5bb7ca61b8f51a3c14a1d5500521027636c Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 13 May 2024 13:33:41 -0700 Subject: [PATCH 05/18] fix param names for includeTeams --- src/pages/api/admin/websites.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/api/admin/websites.ts b/src/pages/api/admin/websites.ts index 86692144..58a59586 100644 --- a/src/pages/api/admin/websites.ts +++ b/src/pages/api/admin/websites.ts @@ -43,7 +43,7 @@ export default async ( return unauthorized(res); } - const { userId, includeOwnedTeams } = req.query; + const { userId, includeTeams } = req.query; const websites = await getWebsites( { @@ -51,7 +51,7 @@ export default async ( OR: [ ...(userId && [{ userId }]), ...(userId && - includeOwnedTeams && [ + includeTeams && [ { team: { deletedAt: null, From c80be88d14e5c718aa6fa8ac56fb2c1a159cbdee Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 14 May 2024 09:39:04 -0700 Subject: [PATCH 06/18] update getAllwebsites, match usage query with api / cloud call --- src/pages/api/users/[userId]/usage.ts | 3 +-- src/queries/admin/website.ts | 14 +++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/pages/api/users/[userId]/usage.ts b/src/pages/api/users/[userId]/usage.ts index 9d2bc37e..90cfb9ee 100644 --- a/src/pages/api/users/[userId]/usage.ts +++ b/src/pages/api/users/[userId]/usage.ts @@ -7,8 +7,7 @@ import * as yup from 'yup'; export interface UserUsageRequestQuery { id: string; - startAt: string; - endAt: string; + params: { startAt: string; endAt: string }; } export interface UserUsageRequestResponse { diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index 37dd5f48..a3bcac7b 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -48,7 +48,19 @@ export async function getWebsites( export async function getAllWebsites(userId: string) { return prisma.client.website.findMany({ where: { - userId, + OR: [ + { userId }, + { + team: { + deletedAt: null, + teamUser: { + some: { + userId, + }, + }, + }, + }, + ], }, }); } From 4b421d08d0a70588e06c4ae091711b7acd3a1058 Mon Sep 17 00:00:00 2001 From: Brian Cao Date: Tue, 14 May 2024 12:01:27 -0700 Subject: [PATCH 07/18] fix usage. --- src/pages/api/users/[userId]/usage.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/api/users/[userId]/usage.ts b/src/pages/api/users/[userId]/usage.ts index 90cfb9ee..547de338 100644 --- a/src/pages/api/users/[userId]/usage.ts +++ b/src/pages/api/users/[userId]/usage.ts @@ -6,8 +6,9 @@ import { getAllUserWebsitesIncludingTeamOwner, getEventDataUsage, getEventUsage import * as yup from 'yup'; export interface UserUsageRequestQuery { - id: string; - params: { startAt: string; endAt: string }; + userId: string; + startAt: string; + endAt: string; } export interface UserUsageRequestResponse { @@ -44,7 +45,7 @@ export default async ( return unauthorized(res); } - const { id: userId, startAt, endAt } = req.query; + const { userId, startAt, endAt } = req.query; const startDate = new Date(+startAt); const endDate = new Date(+endAt); From b3bcfa5bd1d7b639a6fe7bdb079748102d50634b Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 14 May 2024 17:19:10 -0700 Subject: [PATCH 08/18] filter usagewebsites --- src/pages/api/users/[userId]/usage.ts | 7 ++++++- src/pages/api/users/[userId]/websites.ts | 1 - src/queries/admin/website.ts | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pages/api/users/[userId]/usage.ts b/src/pages/api/users/[userId]/usage.ts index 547de338..b5000395 100644 --- a/src/pages/api/users/[userId]/usage.ts +++ b/src/pages/api/users/[userId]/usage.ts @@ -62,6 +62,7 @@ export default async ( websiteName: a.name, websiteEventUsage: websiteEventUsage.find(b => a.id === b.websiteId)?.count || 0, eventDataUsage: eventDataUsage.find(b => a.id === b.websiteId)?.count || 0, + deletedAt: a.deletedAt, })); const usage = websiteUsage.reduce( @@ -74,9 +75,13 @@ export default async ( { websiteEventUsage: 0, eventDataUsage: 0 }, ); + const filteredWebsiteUsage = websiteUsage.filter( + a => !a.deletedAt && (a.websiteEventUsage > 0 || a.eventDataUsage > 0), + ); + return ok(res, { ...usage, - websites: websiteUsage, + websites: filteredWebsiteUsage, }); } diff --git a/src/pages/api/users/[userId]/websites.ts b/src/pages/api/users/[userId]/websites.ts index f443deb8..88a2bad1 100644 --- a/src/pages/api/users/[userId]/websites.ts +++ b/src/pages/api/users/[userId]/websites.ts @@ -9,7 +9,6 @@ import * as yup from 'yup'; const schema = { GET: yup.object().shape({ userId: yup.string().uuid().required(), - teamId: yup.string().uuid(), ...pageInfo, }), }; diff --git a/src/queries/admin/website.ts b/src/queries/admin/website.ts index a3bcac7b..eb07f779 100644 --- a/src/queries/admin/website.ts +++ b/src/queries/admin/website.ts @@ -61,6 +61,7 @@ export async function getAllWebsites(userId: string) { }, }, ], + deletedAt: null, }, }); } From 36928d4f04b616ad8ec8ff954f8531598b336f30 Mon Sep 17 00:00:00 2001 From: Brian Cao Date: Tue, 14 May 2024 17:13:16 -0700 Subject: [PATCH 09/18] fix admin/website --- src/pages/api/admin/websites.ts | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/pages/api/admin/websites.ts b/src/pages/api/admin/websites.ts index 58a59586..686de6cb 100644 --- a/src/pages/api/admin/websites.ts +++ b/src/pages/api/admin/websites.ts @@ -10,7 +10,7 @@ import * as yup from 'yup'; export interface WebsitesRequestQuery extends PageParams { userId?: string; - includeTeams?: boolean; + includeOwnedTeams?: boolean; } export interface WebsitesRequestBody { @@ -43,27 +43,28 @@ export default async ( return unauthorized(res); } - const { userId, includeTeams } = req.query; + const { userId, includeOwnedTeams } = req.query; const websites = await getWebsites( { where: { OR: [ ...(userId && [{ userId }]), - ...(userId && - includeTeams && [ - { - team: { - deletedAt: null, - teamUser: { - some: { - role: ROLES.teamOwner, - userId, + ...(userId && includeOwnedTeams + ? [ + { + team: { + deletedAt: null, + teamUser: { + some: { + role: ROLES.teamOwner, + userId, + }, }, }, }, - }, - ]), + ] + : []), ], }, include: { From b41ab4ec2a4834de1f0dfe2c80641bafa89c45d4 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 3 Jun 2024 09:33:58 -0700 Subject: [PATCH 10/18] remove Journey report --- .../(main)/reports/create/ReportTemplates.tsx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/app/(main)/reports/create/ReportTemplates.tsx b/src/app/(main)/reports/create/ReportTemplates.tsx index 0777cc1f..bcbb989a 100644 --- a/src/app/(main)/reports/create/ReportTemplates.tsx +++ b/src/app/(main)/reports/create/ReportTemplates.tsx @@ -1,14 +1,13 @@ -import Link from 'next/link'; -import { Button, Icons, Text, Icon } from 'react-basics'; -import PageHeader from 'components/layout/PageHeader'; import Funnel from 'assets/funnel.svg'; import Lightbulb from 'assets/lightbulb.svg'; import Magnet from 'assets/magnet.svg'; import Tag from 'assets/tag.svg'; import Target from 'assets/target.svg'; -import Path from 'assets/path.svg'; -import styles from './ReportTemplates.module.css'; import { useMessages, useTeamUrl } from 'components/hooks'; +import PageHeader from 'components/layout/PageHeader'; +import Link from 'next/link'; +import { Button, Icon, Icons, Text } from 'react-basics'; +import styles from './ReportTemplates.module.css'; export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) { const { formatMessage, labels } = useMessages(); @@ -45,12 +44,12 @@ export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) url: renderTeamUrl('/reports/goals'), icon: , }, - { - title: formatMessage(labels.journey), - description: formatMessage(labels.journeyDescription), - url: renderTeamUrl('/reports/journey'), - icon: , - }, + // { + // title: formatMessage(labels.journey), + // description: formatMessage(labels.journeyDescription), + // url: renderTeamUrl('/reports/journey'), + // icon: , + // }, ]; return ( From 7a9b6a521dfc5bb2c5ae78fd7e57bcff871d2b02 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 3 Jun 2024 12:26:03 -0700 Subject: [PATCH 11/18] fix getReports for website, user, team --- src/app/(main)/reports/ReportsPage.tsx | 5 ++++- src/app/(main)/reports/page.tsx | 4 ++-- src/pages/api/reports/index.ts | 28 +++++++++++++++++++++----- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/app/(main)/reports/ReportsPage.tsx b/src/app/(main)/reports/ReportsPage.tsx index a76a6a47..5b031cfa 100644 --- a/src/app/(main)/reports/ReportsPage.tsx +++ b/src/app/(main)/reports/ReportsPage.tsx @@ -2,8 +2,11 @@ import { Metadata } from 'next'; import ReportsHeader from './ReportsHeader'; import ReportsDataTable from './ReportsDataTable'; +import { useTeamUrl } from 'components/hooks'; + +export default function ReportsPage() { + const { teamId } = useTeamUrl(); -export default function ReportsPage({ teamId }: { teamId: string }) { return ( <> diff --git a/src/app/(main)/reports/page.tsx b/src/app/(main)/reports/page.tsx index 4b495aca..ef4e56ad 100644 --- a/src/app/(main)/reports/page.tsx +++ b/src/app/(main)/reports/page.tsx @@ -1,8 +1,8 @@ import ReportsPage from './ReportsPage'; import { Metadata } from 'next'; -export default function ({ params: { teamId } }: { params: { teamId: string } }) { - return ; +export default function () { + return ; } export const metadata: Metadata = { diff --git a/src/pages/api/reports/index.ts b/src/pages/api/reports/index.ts index 186a1821..f9d4cca4 100644 --- a/src/pages/api/reports/index.ts +++ b/src/pages/api/reports/index.ts @@ -66,11 +66,29 @@ export default async ( const data = await getReports( { where: { - userId: !teamId && !websiteId ? userId : undefined, - websiteId, - website: { - teamId, - }, + OR: [ + ...(websiteId ? [{ websiteId }] : []), + ...(teamId + ? [ + { + website: { + deletedAt: null, + teamId, + }, + }, + ] + : []), + ...(userId + ? [ + { + website: { + deletedAt: null, + userId, + }, + }, + ] + : []), + ], }, include: { website: { From d24634ffbb89071619c1819dbf85b18b8bfe6c44 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 3 Jun 2024 12:38:37 -0700 Subject: [PATCH 12/18] fix userId getReport query --- src/pages/api/reports/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/api/reports/index.ts b/src/pages/api/reports/index.ts index f9d4cca4..0698188c 100644 --- a/src/pages/api/reports/index.ts +++ b/src/pages/api/reports/index.ts @@ -78,7 +78,7 @@ export default async ( }, ] : []), - ...(userId + ...(userId && !websiteId && !teamId ? [ { website: { From f6e8522f6ad57e41bed0e96ad84a626fef27914c Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 10 Jun 2024 12:47:31 -0700 Subject: [PATCH 13/18] change bounce rate to use visits --- src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx index 246a54b8..a6e7ad40 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx @@ -57,11 +57,11 @@ export function WebsiteMetricsBar({ }, { label: formatMessage(labels.bounceRate), - value: (Math.min(visitors.value, bounces.value) / visitors.value) * 100, - prev: (Math.min(visitors.prev, bounces.prev) / visitors.prev) * 100, + value: (Math.min(visits.value, bounces.value) / visits.value) * 100, + prev: (Math.min(visits.prev, bounces.prev) / visits.prev) * 100, change: - (Math.min(visitors.value, bounces.value) / visitors.value) * 100 - - (Math.min(visitors.prev, bounces.prev) / visitors.prev) * 100, + (Math.min(visits.value, bounces.value) / visits.value) * 100 - + (Math.min(visits.prev, bounces.prev) / visits.prev) * 100, formatValue: n => Math.round(+n) + '%', reverseColors: true, }, From 895398bebf724ab1a3810ff3fe41701ccbc5ad7e Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 10 Jun 2024 12:47:31 -0700 Subject: [PATCH 14/18] change bounce rate to use visits --- src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx index b258a19f..646b20e3 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx @@ -57,11 +57,11 @@ export function WebsiteMetricsBar({ }, { label: formatMessage(labels.bounceRate), - value: (Math.min(visitors.value, bounces.value) / visitors.value) * 100, - prev: (Math.min(visitors.prev, bounces.prev) / visitors.prev) * 100, + value: (Math.min(visits.value, bounces.value) / visits.value) * 100, + prev: (Math.min(visits.prev, bounces.prev) / visits.prev) * 100, change: - (Math.min(visitors.value, bounces.value) / visitors.value) * 100 - - (Math.min(visitors.prev, bounces.prev) / visitors.prev) * 100, + (Math.min(visits.value, bounces.value) / visits.value) * 100 - + (Math.min(visits.prev, bounces.prev) / visits.prev) * 100, formatValue: n => Number(n).toFixed(0) + '%', reverseColors: true, }, From 1d9079f6adea49c08763fcd23b3d4277be5c86eb Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 10 Jun 2024 13:20:24 -0700 Subject: [PATCH 15/18] fix change label --- .../(main)/websites/[websiteId]/WebsiteMetricsBar.tsx | 2 +- src/components/metrics/ChangeLabel.tsx | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx index 646b20e3..a6e7ad40 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx @@ -62,7 +62,7 @@ export function WebsiteMetricsBar({ change: (Math.min(visits.value, bounces.value) / visits.value) * 100 - (Math.min(visits.prev, bounces.prev) / visits.prev) * 100, - formatValue: n => Number(n).toFixed(0) + '%', + formatValue: n => Math.round(+n) + '%', reverseColors: true, }, { diff --git a/src/components/metrics/ChangeLabel.tsx b/src/components/metrics/ChangeLabel.tsx index 14eb1a8b..7e7cb77b 100644 --- a/src/components/metrics/ChangeLabel.tsx +++ b/src/components/metrics/ChangeLabel.tsx @@ -19,21 +19,22 @@ export function ChangeLabel({ className?: string; children?: ReactNode; }) { - const positive = value * (reverseColors ? -1 : 1) >= 0; - const negative = value * (reverseColors ? -1 : 1) < 0; + const positive = value >= 0; + const negative = value < 0; const neutral = value === 0 || isNaN(value); + const good = reverseColors ? negative : positive; return (
{!neutral && ( - + )} From 8f015e870d6e051ab417dbe5c87943f317ee54f0 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 10 Jun 2024 15:47:59 -0700 Subject: [PATCH 16/18] add Journey report --- src/app/(main)/reports/create/ReportTemplates.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/(main)/reports/create/ReportTemplates.tsx b/src/app/(main)/reports/create/ReportTemplates.tsx index bcbb989a..e37efc03 100644 --- a/src/app/(main)/reports/create/ReportTemplates.tsx +++ b/src/app/(main)/reports/create/ReportTemplates.tsx @@ -1,6 +1,7 @@ import Funnel from 'assets/funnel.svg'; import Lightbulb from 'assets/lightbulb.svg'; import Magnet from 'assets/magnet.svg'; +import Path from 'assets/path.svg'; import Tag from 'assets/tag.svg'; import Target from 'assets/target.svg'; import { useMessages, useTeamUrl } from 'components/hooks'; @@ -44,12 +45,12 @@ export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) url: renderTeamUrl('/reports/goals'), icon: , }, - // { - // title: formatMessage(labels.journey), - // description: formatMessage(labels.journeyDescription), - // url: renderTeamUrl('/reports/journey'), - // icon: , - // }, + { + title: formatMessage(labels.journey), + description: formatMessage(labels.journeyDescription), + url: renderTeamUrl('/reports/journey'), + icon: , + }, ]; return ( From 632ecd1a1b7c8ac0b7b6c26581ef85ac8a024aa4 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 12 Jun 2024 22:36:09 -0700 Subject: [PATCH 17/18] update insights query --- .../(main)/reports/insights/InsightsTable.tsx | 30 ++++++- src/lib/clickhouse.ts | 2 +- src/queries/analytics/reports/getInsights.ts | 87 +++++++++++-------- 3 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/app/(main)/reports/insights/InsightsTable.tsx b/src/app/(main)/reports/insights/InsightsTable.tsx index 2cccc24c..692d7824 100644 --- a/src/app/(main)/reports/insights/InsightsTable.tsx +++ b/src/app/(main)/reports/insights/InsightsTable.tsx @@ -3,6 +3,7 @@ import { GridTable, GridColumn } from 'react-basics'; import { useFormat, useMessages } from 'components/hooks'; import { ReportContext } from '../[reportId]/Report'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; +import { formatShortTime } from 'lib/format'; export function InsightsTable() { const [fields, setFields] = useState([]); @@ -31,6 +32,12 @@ export function InsightsTable() { ); })} + + {row => row?.views?.toLocaleString()} + + + {row => row?.visits?.toLocaleString()} + {row => row?.visitors?.toLocaleString()} - - {row => row?.views?.toLocaleString()} + + {row => { + const n = (Math.min(row?.visits, row?.bounces) / row?.visits) * 100; + return Math.round(+n) + '%'; + }} + + + {row => { + const n = row?.totaltime / row?.visits; + return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`; + }} ); diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index e5cb40c0..c1b9d25f 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -119,7 +119,7 @@ async function parseFilters(websiteId: string, filters: QueryFilters = {}, optio }; } -async function rawQuery(query: string, params: Record = {}): Promise { +async function rawQuery(query: string, params: Record = {}): Promise { if (process.env.LOG_QUERY) { log('QUERY:\n', query); log('PARAMETERS:\n', params); diff --git a/src/queries/analytics/reports/getInsights.ts b/src/queries/analytics/reports/getInsights.ts index 282ed755..7313e436 100644 --- a/src/queries/analytics/reports/getInsights.ts +++ b/src/queries/analytics/reports/getInsights.ts @@ -23,7 +23,7 @@ async function relationalQuery( y: number; }[] > { - const { parseFilters, rawQuery } = prisma; + const { getTimestampDiffQuery, parseFilters, rawQuery } = prisma; const { filterQuery, joinSession, params } = await parseFilters( websiteId, { @@ -37,15 +37,31 @@ async function relationalQuery( return rawQuery( ` - select + select + sum(t.c) as "views", + count(distinct t.session_id) as "visitors", + count(distinct t.visit_id) as "visits", + sum(case when t.c = 1 then 1 else 0 end) as "bounces", + sum(${getTimestampDiffQuery('t.min_time', 't.max_time')}) as "totaltime", ${parseFields(fields)} - from website_event - ${joinSession} - where website_event.website_id = {{websiteId::uuid}} - and website_event.created_at between {{startDate}} and {{endDate}} - and website_event.event_type = {{eventType}} - ${filterQuery} - ${parseGroupBy(fields)} + from ( + select + ${parseFields(fields)}, + website_event.session_id, + website_event.visit_id, + count(*) as "c", + min(website_event.created_at) as "min_time", + max(website_event.created_at) as "max_time" + from website_event + ${joinSession} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and event_type = {{eventType}} + ${filterQuery} + group by ${parseFields(fields)}, + website_event.session_id, website_event.visit_id + ) as t + group by ${parseFields(fields)} order by 1 desc, 2 desc limit 500 `, @@ -71,14 +87,30 @@ async function clickhouseQuery( return rawQuery( ` - select + select + sum(t.c) as "views", + count(distinct t.session_id) as "visitors", + count(distinct t.visit_id) as "visits", + sum(if(t.c = 1, 1, 0)) as "bounces", + sum(max_time-min_time) as "totaltime", ${parseFields(fields)} - from website_event - where website_id = {websiteId:UUID} - and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and event_type = {eventType:UInt32} - ${filterQuery} - ${parseGroupBy(fields)} + from ( + select + ${parseFields(fields)}, + session_id, + visit_id, + count(*) c, + min(created_at) min_time, + max(created_at) max_time + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = {eventType:UInt32} + ${filterQuery} + group by ${parseFields(fields)}, + session_id, visit_id + ) as t + group by ${parseFields(fields)} order by 1 desc, 2 desc limit 500 `, @@ -89,27 +121,14 @@ async function clickhouseQuery( ...a, views: Number(a.views), visitors: Number(a.visitors), + visits: Number(a.visits), + bounces: Number(a.bounces), + totaltime: Number(a.totaltime), }; }); }); } -function parseFields(fields: any[]) { - const query = fields.reduce( - (arr, field) => { - const { name } = field; - - return arr.concat(`${FILTER_COLUMNS[name]} as "${name}"`); - }, - ['count(*) as views', 'count(distinct website_event.session_id) as visitors'], - ); - - return query.join(',\n'); -} - -function parseGroupBy(fields: { name: any }[]) { - if (!fields.length) { - return ''; - } - return `group by ${fields.map(({ name }) => FILTER_COLUMNS[name]).join(',')}`; +function parseFields(fields: { name: any }[]) { + return `${fields.map(({ name }) => FILTER_COLUMNS[name]).join(',')}`; } From fdc7c39fe4075180fc26bf0104d2d723b84e4a72 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 12 Jun 2024 23:23:12 -0700 Subject: [PATCH 18/18] fix missing websitechart --- src/app/(main)/reports/[reportId]/Report.module.css | 2 +- src/components/layout/Page.module.css | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/(main)/reports/[reportId]/Report.module.css b/src/app/(main)/reports/[reportId]/Report.module.css index db65d001..6aa6a9b3 100644 --- a/src/app/(main)/reports/[reportId]/Report.module.css +++ b/src/app/(main)/reports/[reportId]/Report.module.css @@ -3,5 +3,5 @@ grid-template-rows: max-content 1fr; grid-template-columns: max-content 1fr; margin-bottom: 60px; - height: 100%; + height: 90vh; } diff --git a/src/components/layout/Page.module.css b/src/components/layout/Page.module.css index d1498122..52893157 100644 --- a/src/components/layout/Page.module.css +++ b/src/components/layout/Page.module.css @@ -4,7 +4,6 @@ flex-direction: column; position: relative; width: 100%; - height: 100%; max-width: 1320px; margin: 0 auto; padding: 0 20px;