From 2af95b5802e36e3af9003db42c13c8c2f3c1ceb1 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 7 Jun 2025 00:15:30 -0700 Subject: [PATCH] Upgraded Prisma, use new query compiler. Removed old reports. --- db/postgresql/schema.prisma | 2 +- package.json | 4 +- pnpm-lock.yaml | 83 +++---- src/app/(main)/reports/ReportDeleteButton.tsx | 55 ----- src/app/(main)/reports/ReportsDataTable.tsx | 22 -- src/app/(main)/reports/ReportsHeader.tsx | 26 --- src/app/(main)/reports/ReportsPage.tsx | 21 -- src/app/(main)/reports/ReportsTable.tsx | 44 ---- .../reports/[reportId]/BaseParameters.tsx | 65 ------ .../reports/[reportId]/FieldAddForm.tsx | 44 ---- .../reports/[reportId]/FieldAggregateForm.tsx | 53 ----- .../[reportId]/FieldFilterEditForm.module.css | 36 --- .../[reportId]/FieldFilterEditForm.tsx | 219 ------------------ .../reports/[reportId]/FieldParameters.tsx | 55 ----- .../[reportId]/FieldSelectForm.module.css | 20 -- .../reports/[reportId]/FieldSelectForm.tsx | 29 --- .../[reportId]/FilterParameters.module.css | 40 ---- .../reports/[reportId]/FilterParameters.tsx | 140 ----------- .../reports/[reportId]/FilterSelectForm.tsx | 43 ---- .../[reportId]/ParameterList.module.css | 29 --- .../reports/[reportId]/ParameterList.tsx | 56 ----- .../reports/[reportId]/Report.module.css | 7 - src/app/(main)/reports/[reportId]/Report.tsx | 29 --- .../reports/[reportId]/ReportBody.module.css | 5 - .../(main)/reports/[reportId]/ReportBody.tsx | 12 - .../reports/[reportId]/ReportHeader.tsx | 100 -------- .../reports/[reportId]/ReportMenu.module.css | 38 --- .../(main)/reports/[reportId]/ReportMenu.tsx | 26 --- .../(main)/reports/[reportId]/ReportPage.tsx | 35 --- src/app/(main)/reports/[reportId]/page.tsx | 12 - .../attribution/AttributionParameters.tsx | 174 -------------- .../reports/attribution/AttributionReport.tsx | 27 --- .../attribution/AttributionReportPage.tsx | 6 - .../attribution/AttributionStepAddForm.tsx | 77 ------ .../reports/attribution/AttributionView.tsx | 133 ----------- src/app/(main)/reports/attribution/page.tsx | 10 - .../reports/create/ReportCreatePage.tsx | 6 - .../(main)/reports/create/ReportTemplates.tsx | 108 --------- src/app/(main)/reports/create/page.tsx | 10 - .../event-data/EventDataParameters.module.css | 12 - .../event-data/EventDataParameters.tsx | 142 ------------ .../reports/event-data/EventDataReport.tsx | 26 --- .../event-data/EventDataReportPage.tsx | 6 - .../reports/event-data/EventDataTable.tsx | 15 -- src/app/(main)/reports/event-data/page.tsx | 10 - .../reports/insights/InsightsParameters.tsx | 32 --- .../reports/insights/InsightsReport.tsx | 27 --- .../reports/insights/InsightsReportPage.tsx | 6 - .../(main)/reports/insights/InsightsTable.tsx | 57 ----- src/app/(main)/reports/insights/page.tsx | 10 - src/app/(main)/reports/page.tsx | 10 - .../websites/[websiteId]/funnels/Funnel.tsx | 6 +- .../websites/[websiteId]/goals/Goal.tsx | 2 +- .../websites/[websiteId]/journeys/Journey.tsx | 14 +- src/components/common/Panel.tsx | 21 +- src/components/messages.ts | 1 + src/lib/prisma.ts | 9 + src/styles/global.css | 5 - 58 files changed, 88 insertions(+), 2224 deletions(-) delete mode 100644 src/app/(main)/reports/ReportDeleteButton.tsx delete mode 100644 src/app/(main)/reports/ReportsDataTable.tsx delete mode 100644 src/app/(main)/reports/ReportsHeader.tsx delete mode 100644 src/app/(main)/reports/ReportsPage.tsx delete mode 100644 src/app/(main)/reports/ReportsTable.tsx delete mode 100644 src/app/(main)/reports/[reportId]/BaseParameters.tsx delete mode 100644 src/app/(main)/reports/[reportId]/FieldAddForm.tsx delete mode 100644 src/app/(main)/reports/[reportId]/FieldAggregateForm.tsx delete mode 100644 src/app/(main)/reports/[reportId]/FieldFilterEditForm.module.css delete mode 100644 src/app/(main)/reports/[reportId]/FieldFilterEditForm.tsx delete mode 100644 src/app/(main)/reports/[reportId]/FieldParameters.tsx delete mode 100644 src/app/(main)/reports/[reportId]/FieldSelectForm.module.css delete mode 100644 src/app/(main)/reports/[reportId]/FieldSelectForm.tsx delete mode 100644 src/app/(main)/reports/[reportId]/FilterParameters.module.css delete mode 100644 src/app/(main)/reports/[reportId]/FilterParameters.tsx delete mode 100644 src/app/(main)/reports/[reportId]/FilterSelectForm.tsx delete mode 100644 src/app/(main)/reports/[reportId]/ParameterList.module.css delete mode 100644 src/app/(main)/reports/[reportId]/ParameterList.tsx delete mode 100644 src/app/(main)/reports/[reportId]/Report.module.css delete mode 100644 src/app/(main)/reports/[reportId]/Report.tsx delete mode 100644 src/app/(main)/reports/[reportId]/ReportBody.module.css delete mode 100644 src/app/(main)/reports/[reportId]/ReportBody.tsx delete mode 100644 src/app/(main)/reports/[reportId]/ReportHeader.tsx delete mode 100644 src/app/(main)/reports/[reportId]/ReportMenu.module.css delete mode 100644 src/app/(main)/reports/[reportId]/ReportMenu.tsx delete mode 100644 src/app/(main)/reports/[reportId]/ReportPage.tsx delete mode 100644 src/app/(main)/reports/[reportId]/page.tsx delete mode 100644 src/app/(main)/reports/attribution/AttributionParameters.tsx delete mode 100644 src/app/(main)/reports/attribution/AttributionReport.tsx delete mode 100644 src/app/(main)/reports/attribution/AttributionReportPage.tsx delete mode 100644 src/app/(main)/reports/attribution/AttributionStepAddForm.tsx delete mode 100644 src/app/(main)/reports/attribution/AttributionView.tsx delete mode 100644 src/app/(main)/reports/attribution/page.tsx delete mode 100644 src/app/(main)/reports/create/ReportCreatePage.tsx delete mode 100644 src/app/(main)/reports/create/ReportTemplates.tsx delete mode 100644 src/app/(main)/reports/create/page.tsx delete mode 100644 src/app/(main)/reports/event-data/EventDataParameters.module.css delete mode 100644 src/app/(main)/reports/event-data/EventDataParameters.tsx delete mode 100644 src/app/(main)/reports/event-data/EventDataReport.tsx delete mode 100644 src/app/(main)/reports/event-data/EventDataReportPage.tsx delete mode 100644 src/app/(main)/reports/event-data/EventDataTable.tsx delete mode 100644 src/app/(main)/reports/event-data/page.tsx delete mode 100644 src/app/(main)/reports/insights/InsightsParameters.tsx delete mode 100644 src/app/(main)/reports/insights/InsightsReport.tsx delete mode 100644 src/app/(main)/reports/insights/InsightsReportPage.tsx delete mode 100644 src/app/(main)/reports/insights/InsightsTable.tsx delete mode 100644 src/app/(main)/reports/insights/page.tsx delete mode 100644 src/app/(main)/reports/page.tsx diff --git a/db/postgresql/schema.prisma b/db/postgresql/schema.prisma index 6733bca6..d39620ca 100644 --- a/db/postgresql/schema.prisma +++ b/db/postgresql/schema.prisma @@ -1,6 +1,6 @@ generator client { provider = "prisma-client" - previewFeatures = ["driverAdapters"] + previewFeatures = ["queryCompiler", "driverAdapters"] output = "../src/generated/prisma" moduleFormat = "esm" } diff --git a/package.json b/package.json index 70fd1f73..df26f460 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@fontsource/inter": "^4.5.15", "@hello-pangea/dnd": "^17.0.0", "@prisma/adapter-pg": "^6.8.2", - "@prisma/client": "^6.8.2", + "@prisma/client": "^6.9.0", "@prisma/extension-read-replicas": "^0.4.1", "@react-spring/web": "^9.7.3", "@svgr/cli": "^8.1.0", @@ -114,7 +114,7 @@ "node-fetch": "^3.2.8", "npm-run-all": "^4.1.5", "pg": "^8.16.0", - "prisma": "6.8.2", + "prisma": "6.9.0", "pure-rand": "^6.1.0", "react": "^19.0.0", "react-basics": "^0.126.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1fac552a..571361ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,11 +30,11 @@ importers: specifier: ^6.8.2 version: 6.8.2(pg@8.16.0) '@prisma/client': - specifier: ^6.8.2 - version: 6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3) + specifier: ^6.9.0 + version: 6.9.0(prisma@6.9.0(typescript@5.8.3))(typescript@5.8.3) '@prisma/extension-read-replicas': specifier: ^0.4.1 - version: 0.4.1(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3)) + version: 0.4.1(@prisma/client@6.9.0(prisma@6.9.0(typescript@5.8.3))(typescript@5.8.3)) '@react-spring/web': specifier: ^9.7.3 version: 9.7.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -144,8 +144,8 @@ importers: specifier: ^8.16.0 version: 8.16.0 prisma: - specifier: 6.8.2 - version: 6.8.2(typescript@5.8.3) + specifier: 6.9.0 + version: 6.9.0(typescript@5.8.3) pure-rand: specifier: ^6.1.0 version: 6.1.0 @@ -1508,8 +1508,8 @@ packages: peerDependencies: pg: ^8.11.3 - '@prisma/client@6.8.2': - resolution: {integrity: sha512-5II+vbyzv4si6Yunwgkj0qT/iY0zyspttoDrL3R4BYgLdp42/d2C8xdi9vqkrYtKt9H32oFIukvyw3Koz5JoDg==} + '@prisma/client@6.9.0': + resolution: {integrity: sha512-Gg7j1hwy3SgF1KHrh0PZsYvAaykeR0PaxusnLXydehS96voYCGt1U5zVR31NIouYc63hWzidcrir1a7AIyCsNQ==} engines: {node: '>=18.18'} peerDependencies: prisma: '*' @@ -1520,31 +1520,34 @@ packages: typescript: optional: true - '@prisma/config@6.8.2': - resolution: {integrity: sha512-ZJY1fF4qRBPdLQ/60wxNtX+eu89c3AkYEcP7L3jkp0IPXCNphCYxikTg55kPJLDOG6P0X+QG5tCv6CmsBRZWFQ==} + '@prisma/config@6.9.0': + resolution: {integrity: sha512-Wcfk8/lN3WRJd5w4jmNQkUwhUw0eksaU/+BlAJwPQKW10k0h0LC9PD/6TQFmqKVbHQL0vG2z266r0S1MPzzhbA==} '@prisma/debug@6.8.2': resolution: {integrity: sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==} + '@prisma/debug@6.9.0': + resolution: {integrity: sha512-bFeur/qi/Q+Mqk4JdQ3R38upSYPebv5aOyD1RKywVD+rAMLtRkmTFn28ZuTtVOnZHEdtxnNOCH+bPIeSGz1+Fg==} + '@prisma/driver-adapter-utils@6.8.2': resolution: {integrity: sha512-5+CzN/41gBsRmA3ekbVy1TXnSImSPBtMlxWAttVH6tg94bv4zGGRmyk5tUCdT83nl0hG1Sq2oMXR7ml6aqILvw==} - '@prisma/engines-version@6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e': - resolution: {integrity: sha512-Rkik9lMyHpFNGaLpPF3H5q5TQTkm/aE7DsGM5m92FZTvWQsvmi6Va8On3pWvqLHOt5aPUvFb/FeZTmphI4CPiQ==} + '@prisma/engines-version@6.9.0-10.81e4af48011447c3cc503a190e86995b66d2a28e': + resolution: {integrity: sha512-Qp9gMoBHgqhKlrvumZWujmuD7q4DV/gooEyPCLtbkc13EZdSz2RsGUJ5mHb3RJgAbk+dm6XenqG7obJEhXcJ6Q==} - '@prisma/engines@6.8.2': - resolution: {integrity: sha512-XqAJ//LXjqYRQ1RRabs79KOY4+v6gZOGzbcwDQl0D6n9WBKjV7qdrbd042CwSK0v0lM9MSHsbcFnU2Yn7z8Zlw==} + '@prisma/engines@6.9.0': + resolution: {integrity: sha512-im0X0bwDLA0244CDf8fuvnLuCQcBBdAGgr+ByvGfQY9wWl6EA+kRGwVk8ZIpG65rnlOwtaWIr/ZcEU5pNVvq9g==} '@prisma/extension-read-replicas@0.4.1': resolution: {integrity: sha512-mCMDloqUKUwx2o5uedTs1FHX3Nxdt1GdRMoeyp1JggjiwOALmIYWhxfIN08M2BZ0w8SKwvJqicJZMjkQYkkijw==} peerDependencies: '@prisma/client': ^6.5.0 - '@prisma/fetch-engine@6.8.2': - resolution: {integrity: sha512-lCvikWOgaLOfqXGacEKSNeenvj0n3qR5QvZUOmPE2e1Eh8cMYSobxonCg9rqM6FSdTfbpqp9xwhSAOYfNqSW0g==} + '@prisma/fetch-engine@6.9.0': + resolution: {integrity: sha512-PMKhJdl4fOdeE3J3NkcWZ+tf3W6rx3ht/rLU8w4SXFRcLhd5+3VcqY4Kslpdm8osca4ej3gTfB3+cSk5pGxgFg==} - '@prisma/get-platform@6.8.2': - resolution: {integrity: sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==} + '@prisma/get-platform@6.9.0': + resolution: {integrity: sha512-/B4n+5V1LI/1JQcHp+sUpyRT1bBgZVPHbsC4lt4/19Xp4jvNIVcq5KYNtQDk5e/ukTSjo9PZVAxxy9ieFtlpTQ==} '@react-aria/autocomplete@3.0.0-beta.3': resolution: {integrity: sha512-8haBygHNMqVt4Ge90VOk+iVlLW+zhiOGHYz2IKCE6+Sy1dTE6mzhHjxrtwWYnSez/OQLbxjHlwLch4CDd5JkLA==} @@ -5906,8 +5909,8 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - prisma@6.8.2: - resolution: {integrity: sha512-JNricTXQxzDtRS7lCGGOB4g5DJ91eg3nozdubXze3LpcMl1oWwcFddrj++Up3jnRE6X/3gB/xz3V+ecBk/eEGA==} + prisma@6.9.0: + resolution: {integrity: sha512-resJAwMyZREC/I40LF6FZ6rZTnlrlrYrb63oW37Gq+U+9xHwbyMSPJjKtM7VZf3gTO86t/Oyz+YeSXr3CmAY1Q==} engines: {node: '>=18.18'} hasBin: true peerDependencies: @@ -8209,43 +8212,45 @@ snapshots: pg: 8.16.0 postgres-array: 3.0.4 - '@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3)': + '@prisma/client@6.9.0(prisma@6.9.0(typescript@5.8.3))(typescript@5.8.3)': optionalDependencies: - prisma: 6.8.2(typescript@5.8.3) + prisma: 6.9.0(typescript@5.8.3) typescript: 5.8.3 - '@prisma/config@6.8.2': + '@prisma/config@6.9.0': dependencies: jiti: 2.4.2 '@prisma/debug@6.8.2': {} + '@prisma/debug@6.9.0': {} + '@prisma/driver-adapter-utils@6.8.2': dependencies: '@prisma/debug': 6.8.2 - '@prisma/engines-version@6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e': {} + '@prisma/engines-version@6.9.0-10.81e4af48011447c3cc503a190e86995b66d2a28e': {} - '@prisma/engines@6.8.2': + '@prisma/engines@6.9.0': dependencies: - '@prisma/debug': 6.8.2 - '@prisma/engines-version': 6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e - '@prisma/fetch-engine': 6.8.2 - '@prisma/get-platform': 6.8.2 + '@prisma/debug': 6.9.0 + '@prisma/engines-version': 6.9.0-10.81e4af48011447c3cc503a190e86995b66d2a28e + '@prisma/fetch-engine': 6.9.0 + '@prisma/get-platform': 6.9.0 - '@prisma/extension-read-replicas@0.4.1(@prisma/client@6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3))': + '@prisma/extension-read-replicas@0.4.1(@prisma/client@6.9.0(prisma@6.9.0(typescript@5.8.3))(typescript@5.8.3))': dependencies: - '@prisma/client': 6.8.2(prisma@6.8.2(typescript@5.8.3))(typescript@5.8.3) + '@prisma/client': 6.9.0(prisma@6.9.0(typescript@5.8.3))(typescript@5.8.3) - '@prisma/fetch-engine@6.8.2': + '@prisma/fetch-engine@6.9.0': dependencies: - '@prisma/debug': 6.8.2 - '@prisma/engines-version': 6.8.0-43.2060c79ba17c6bb9f5823312b6f6b7f4a845738e - '@prisma/get-platform': 6.8.2 + '@prisma/debug': 6.9.0 + '@prisma/engines-version': 6.9.0-10.81e4af48011447c3cc503a190e86995b66d2a28e + '@prisma/get-platform': 6.9.0 - '@prisma/get-platform@6.8.2': + '@prisma/get-platform@6.9.0': dependencies: - '@prisma/debug': 6.8.2 + '@prisma/debug': 6.9.0 '@react-aria/autocomplete@3.0.0-beta.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: @@ -13603,10 +13608,10 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - prisma@6.8.2(typescript@5.8.3): + prisma@6.9.0(typescript@5.8.3): dependencies: - '@prisma/config': 6.8.2 - '@prisma/engines': 6.8.2 + '@prisma/config': 6.9.0 + '@prisma/engines': 6.9.0 optionalDependencies: typescript: 5.8.3 diff --git a/src/app/(main)/reports/ReportDeleteButton.tsx b/src/app/(main)/reports/ReportDeleteButton.tsx deleted file mode 100644 index d64e2b56..00000000 --- a/src/app/(main)/reports/ReportDeleteButton.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Button, Icon, Modal, DialogTrigger, Dialog, Text } from '@umami/react-zen'; -import { useMessages } from '@/components/hooks'; -import { Trash } from '@/components/icons'; -import { ConfirmationForm } from '@/components/common/ConfirmationForm'; -import { useDeleteQuery } from '@/components/hooks/queries/useDeleteQuery'; - -export function ReportDeleteButton({ - reportId, - reportName, - onDelete, -}: { - reportId: string; - reportName: string; - onDelete?: () => void; -}) { - const { formatMessage, labels, messages } = useMessages(); - const { mutate, isPending, error, touch } = useDeleteQuery(`/reports/${reportId}`); - - const handleConfirm = (close: () => void) => { - mutate(reportId as any, { - onSuccess: () => { - touch('reports'); - onDelete?.(); - close(); - }, - }); - }; - - return ( - - - - - {({ close }) => ( - {reportName}, - })} - isLoading={isPending} - error={error} - onConfirm={handleConfirm.bind(null, close)} - onClose={close} - buttonLabel={formatMessage(labels.delete)} - /> - )} - - - - ); -} diff --git a/src/app/(main)/reports/ReportsDataTable.tsx b/src/app/(main)/reports/ReportsDataTable.tsx deleted file mode 100644 index ca0109e8..00000000 --- a/src/app/(main)/reports/ReportsDataTable.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { ReactNode } from 'react'; -import { useReportsQuery } from '@/components/hooks'; -import { DataGrid } from '@/components/common/DataGrid'; -import { ReportsTable } from './ReportsTable'; - -export function ReportsDataTable({ - websiteId, - teamId, - children, -}: { - websiteId?: string; - teamId?: string; - children?: ReactNode; -}) { - const queryResult = useReportsQuery({ websiteId, teamId }); - - return ( - children}> - {({ data }) => } - - ); -} diff --git a/src/app/(main)/reports/ReportsHeader.tsx b/src/app/(main)/reports/ReportsHeader.tsx deleted file mode 100644 index b477f386..00000000 --- a/src/app/(main)/reports/ReportsHeader.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { SectionHeader } from '@/components/common/SectionHeader'; -import { Icon, Text } from '@umami/react-zen'; -import { useLoginQuery, useMessages, useNavigation } from '@/components/hooks'; -import { Plus } from '@/components/icons'; -import { LinkButton } from '@/components/common/LinkButton'; -import { ROLES } from '@/lib/constants'; - -export function ReportsHeader() { - const { formatMessage, labels } = useMessages(); - const { renderTeamUrl } = useNavigation(); - const { user } = useLoginQuery(); - const canEdit = user.role !== ROLES.viewOnly; - - return ( - - {canEdit && ( - - - - - {formatMessage(labels.createReport)} - - )} - - ); -} diff --git a/src/app/(main)/reports/ReportsPage.tsx b/src/app/(main)/reports/ReportsPage.tsx deleted file mode 100644 index 3041fced..00000000 --- a/src/app/(main)/reports/ReportsPage.tsx +++ /dev/null @@ -1,21 +0,0 @@ -'use client'; -import { Metadata } from 'next'; -import { ReportsHeader } from './ReportsHeader'; -import { ReportsDataTable } from './ReportsDataTable'; -import { useNavigation } from '@/components/hooks'; -import { PageBody } from '@/components/common/PageBody'; - -export function ReportsPage() { - const { teamId } = useNavigation(); - - return ( - - - - - ); -} - -export const metadata: Metadata = { - title: 'Reports', -}; diff --git a/src/app/(main)/reports/ReportsTable.tsx b/src/app/(main)/reports/ReportsTable.tsx deleted file mode 100644 index 7e288384..00000000 --- a/src/app/(main)/reports/ReportsTable.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Icon, Text, DataTable, DataColumn, Row } from '@umami/react-zen'; -import { LinkButton } from '@/components/common/LinkButton'; -import { useMessages, useLoginQuery, useNavigation } from '@/components/hooks'; -import { REPORT_TYPES } from '@/lib/constants'; -import { Arrow } from '@/components/icons'; -import { ReportDeleteButton } from './ReportDeleteButton'; - -export function ReportsTable({ data = [] }: { data: any[]; showDomain?: boolean }) { - const { formatMessage, labels } = useMessages(); - const { user } = useLoginQuery(); - const { renderTeamUrl } = useNavigation(); - - return ( - - - - - {(row: any) => { - return formatMessage( - labels[Object.keys(REPORT_TYPES).find(key => REPORT_TYPES[key] === row.type)], - ); - }} - - - {(row: any) => { - const { id, name, userId, website } = row; - return ( - - {(user.id === userId || user.id === website?.userId) && ( - - )} - - - - - {formatMessage(labels.view)} - - - ); - }} - - - ); -} diff --git a/src/app/(main)/reports/[reportId]/BaseParameters.tsx b/src/app/(main)/reports/[reportId]/BaseParameters.tsx deleted file mode 100644 index 1e49d378..00000000 --- a/src/app/(main)/reports/[reportId]/BaseParameters.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { Column, Label } from '@umami/react-zen'; -import { useReport } from '@/components/hooks'; -import { parseDateRange } from '@/lib/date'; -import { DateFilter } from '@/components/input/DateFilter'; -import { WebsiteSelect } from '@/components/input/WebsiteSelect'; -import { useMessages, useNavigation, useWebsiteQuery } from '@/components/hooks'; - -export interface BaseParametersProps { - showWebsiteSelect?: boolean; - allowWebsiteSelect?: boolean; - showDateSelect?: boolean; - allowDateSelect?: boolean; -} - -export function BaseParameters({ - showWebsiteSelect = true, - allowWebsiteSelect = true, - showDateSelect = true, - allowDateSelect = true, -}: BaseParametersProps) { - const { report, updateReport } = useReport(); - const { formatMessage, labels } = useMessages(); - const { teamId } = useNavigation(); - const { parameters } = report || {}; - const { websiteId, dateRange } = parameters || {}; - const { value, startDate, endDate } = dateRange || {}; - const { data: website } = useWebsiteQuery(websiteId); - const { name } = website || {}; - - const handleWebsiteSelect = (websiteId: string) => { - updateReport({ websiteId, parameters: { websiteId } }); - }; - - const handleDateChange = (value: string) => { - updateReport({ parameters: { dateRange: { ...parseDateRange(value) } } }); - }; - - return ( - <> - {showWebsiteSelect && ( - - - {allowWebsiteSelect ? ( - - ) : ( - name - )} - - )} - {showDateSelect && ( - - - {allowDateSelect && ( - - )} - - )} - - ); -} diff --git a/src/app/(main)/reports/[reportId]/FieldAddForm.tsx b/src/app/(main)/reports/[reportId]/FieldAddForm.tsx deleted file mode 100644 index 8034724e..00000000 --- a/src/app/(main)/reports/[reportId]/FieldAddForm.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useState } from 'react'; -import { createPortal } from 'react-dom'; -import { REPORT_PARAMETERS } from '@/lib/constants'; -import { FieldSelectForm } from './FieldSelectForm'; - -export function FieldAddForm({ - fields = [], - group, - onAdd, - onClose, -}: { - fields?: any[]; - group: string; - onAdd: (group: string, value: string) => void; - onClose: () => void; -}) { - const [selected, setSelected] = useState<{ - name: string; - type: string; - value: string; - }>(); - - const handleSelect = (value: any) => { - const { type } = value; - - if (group === REPORT_PARAMETERS.groups || type === 'array' || type === 'boolean') { - value.value = group === REPORT_PARAMETERS.groups ? '' : 'total'; - handleSave(value); - return; - } - - setSelected(value); - }; - - const handleSave = (value: any) => { - onAdd(group, value); - onClose(); - }; - - return createPortal( - !selected && , - document.body, - ); -} diff --git a/src/app/(main)/reports/[reportId]/FieldAggregateForm.tsx b/src/app/(main)/reports/[reportId]/FieldAggregateForm.tsx deleted file mode 100644 index fd895c7e..00000000 --- a/src/app/(main)/reports/[reportId]/FieldAggregateForm.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Form, FormRow, Menu, Item } from '@umami/react-zen'; -import { useMessages } from '@/components/hooks'; - -export function FieldAggregateForm({ - name, - type, - onSelect, -}: { - name: string; - type: string; - onSelect: (key: any) => void; -}) { - const { formatMessage, labels } = useMessages(); - - const options = { - number: [ - { label: formatMessage(labels.sum), value: 'sum' }, - { label: formatMessage(labels.average), value: 'average' }, - { label: formatMessage(labels.min), value: 'min' }, - { label: formatMessage(labels.max), value: 'max' }, - ], - date: [ - { label: formatMessage(labels.min), value: 'min' }, - { label: formatMessage(labels.max), value: 'max' }, - ], - string: [ - { label: formatMessage(labels.total), value: 'total' }, - { label: formatMessage(labels.unique), value: 'unique' }, - ], - uuid: [ - { label: formatMessage(labels.total), value: 'total' }, - { label: formatMessage(labels.unique), value: 'unique' }, - ], - }; - - const items = options[type]; - - const handleSelect = (value: any) => { - onSelect({ name, type, value }); - }; - - return ( -
- - - {items.map(({ label, value }) => { - return {label}; - })} - - -
- ); -} diff --git a/src/app/(main)/reports/[reportId]/FieldFilterEditForm.module.css b/src/app/(main)/reports/[reportId]/FieldFilterEditForm.module.css deleted file mode 100644 index 43a34438..00000000 --- a/src/app/(main)/reports/[reportId]/FieldFilterEditForm.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.menu { - position: absolute; - max-width: 300px; - max-height: 210px; -} - -.filter { - display: flex; - flex-direction: column; - gap: 20px; -} - -.dropdown { - min-width: 200px; -} - -.text { - min-width: 200px; -} - -.selected { - display: flex; - align-items: center; - justify-content: space-between; - padding: 8px 16px; - white-space: nowrap; - min-width: 200px; - font-weight: 900; - background: var(--base100); - border-radius: var(--border-radius); - cursor: pointer; -} - -.search { - position: relative; -} diff --git a/src/app/(main)/reports/[reportId]/FieldFilterEditForm.tsx b/src/app/(main)/reports/[reportId]/FieldFilterEditForm.tsx deleted file mode 100644 index 4e5e5847..00000000 --- a/src/app/(main)/reports/[reportId]/FieldFilterEditForm.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { useMemo, useState } from 'react'; -import { useFilters, useFormat, useMessages, useWebsiteValuesQuery } from '@/components/hooks'; -import { OPERATORS } from '@/lib/constants'; -import { isEqualsOperator } from '@/lib/params'; -import { - Button, - Column, - Row, - Select, - Icon, - Loading, - Menu, - MenuItem, - ListItem, - SearchField, - Text, - TextField, - Label, -} from '@umami/react-zen'; -import { Close } from '@/components/icons'; -import styles from './FieldFilterEditForm.module.css'; - -export interface FieldFilterFormProps { - websiteId?: string; - name: string; - label?: string; - type: string; - startDate: Date; - endDate: Date; - operator?: string; - defaultValue?: string; - onChange?: (filter: { name: string; type: string; operator: string; value: string }) => void; - allowFilterSelect?: boolean; - isNew?: boolean; -} - -export function FieldFilterEditForm({ - websiteId, - name, - label, - type, - startDate, - endDate, - operator: defaultOperator = 'eq', - defaultValue = '', - onChange, - allowFilterSelect = true, - isNew, -}: FieldFilterFormProps) { - const { formatMessage, labels } = useMessages(); - const [operator, setOperator] = useState(defaultOperator); - const [value, setValue] = useState(defaultValue); - const [showMenu, setShowMenu] = useState(false); - const isEquals = isEqualsOperator(operator); - const [search, setSearch] = useState(''); - const [selected, setSelected] = useState(isEquals ? value : ''); - const { filters } = useFilters(); - const { formatValue } = useFormat(); - const isDisabled = !operator || (isEquals && !selected) || (!isEquals && !value); - const { - data: values = [], - isLoading, - refetch, - } = useWebsiteValuesQuery({ - websiteId, - type: name, - startDate, - endDate, - search, - }); - - const filterDropdownItems = (name: string) => { - const limitedFilters = ['country', 'region', 'city']; - - if (limitedFilters.includes(name)) { - return filters.filter(f => f.type === type && !f.label.match(/contain/gi)); - } else { - return filters.filter(f => f.type === type); - } - }; - - const formattedValues = useMemo(() => { - return values.reduce((obj: { [x: string]: string }, { value }: { value: string }) => { - obj[value] = formatValue(value, name); - - return obj; - }, {}); - }, [formatValue, name, values]); - - const filteredValues = useMemo(() => { - return value - ? values.filter((n: string | number) => - formattedValues[n]?.toLowerCase()?.includes(value.toLowerCase()), - ) - : values; - }, [value, formattedValues]); - - const handleAdd = () => { - onChange({ name, type, operator, value: isEquals ? selected : value }); - }; - - const handleMenuSelect = (value: string) => { - setSelected(value); - setShowMenu(false); - }; - - const handleSearch = (value: string) => { - setSearch(value); - }; - - const handleReset = () => { - setSelected(''); - setValue(''); - setSearch(''); - refetch(); - }; - - const handleOperatorChange = (value: any) => { - setOperator(value); - - if ([OPERATORS.equals, OPERATORS.notEquals].includes(value)) { - setValue(''); - } else { - setSelected(''); - } - }; - - const handleBlur = () => { - window.setTimeout(() => setShowMenu(false), 500); - }; - - const items = filterDropdownItems(name); - - return ( - - - - - {allowFilterSelect && ( - - )} - {selected && isEquals && ( -
- {formatValue(selected, name)} - - - -
- )} - {!selected && isEquals && ( -
- setShowMenu(true)} - onBlur={handleBlur} - /> - {showMenu && ( - - )} -
- )} - {!selected && !isEquals && ( - setValue(e.target.value)} - /> - )} -
- -
-
- ); -} - -const ResultsMenu = ({ values, type, isLoading, onSelect }) => { - const { formatValue } = useFormat(); - if (isLoading) { - return ( - - - - - - ); - } - - if (!values?.length) { - return null; - } - - return ( - - {values?.map(({ value }) => { - return {formatValue(value, type)}; - })} - - ); -}; diff --git a/src/app/(main)/reports/[reportId]/FieldParameters.tsx b/src/app/(main)/reports/[reportId]/FieldParameters.tsx deleted file mode 100644 index 7bf62ece..00000000 --- a/src/app/(main)/reports/[reportId]/FieldParameters.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { useFields, useMessages, useReport } from '@/components/hooks'; -import { Plus } from '@/components/icons'; -import { Button, Row, Label, Icon, Popover, MenuTrigger, Column } from '@umami/react-zen'; -import { FieldSelectForm } from '../[reportId]/FieldSelectForm'; -import { ParameterList } from '../[reportId]/ParameterList'; - -export function FieldParameters() { - const { report, updateReport } = useReport(); - const { formatMessage, labels } = useMessages(); - const { parameters } = report || {}; - const { fields } = parameters || {}; - const { fields: fieldOptions } = useFields(); - - const handleAdd = (value: string) => { - if (!fields.find(({ name }) => name === value)) { - const field = fieldOptions.find(({ name }) => name === value); - updateReport({ parameters: { fields: fields.concat(field) } }); - } - }; - - const handleRemove = (name: string) => { - updateReport({ parameters: { fields: fields.filter(f => f.name !== name) } }); - }; - - return ( - - - - - - - !fields.find(f => f.name === name))} - onSelect={handleAdd} - showType={false} - /> - - - - - {fields.map(({ name }) => { - return ( - handleRemove(name)}> - {fieldOptions.find(f => f.name === name)?.label} - - ); - })} - - - ); -} diff --git a/src/app/(main)/reports/[reportId]/FieldSelectForm.module.css b/src/app/(main)/reports/[reportId]/FieldSelectForm.module.css deleted file mode 100644 index 3a5ed9b8..00000000 --- a/src/app/(main)/reports/[reportId]/FieldSelectForm.module.css +++ /dev/null @@ -1,20 +0,0 @@ -.menu { - width: 360px; - max-height: 300px; - overflow: auto; -} - -.item { - display: flex; - flex-direction: row; - justify-content: space-between; - border-radius: var(--border-radius); -} - -.item:hover { - background: var(--base75); -} - -.type { - color: var(--font-color300); -} diff --git a/src/app/(main)/reports/[reportId]/FieldSelectForm.tsx b/src/app/(main)/reports/[reportId]/FieldSelectForm.tsx deleted file mode 100644 index 038183bc..00000000 --- a/src/app/(main)/reports/[reportId]/FieldSelectForm.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Menu, MenuItem, Text, MenuSection, Row } from '@umami/react-zen'; -import { useMessages } from '@/components/hooks'; - -export interface FieldSelectFormProps { - fields?: any[]; - onSelect?: (value: any) => void; - showType?: boolean; -} - -export function FieldSelectForm({ fields = [], onSelect, showType = true }: FieldSelectFormProps) { - const { formatMessage, labels } = useMessages(); - - return ( - onSelect?.(value)}> - - {fields.map(({ name, label, type }) => { - return ( - - - {label || name} - {showType && type && {type}} - - - ); - })} - - - ); -} diff --git a/src/app/(main)/reports/[reportId]/FilterParameters.module.css b/src/app/(main)/reports/[reportId]/FilterParameters.module.css deleted file mode 100644 index 939d0652..00000000 --- a/src/app/(main)/reports/[reportId]/FilterParameters.module.css +++ /dev/null @@ -1,40 +0,0 @@ -.item { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 10px; - overflow: hidden; -} - -.label { - color: var(--base800); - border: 1px solid var(--base300); - font-weight: 900; - padding: 2px 8px; - border-radius: 5px; - white-space: nowrap; -} - -.op { - color: var(--blue900); - background-color: var(--blue100); - font-size: 12px; - font-weight: 900; - padding: 2px 8px; - border-radius: 5px; - text-transform: uppercase; - white-space: nowrap; -} - -.value { - color: var(--base900); - background-color: var(--base100); - font-weight: 900; - padding: 2px 8px; - border-radius: 5px; - white-space: nowrap; -} - -.edit { - margin-top: 20px; -} diff --git a/src/app/(main)/reports/[reportId]/FilterParameters.tsx b/src/app/(main)/reports/[reportId]/FilterParameters.tsx deleted file mode 100644 index 9d157411..00000000 --- a/src/app/(main)/reports/[reportId]/FilterParameters.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { useMessages, useFormat, useFilters, useFields, useReport } from '@/components/hooks'; -import { Plus } from '@/components/icons'; -import { - Button, - Row, - Column, - Label, - Icon, - Popover, - MenuTrigger, - Text, - Pressable, -} from '@umami/react-zen'; -import { FilterSelectForm } from '../[reportId]/FilterSelectForm'; -import { ParameterList } from '../[reportId]/ParameterList'; -import { FieldFilterEditForm } from '../[reportId]/FieldFilterEditForm'; -import { isSearchOperator } from '@/lib/params'; - -export function FilterParameters() { - const { report, updateReport } = useReport(); - const { formatMessage, labels } = useMessages(); - const { formatValue } = useFormat(); - const { parameters } = report || {}; - const { websiteId, filters, dateRange } = parameters || {}; - const { fields } = useFields(); - - const handleAdd = (value: { name: any }) => { - if (!filters.find(({ name }) => name === value.name)) { - updateReport({ parameters: { filters: filters.concat(value) } }); - } - }; - - const handleRemove = (name: string) => { - updateReport({ parameters: { filters: filters.filter(f => f.name !== name) } }); - }; - - const handleChange = (close: () => void, filter: { name: any }) => { - updateReport({ - parameters: { - filters: filters.map(f => { - if (filter.name === f.name) { - return filter; - } - return f; - }), - }, - }); - close(); - }; - - return ( - - - - - - - !filters.find(f => f.name === name))} - startDate={dateRange?.startDate} - endDate={dateRange?.endDate} - onChange={handleAdd} - /> - - - - - {filters.map( - ({ name, operator, value }: { name: string; operator: string; value: string }) => { - const label = fields.find(f => f.name === name)?.label; - const isSearch = isSearchOperator(operator); - - return ( - handleRemove(name)}> - - - ); - }, - )} - - - ); -} - -const FilterParameter = ({ - websiteId, - name, - label, - operator, - value, - type = 'string', - startDate, - endDate, - onChange, -}) => { - const { operatorLabels } = useFilters(); - - return ( - - - - {label} - - {operatorLabels[operator]} - - {value} - - - - {(close: any) => ( - - )} - - - ); -}; diff --git a/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx b/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx deleted file mode 100644 index beb3350f..00000000 --- a/src/app/(main)/reports/[reportId]/FilterSelectForm.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useState } from 'react'; -import { FieldSelectForm } from './FieldSelectForm'; -import { FieldFilterEditForm } from './FieldFilterEditForm'; - -export interface FilterSelectFormProps { - websiteId?: string; - fields: any[]; - startDate?: Date; - endDate?: Date; - onChange?: (filter: { name: string; type: string; operator: string; value: string }) => void; - allowFilterSelect?: boolean; -} - -export function FilterSelectForm({ - websiteId, - fields, - startDate, - endDate, - onChange, - allowFilterSelect, -}: FilterSelectFormProps) { - const [field, setField] = useState<{ name: string; label: string; type: string }>(); - - if (!field) { - return ; - } - - const { name, label, type } = field; - - return ( - - ); -} diff --git a/src/app/(main)/reports/[reportId]/ParameterList.module.css b/src/app/(main)/reports/[reportId]/ParameterList.module.css deleted file mode 100644 index 75860b25..00000000 --- a/src/app/(main)/reports/[reportId]/ParameterList.module.css +++ /dev/null @@ -1,29 +0,0 @@ -.list { - display: flex; - flex-direction: column; - gap: 16px; -} - -.item { - display: flex; - gap: 12px; - width: 100%; - flex-wrap: nowrap; - padding: 12px; - border: 1px solid var(--base400); - border-radius: var(--border-radius); - box-shadow: 1px 1px 1px var(--base400); -} - -.value { - display: flex; - flex-direction: row; - align-items: center; - flex-wrap: wrap; - flex: 1; -} - -.icon, -.close { - height: 1.5rem; -} diff --git a/src/app/(main)/reports/[reportId]/ParameterList.tsx b/src/app/(main)/reports/[reportId]/ParameterList.tsx deleted file mode 100644 index 663c12ea..00000000 --- a/src/app/(main)/reports/[reportId]/ParameterList.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { ReactNode } from 'react'; -import { Icon, Row, Text, Button, Column } from '@umami/react-zen'; -import { Close } from '@/components/icons'; -import { Empty } from '@/components/common/Empty'; -import { useMessages } from '@/components/hooks'; - -export interface ParameterListProps { - children?: ReactNode; -} - -export function ParameterList({ children }: ParameterListProps) { - const { formatMessage, labels } = useMessages(); - - return ( - - {!children && } - {children} - - ); -} - -const Item = ({ - icon, - onClick, - onRemove, - children, -}: { - icon?: ReactNode; - onClick?: () => void; - onRemove?: () => void; - children?: ReactNode; -}) => { - return ( - - {icon && {icon}} - {children} - - - ); -}; - -ParameterList.Item = Item; diff --git a/src/app/(main)/reports/[reportId]/Report.module.css b/src/app/(main)/reports/[reportId]/Report.module.css deleted file mode 100644 index 6aa6a9b3..00000000 --- a/src/app/(main)/reports/[reportId]/Report.module.css +++ /dev/null @@ -1,7 +0,0 @@ -.container { - display: grid; - grid-template-rows: max-content 1fr; - grid-template-columns: max-content 1fr; - margin-bottom: 60px; - height: 90vh; -} diff --git a/src/app/(main)/reports/[reportId]/Report.tsx b/src/app/(main)/reports/[reportId]/Report.tsx deleted file mode 100644 index 788191b3..00000000 --- a/src/app/(main)/reports/[reportId]/Report.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { createContext, ReactNode } from 'react'; -import { Loading, Grid } from '@umami/react-zen'; -import { useReportQuery } from '@/components/hooks'; - -export const ReportContext = createContext(null); - -export function Report({ - reportId, - defaultParameters, - children, -}: { - reportId: string; - defaultParameters: { type: string; parameters: { [key: string]: any } }; - children: ReactNode; -}) { - const report = useReportQuery(reportId, defaultParameters); - - if (!report) { - return reportId ? : null; - } - - return ( - - - {children} - - - ); -} diff --git a/src/app/(main)/reports/[reportId]/ReportBody.module.css b/src/app/(main)/reports/[reportId]/ReportBody.module.css deleted file mode 100644 index 9af1070a..00000000 --- a/src/app/(main)/reports/[reportId]/ReportBody.module.css +++ /dev/null @@ -1,5 +0,0 @@ -.body { - padding-inline-start: 20px; - grid-row: 2 / 3; - grid-column: 2 / 3; -} diff --git a/src/app/(main)/reports/[reportId]/ReportBody.tsx b/src/app/(main)/reports/[reportId]/ReportBody.tsx deleted file mode 100644 index bbf5323b..00000000 --- a/src/app/(main)/reports/[reportId]/ReportBody.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Panel } from '@/components/common/Panel'; -import { useReport } from '@/components/hooks'; - -export function ReportBody({ children }) { - const { report } = useReport(); - - if (!report) { - return null; - } - - return {children}; -} diff --git a/src/app/(main)/reports/[reportId]/ReportHeader.tsx b/src/app/(main)/reports/[reportId]/ReportHeader.tsx deleted file mode 100644 index d6a7fc05..00000000 --- a/src/app/(main)/reports/[reportId]/ReportHeader.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { - Row, - Column, - Text, - Heading, - Icon, - LoadingButton, - InlineEditField, - useToast, -} from '@umami/react-zen'; -import { useMessages, useApi, useNavigation, useReport } from '@/components/hooks'; -import { REPORT_TYPES } from '@/lib/constants'; - -export function ReportHeader({ icon }) { - const { report, updateReport } = useReport(); - const { formatMessage, labels, messages } = useMessages(); - const { toast } = useToast(); - const { router, renderTeamUrl } = useNavigation(); - - const { post, useMutation } = useApi(); - const { mutate: create, isPending: isCreating } = useMutation({ - mutationFn: (data: any) => post(`/reports`, data), - }); - const { mutate: update, isPending: isUpdating } = useMutation({ - mutationFn: (data: any) => post(`/reports/${data.id}`, data), - }); - - const { name, description, parameters } = report || {}; - const { websiteId, dateRange } = parameters || {}; - const defaultName = formatMessage(labels.untitled); - - const handleSave = async () => { - if (!report.id) { - create(report, { - onSuccess: async ({ id }) => { - toast(formatMessage(messages.saved)); - router.push(renderTeamUrl(`/reports/${id}`)); - }, - }); - } else { - update(report, { - onSuccess: async () => { - toast(formatMessage(messages.saved)); - }, - }); - } - }; - - const handleNameChange = (name: string) => { - updateReport({ name: name || defaultName }); - }; - - const handleDescriptionChange = (description: string) => { - updateReport({ description }); - }; - - if (!report) { - return null; - } - - return ( - - - {icon} - - {formatMessage( - labels[Object.keys(REPORT_TYPES).find(key => REPORT_TYPES[key] === report?.type)], - )} - - - - - - - - {name} - - - - {description || `+ ${formatMessage(labels.addDescription)}`} - - - - - {formatMessage(labels.save)} - - - - ); -} diff --git a/src/app/(main)/reports/[reportId]/ReportMenu.module.css b/src/app/(main)/reports/[reportId]/ReportMenu.module.css deleted file mode 100644 index 21368411..00000000 --- a/src/app/(main)/reports/[reportId]/ReportMenu.module.css +++ /dev/null @@ -1,38 +0,0 @@ -.menu { - position: relative; - width: 300px; - padding-top: 20px; - padding-inline-end: 20px; - border-inline-end: 1px solid var(--base300); - grid-row: 2 / 3; - grid-column: 1 / 2; -} - -.button { - position: absolute; - top: 0; - right: 0; - display: flex; - place-content: center; - border: 1px solid var(--base400); - border-right: 0; - width: 30px; - padding: 5px; - cursor: pointer; - border-radius: 4px 0 0 4px; - z-index: 1; -} - -.button:hover { - background: var(--base75); -} - -.menu.collapsed { - width: 0; - padding: 0; -} - -.menu.collapsed .button { - right: 0; - border-radius: 4px 0 0 4px; -} diff --git a/src/app/(main)/reports/[reportId]/ReportMenu.tsx b/src/app/(main)/reports/[reportId]/ReportMenu.tsx deleted file mode 100644 index 23175fc2..00000000 --- a/src/app/(main)/reports/[reportId]/ReportMenu.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useState } from 'react'; -import { Button, Column, Icon, Row } from '@umami/react-zen'; -import { PanelLeft } from '@/components/icons'; -import { useReport } from '@/components/hooks'; - -export function ReportMenu({ children }) { - const [collapsed, setCollapsed] = useState(false); - const { report } = useReport(); - - if (!report) { - return null; - } - - return ( - - - - - {!collapsed && children} - - ); -} diff --git a/src/app/(main)/reports/[reportId]/ReportPage.tsx b/src/app/(main)/reports/[reportId]/ReportPage.tsx deleted file mode 100644 index 11c80f5f..00000000 --- a/src/app/(main)/reports/[reportId]/ReportPage.tsx +++ /dev/null @@ -1,35 +0,0 @@ -'use client'; -import { useReportQuery } from '@/components/hooks'; -import { EventDataReport } from '../event-data/EventDataReport'; -import { FunnelReport } from '../funnel/FunnelReport'; -import { GoalsReport } from '../goals/GoalsReport'; -import { InsightsReport } from '../insights/InsightsReport'; -import { JourneyReport } from '../journey/JourneyReport'; -import { RetentionReport } from '../retention/RetentionReport'; -import { UTMReport } from '../utm/UTMReport'; -import { RevenueReport } from '../revenue/RevenueReport'; -import AttributionReport from '../attribution/AttributionReport'; - -const reports = { - funnel: FunnelReport, - 'event-data': EventDataReport, - insights: InsightsReport, - retention: RetentionReport, - utm: UTMReport, - goals: GoalsReport, - journey: JourneyReport, - revenue: RevenueReport, - attribution: AttributionReport, -}; - -export function ReportPage({ reportId }: { reportId: string }) { - const { report } = useReportQuery(reportId); - - if (!report) { - return null; - } - - const ReportComponent = reports[report.type]; - - return ; -} diff --git a/src/app/(main)/reports/[reportId]/page.tsx b/src/app/(main)/reports/[reportId]/page.tsx deleted file mode 100644 index b228896a..00000000 --- a/src/app/(main)/reports/[reportId]/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Metadata } from 'next'; -import { ReportPage } from './ReportPage'; - -export default async function ({ params }: { params: Promise<{ reportId: string }> }) { - const { reportId } = await params; - - return ; -} - -export const metadata: Metadata = { - title: 'Reports', -}; diff --git a/src/app/(main)/reports/attribution/AttributionParameters.tsx b/src/app/(main)/reports/attribution/AttributionParameters.tsx deleted file mode 100644 index 15d737c9..00000000 --- a/src/app/(main)/reports/attribution/AttributionParameters.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import { useMessages } from '@/components/hooks'; -import { Eye, Bolt, Plus } from '@/components/icons'; -import { useContext, useState } from 'react'; -import { - Button, - Select, - Form, - FormButtons, - FormField, - Icon, - ListItem, - Popover, - DialogTrigger, - Toggle, - FormSubmitButton, -} from '@umami/react-zen'; -import { BaseParameters } from '../[reportId]/BaseParameters'; -import { ParameterList } from '../[reportId]/ParameterList'; -import { ReportContext } from '../[reportId]/Report'; -import { FunnelStepAddForm } from '../funnel/FunnelStepAddForm'; -import { AttributionStepAddForm } from './AttributionStepAddForm'; -import { useRevenueValuesQuery } from '@/components/hooks/queries/useRevenueValuesQuery'; - -export function AttributionParameters() { - const { report, runReport, updateReport, isRunning } = useContext(ReportContext); - const { formatMessage, labels } = useMessages(); - const { id, parameters } = report || {}; - const { websiteId, dateRange, steps } = parameters || {}; - const queryEnabled = websiteId && dateRange && steps.length > 0; - const [model, setModel] = useState(''); - const [revenueMode, setRevenueMode] = useState(false); - - const { data: currencyValues = [] } = useRevenueValuesQuery( - websiteId, - dateRange?.startDate, - dateRange?.endDate, - ); - - const handleSubmit = (data: any, e: any) => { - if (revenueMode === false) { - delete data.currency; - } - - e.stopPropagation(); - e.preventDefault(); - runReport(data); - }; - - const handleCheck = () => { - setRevenueMode(!revenueMode); - }; - - const handleAddStep = (step: { type: string; value: string }) => { - if (step.type === 'url') { - setRevenueMode(false); - } - updateReport({ parameters: { steps: parameters.steps.concat(step) } }); - }; - - const handleUpdateStep = ( - close: () => void, - index: number, - step: { type: string; value: string }, - ) => { - if (step.type === 'url') { - setRevenueMode(false); - } - const steps = [...parameters.steps]; - steps[index] = step; - updateReport({ parameters: { steps } }); - close(); - }; - - const handleRemoveStep = (index: number) => { - const steps = [...parameters.steps]; - delete steps[index]; - updateReport({ parameters: { steps: steps.filter(n => n) } }); - }; - - const AddStepButton = () => { - return ( - - - - - - - ); - }; - - const items = [ - { id: 'first-click', label: 'First-Click', value: 'firstClick' }, - { id: 'last-click', label: 'Last-Click', value: 'lastClick' }, - ]; - - const onModelChange = (value: any) => { - setModel(value); - updateReport({ parameters: { model } }); - }; - - return ( -
- - - - - - - {steps.map((step: { type: string; value: string }, index: number) => { - return ( - - : } - onRemove={() => handleRemoveStep(index)} - > -
{step.value}
-
- - - -
- ); - })} -
- -
- - - Revenue Mode - - - {revenueMode && ( - - - - )} - - - {formatMessage(labels.runQuery)} - - - - ); -} diff --git a/src/app/(main)/reports/attribution/AttributionReport.tsx b/src/app/(main)/reports/attribution/AttributionReport.tsx deleted file mode 100644 index e7981592..00000000 --- a/src/app/(main)/reports/attribution/AttributionReport.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Network } from '@/components/icons'; -import { REPORT_TYPES } from '@/lib/constants'; -import { Report } from '../[reportId]/Report'; -import { ReportBody } from '../[reportId]/ReportBody'; -import { ReportHeader } from '../[reportId]/ReportHeader'; -import { ReportMenu } from '../[reportId]/ReportMenu'; -import { AttributionParameters } from './AttributionParameters'; -import { AttributionView } from './AttributionView'; - -const defaultParameters = { - type: REPORT_TYPES.attribution, - parameters: { model: 'firstClick', steps: [] }, -}; - -export default function AttributionReport({ reportId }: { reportId?: string }) { - return ( - - } /> - - - - - - - - ); -} diff --git a/src/app/(main)/reports/attribution/AttributionReportPage.tsx b/src/app/(main)/reports/attribution/AttributionReportPage.tsx deleted file mode 100644 index ed730704..00000000 --- a/src/app/(main)/reports/attribution/AttributionReportPage.tsx +++ /dev/null @@ -1,6 +0,0 @@ -'use client'; -import AttributionReport from './AttributionReport'; - -export default function AttributionReportPage() { - return ; -} diff --git a/src/app/(main)/reports/attribution/AttributionStepAddForm.tsx b/src/app/(main)/reports/attribution/AttributionStepAddForm.tsx deleted file mode 100644 index 8a81c06f..00000000 --- a/src/app/(main)/reports/attribution/AttributionStepAddForm.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { useState } from 'react'; -import { useMessages } from '@/components/hooks'; -import { - Button, - FormButtons, - FormField, - TextField, - Row, - Column, - Select, - ListItem, -} from '@umami/react-zen'; - -export interface AttributionStepAddFormProps { - type?: string; - value?: string; - onChange?: (step: { type: string; value: string }) => void; -} - -export function AttributionStepAddForm({ - type: defaultType = 'url', - value: defaultValue = '', - onChange, -}: AttributionStepAddFormProps) { - const [type, setType] = useState(defaultType); - const [value, setValue] = useState(defaultValue); - const { formatMessage, labels } = useMessages(); - const items = [ - { id: 'url', label: formatMessage(labels.url), value: 'url' }, - { id: 'event', label: formatMessage(labels.event), value: 'event' }, - ]; - const isDisabled = !type || !value; - - const handleSave = () => { - onChange({ type, value }); - setValue(''); - }; - - const handleChange = e => { - setValue(e.target.value); - }; - - const handleKeyDown = e => { - if (e.key === 'Enter') { - e.stopPropagation(); - handleSave(); - } - }; - - return ( - - - - - - - - - - - - ); -} - -export default AttributionStepAddForm; diff --git a/src/app/(main)/reports/attribution/AttributionView.tsx b/src/app/(main)/reports/attribution/AttributionView.tsx deleted file mode 100644 index 3e560f36..00000000 --- a/src/app/(main)/reports/attribution/AttributionView.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { useContext } from 'react'; -import { PieChart } from '@/components/charts/PieChart'; -import { useMessages } from '@/components/hooks'; -import { GridRow } from '@/components/common/GridRow'; -import { ListTable } from '@/components/metrics/ListTable'; -import { MetricCard } from '@/components/metrics/MetricCard'; -import { MetricsBar } from '@/components/metrics/MetricsBar'; -import { CHART_COLORS } from '@/lib/constants'; -import { formatLongNumber } from '@/lib/format'; -import { ReportContext } from '../[reportId]/Report'; - -export interface AttributionViewProps { - isLoading?: boolean; -} - -export function AttributionView({ isLoading }: AttributionViewProps) { - const { formatMessage, labels } = useMessages(); - const { report } = useContext(ReportContext); - const { - data, - parameters: { currency }, - } = report || {}; - const ATTRIBUTION_PARAMS = [ - { value: 'referrer', label: formatMessage(labels.referrers) }, - { value: 'paidAds', label: formatMessage(labels.paidAds) }, - ]; - - if (!data) { - return null; - } - - const { pageviews, visitors, visits } = data.total; - - const metrics = data - ? [ - { - value: pageviews, - label: formatMessage(labels.views), - formatValue: formatLongNumber, - }, - { - value: visits, - label: formatMessage(labels.visits), - formatValue: formatLongNumber, - }, - { - value: visitors, - label: formatMessage(labels.visitors), - formatValue: formatLongNumber, - }, - ] - : []; - - function UTMTable(UTMTableProps: { data: any; title: string; utm: string }) { - const { data, title, utm } = UTMTableProps; - const total = data[utm].reduce((sum, { value }) => { - return +sum + +value; - }, 0); - - return ( - ({ - x: name, - y: Number(value), - z: (value / total) * 100, - }))} - /> - ); - } - - return ( -
- - {metrics?.map(({ label, value, formatValue }) => { - return ; - })} - - {ATTRIBUTION_PARAMS.map(({ value, label }) => { - const items = data[value]; - const total = items.reduce((sum, { value }) => { - return +sum + +value; - }, 0); - - const chartData = { - labels: items.map(({ name }) => name), - datasets: [ - { - data: items.map(({ value }) => value), - backgroundColor: CHART_COLORS, - borderWidth: 0, - }, - ], - }; - - return ( -
-
-
{label}
- ({ - x: name, - y: Number(value), - z: (value / total) * 100, - }))} - /> -
-
- -
-
- ); - })} - <> - - - - - - - - - - -
- ); -} - -export default AttributionView; diff --git a/src/app/(main)/reports/attribution/page.tsx b/src/app/(main)/reports/attribution/page.tsx deleted file mode 100644 index 9efd6220..00000000 --- a/src/app/(main)/reports/attribution/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import AttributionReportPage from './AttributionReportPage'; -import { Metadata } from 'next'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Attribution Report', -}; diff --git a/src/app/(main)/reports/create/ReportCreatePage.tsx b/src/app/(main)/reports/create/ReportCreatePage.tsx deleted file mode 100644 index 4a04d026..00000000 --- a/src/app/(main)/reports/create/ReportCreatePage.tsx +++ /dev/null @@ -1,6 +0,0 @@ -'use client'; -import { ReportTemplates } from './ReportTemplates'; - -export function ReportCreatePage() { - return ; -} diff --git a/src/app/(main)/reports/create/ReportTemplates.tsx b/src/app/(main)/reports/create/ReportTemplates.tsx deleted file mode 100644 index 68ea0213..00000000 --- a/src/app/(main)/reports/create/ReportTemplates.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { Icon, Text, Row, Column, Grid } from '@umami/react-zen'; -import { useMessages, useNavigation } from '@/components/hooks'; -import { - Lightbulb, - Funnel, - Magnet, - Tag, - Target, - Path, - Money, - Network, - Plus, -} from '@/components/icons'; -import { SectionHeader } from '@/components/common/SectionHeader'; -import { LinkButton } from '@/components/common/LinkButton'; - -export function ReportTemplates({ showHeader = true }: { showHeader?: boolean }) { - const { formatMessage, labels } = useMessages(); - const { renderTeamUrl } = useNavigation(); - - const reports = [ - { - title: formatMessage(labels.insights), - description: formatMessage(labels.insightsDescription), - url: renderTeamUrl('/reports/insights'), - icon: , - }, - { - title: formatMessage(labels.funnel), - description: formatMessage(labels.funnelDescription), - url: renderTeamUrl('/reports/funnel'), - icon: , - }, - { - title: formatMessage(labels.retention), - description: formatMessage(labels.retentionDescription), - url: renderTeamUrl('/reports/retention'), - icon: , - }, - { - title: formatMessage(labels.utm), - description: formatMessage(labels.utmDescription), - url: renderTeamUrl('/reports/utm'), - icon: , - }, - { - title: formatMessage(labels.goals), - description: formatMessage(labels.goalsDescription), - url: renderTeamUrl('/reports/goals'), - icon: , - }, - { - title: formatMessage(labels.journey), - description: formatMessage(labels.journeyDescription), - url: renderTeamUrl('/reports/journey'), - icon: , - }, - { - title: formatMessage(labels.revenue), - description: formatMessage(labels.revenueDescription), - url: renderTeamUrl('/reports/revenue'), - icon: , - }, - { - title: formatMessage(labels.attribution), - description: formatMessage(labels.attributionDescription), - url: renderTeamUrl('/reports/attribution'), - icon: , - }, - ]; - - return ( - <> - {showHeader && } - - {reports.map(({ title, description, url, icon }) => { - return ( - - ); - })} - - - ); -} - -function ReportItem({ title, description, url, icon }) { - const { formatMessage, labels } = useMessages(); - - return ( - - - {icon} - - {title} - - - {description} - - - - - - {formatMessage(labels.create)} - - - - ); -} diff --git a/src/app/(main)/reports/create/page.tsx b/src/app/(main)/reports/create/page.tsx deleted file mode 100644 index 608367fc..00000000 --- a/src/app/(main)/reports/create/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { ReportCreatePage } from './ReportCreatePage'; -import { Metadata } from 'next'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Create Report', -}; diff --git a/src/app/(main)/reports/event-data/EventDataParameters.module.css b/src/app/(main)/reports/event-data/EventDataParameters.module.css deleted file mode 100644 index 06b62414..00000000 --- a/src/app/(main)/reports/event-data/EventDataParameters.module.css +++ /dev/null @@ -1,12 +0,0 @@ -.parameter { - display: flex; - gap: 10px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0; -} - -.op { - font-weight: bold; -} diff --git a/src/app/(main)/reports/event-data/EventDataParameters.tsx b/src/app/(main)/reports/event-data/EventDataParameters.tsx deleted file mode 100644 index e93b5d23..00000000 --- a/src/app/(main)/reports/event-data/EventDataParameters.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { - Form, - FormField, - FormButtons, - FormSubmitButton, - DialogTrigger, - Icon, - Popover, -} from '@umami/react-zen'; -import { Empty } from '@/components/common/Empty'; -import { Plus } from '@/components/icons'; -import { useApi, useMessages, useReport } from '@/components/hooks'; -import { DATA_TYPES, REPORT_PARAMETERS } from '@/lib/constants'; -import { FieldAddForm } from '../[reportId]/FieldAddForm'; -import { ParameterList } from '../[reportId]/ParameterList'; -import { BaseParameters } from '../[reportId]/BaseParameters'; -import styles from './EventDataParameters.module.css'; - -function useFields(websiteId, startDate, endDate) { - const { get, useQuery } = useApi(); - const { data, error, isLoading } = useQuery({ - queryKey: ['fields', websiteId, startDate, endDate], - queryFn: () => - get('/reports/event-data', { - websiteId, - startAt: +startDate, - endAt: +endDate, - }), - enabled: !!(websiteId && startDate && endDate), - }); - - return { data, error, isLoading }; -} - -export function EventDataParameters() { - const { report, runReport, updateReport, isRunning } = useReport(); - const { formatMessage, labels, messages } = useMessages(); - const { id, parameters } = report || {}; - const { websiteId, dateRange, fields, filters, groups } = parameters || {}; - const { startDate, endDate } = dateRange || {}; - const queryEnabled = websiteId && dateRange && fields?.length; - const { data, error } = useFields(websiteId, startDate, endDate); - const parametersSelected = websiteId && startDate && endDate; - const hasData = data?.length !== 0; - - const parameterGroups = [ - { label: formatMessage(labels.fields), group: REPORT_PARAMETERS.fields }, - { label: formatMessage(labels.filters), group: REPORT_PARAMETERS.filters }, - ]; - - const parameterData = { - fields, - filters, - groups, - }; - - const handleSubmit = (values: any) => { - runReport(values); - }; - - const handleAdd = (group: string, value: any) => { - const data = parameterData[group]; - - if (!data.find(({ name }) => name === value?.name)) { - updateReport({ parameters: { [group]: data.concat(value) } }); - } - }; - - const handleRemove = (group: string) => { - const data = [...parameterData[group]]; - updateReport({ parameters: { [group]: data.filter(({ name }) => name !== group) } }); - }; - - const AddButton = ({ group, onAdd }) => { - return ( - - - - - - {({ close }: any) => { - return ( - ({ - name: dataKey, - type: DATA_TYPES[eventDataType], - }))} - group={group} - onAdd={onAdd} - onClose={close} - /> - ); - }} - - - ); - }; - - return ( -
- - {!hasData && } - {parametersSelected && - hasData && - parameterGroups.map(({ label, group }) => { - return ( - - - {parameterData[group].map(({ name, value }) => { - return ( - handleRemove(group)}> -
- {group === REPORT_PARAMETERS.fields && ( - <> -
{name}
-
{value}
- - )} - {group === REPORT_PARAMETERS.filters && ( - <> -
{name}
-
{value[0]}
-
{value[1]}
- - )} -
-
- ); - })} -
- -
- ); - })} - - - {formatMessage(labels.runQuery)} - - - - ); -} diff --git a/src/app/(main)/reports/event-data/EventDataReport.tsx b/src/app/(main)/reports/event-data/EventDataReport.tsx deleted file mode 100644 index 6c6afef1..00000000 --- a/src/app/(main)/reports/event-data/EventDataReport.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Report } from '../[reportId]/Report'; -import { ReportHeader } from '../[reportId]/ReportHeader'; -import { ReportMenu } from '../[reportId]/ReportMenu'; -import { ReportBody } from '../[reportId]/ReportBody'; -import { EventDataParameters } from './EventDataParameters'; -import { EventDataTable } from './EventDataTable'; -import { Nodes } from '@/components/icons'; - -const defaultParameters = { - type: 'event-data', - parameters: { fields: [], filters: [] }, -}; - -export function EventDataReport({ reportId }: { reportId?: string }) { - return ( - - } /> - - - - - - - - ); -} diff --git a/src/app/(main)/reports/event-data/EventDataReportPage.tsx b/src/app/(main)/reports/event-data/EventDataReportPage.tsx deleted file mode 100644 index 92bd0a05..00000000 --- a/src/app/(main)/reports/event-data/EventDataReportPage.tsx +++ /dev/null @@ -1,6 +0,0 @@ -'use client'; -import { EventDataReport } from './EventDataReport'; - -export function EventDataReportPage() { - return ; -} diff --git a/src/app/(main)/reports/event-data/EventDataTable.tsx b/src/app/(main)/reports/event-data/EventDataTable.tsx deleted file mode 100644 index 7aec1b77..00000000 --- a/src/app/(main)/reports/event-data/EventDataTable.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { DataTable, DataColumn } from '@umami/react-zen'; -import { useMessages, useReport } from '@/components/hooks'; - -export function EventDataTable() { - const { report } = useReport(); - const { formatMessage, labels } = useMessages(); - - return ( - - - - - - ); -} diff --git a/src/app/(main)/reports/event-data/page.tsx b/src/app/(main)/reports/event-data/page.tsx deleted file mode 100644 index 88875408..00000000 --- a/src/app/(main)/reports/event-data/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Metadata } from 'next'; -import { EventDataReportPage } from './EventDataReportPage'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Event Data Report', -}; diff --git a/src/app/(main)/reports/insights/InsightsParameters.tsx b/src/app/(main)/reports/insights/InsightsParameters.tsx deleted file mode 100644 index 944cfe58..00000000 --- a/src/app/(main)/reports/insights/InsightsParameters.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useMessages, useReport } from '@/components/hooks'; -import { Form, FormButtons, FormSubmitButton } from '@umami/react-zen'; -import { BaseParameters } from '../[reportId]/BaseParameters'; -import { FieldParameters } from '../[reportId]/FieldParameters'; -import { FilterParameters } from '../[reportId]/FilterParameters'; - -export function InsightsParameters() { - const { report, runReport, isRunning } = useReport(); - const { formatMessage, labels } = useMessages(); - const { id, parameters } = report || {}; - const { websiteId, dateRange, fields, filters } = parameters || {}; - const { startDate, endDate } = dateRange || {}; - const parametersSelected = websiteId && startDate && endDate; - const queryEnabled = websiteId && dateRange && (fields?.length || filters?.length); - - const handleSubmit = (values: any) => { - runReport(values); - }; - - return ( -
- - {parametersSelected && } - {parametersSelected && } - - - {formatMessage(labels.runQuery)} - - - - ); -} diff --git a/src/app/(main)/reports/insights/InsightsReport.tsx b/src/app/(main)/reports/insights/InsightsReport.tsx deleted file mode 100644 index 6f0f6a71..00000000 --- a/src/app/(main)/reports/insights/InsightsReport.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Report } from '../[reportId]/Report'; -import { ReportHeader } from '../[reportId]/ReportHeader'; -import { ReportMenu } from '../[reportId]/ReportMenu'; -import { ReportBody } from '../[reportId]/ReportBody'; -import { InsightsParameters } from './InsightsParameters'; -import { InsightsTable } from './InsightsTable'; -import { Lightbulb } from '@/components/icons'; -import { REPORT_TYPES } from '@/lib/constants'; - -const defaultParameters = { - type: REPORT_TYPES.insights, - parameters: { fields: [], filters: [] }, -}; - -export function InsightsReport({ reportId }: { reportId?: string }) { - return ( - - } /> - - - - - - - - ); -} diff --git a/src/app/(main)/reports/insights/InsightsReportPage.tsx b/src/app/(main)/reports/insights/InsightsReportPage.tsx deleted file mode 100644 index 80cb42ff..00000000 --- a/src/app/(main)/reports/insights/InsightsReportPage.tsx +++ /dev/null @@ -1,6 +0,0 @@ -'use client'; -import { InsightsReport } from './InsightsReport'; - -export function InsightsReportPage() { - return ; -} diff --git a/src/app/(main)/reports/insights/InsightsTable.tsx b/src/app/(main)/reports/insights/InsightsTable.tsx deleted file mode 100644 index e1bd59df..00000000 --- a/src/app/(main)/reports/insights/InsightsTable.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useEffect, useState } from 'react'; -import { DataTable, DataColumn } from '@umami/react-zen'; -import { useFormat, useMessages, useReport } from '@/components/hooks'; -import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder'; -import { formatShortTime } from '@/lib/format'; - -export function InsightsTable() { - const [fields, setFields] = useState([]); - const { report } = useReport(); - const { formatMessage, labels } = useMessages(); - const { formatValue } = useFormat(); - - useEffect( - () => { - setFields(report?.parameters?.fields); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [report?.data], - ); - - if (!fields || !report?.parameters) { - return ; - } - - return ( - - {fields.map(({ name, label }) => { - return ( - - {row => formatValue(row[name], name)} - - ); - })} - - {(row: any) => row?.views?.toLocaleString()} - - - {(row: any) => row?.visits?.toLocaleString()} - - - {(row: any) => row?.visitors?.toLocaleString()} - - - {(row: any) => { - const n = (Math.min(row?.visits, row?.bounces) / row?.visits) * 100; - return Math.round(+n) + '%'; - }} - - - {(row: any) => { - const n = row?.totaltime / row?.visits; - return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`; - }} - - - ); -} diff --git a/src/app/(main)/reports/insights/page.tsx b/src/app/(main)/reports/insights/page.tsx deleted file mode 100644 index 7b9b8722..00000000 --- a/src/app/(main)/reports/insights/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { InsightsReportPage } from './InsightsReportPage'; -import { Metadata } from 'next'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Insights Report', -}; diff --git a/src/app/(main)/reports/page.tsx b/src/app/(main)/reports/page.tsx deleted file mode 100644 index 621281c4..00000000 --- a/src/app/(main)/reports/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { ReportsPage } from './ReportsPage'; -import { Metadata } from 'next'; - -export default function () { - return ; -} - -export const metadata: Metadata = { - title: 'Reports', -}; diff --git a/src/app/(main)/websites/[websiteId]/funnels/Funnel.tsx b/src/app/(main)/websites/[websiteId]/funnels/Funnel.tsx index 6281b5a2..2ca2e41b 100644 --- a/src/app/(main)/websites/[websiteId]/funnels/Funnel.tsx +++ b/src/app/(main)/websites/[websiteId]/funnels/Funnel.tsx @@ -43,7 +43,11 @@ export function Funnel({ id, name, type, parameters, websiteId, startDate, endDa {({ close }) => { return ( - + ); diff --git a/src/app/(main)/websites/[websiteId]/goals/Goal.tsx b/src/app/(main)/websites/[websiteId]/goals/Goal.tsx index 3037ffdb..8e2d453a 100644 --- a/src/app/(main)/websites/[websiteId]/goals/Goal.tsx +++ b/src/app/(main)/websites/[websiteId]/goals/Goal.tsx @@ -52,7 +52,7 @@ export function Goal({ id, name, type, parameters, websiteId, startDate, endDate diff --git a/src/app/(main)/websites/[websiteId]/journeys/Journey.tsx b/src/app/(main)/websites/[websiteId]/journeys/Journey.tsx index fd5b35d5..bbb84eaa 100644 --- a/src/app/(main)/websites/[websiteId]/journeys/Journey.tsx +++ b/src/app/(main)/websites/[websiteId]/journeys/Journey.tsx @@ -1,12 +1,13 @@ import { useMemo, useState } from 'react'; -import { TooltipTrigger, Tooltip, Focusable } from '@umami/react-zen'; +import { TooltipTrigger, Tooltip, Focusable, Icon, Text, Row } from '@umami/react-zen'; import { firstBy } from 'thenby'; import classNames from 'classnames'; import { useEscapeKey, useMessages, useResultQuery } from '@/components/hooks'; +import { File, Lightning } from '@/components/icons'; import { objectToArray } from '@/lib/data'; -import styles from './Journey.module.css'; import { formatLongNumber } from '@/lib/format'; import { LoadingPanel } from '@/components/common/LoadingPanel'; +import styles from './Journey.module.css'; const NODE_HEIGHT = 60; const NODE_GAP = 10; @@ -221,11 +222,12 @@ export function Journey({ })} onClick={() => handleClick(name, columnIndex, paths)} > -
- {name} -
+ + {name.startsWith('/') ? : } + {name} +
- +
{formatLongNumber(nodeCount)}
diff --git a/src/components/common/Panel.tsx b/src/components/common/Panel.tsx index 54024c84..5a7e8fb0 100644 --- a/src/components/common/Panel.tsx +++ b/src/components/common/Panel.tsx @@ -1,6 +1,15 @@ import { useState } from 'react'; -import { Column, type ColumnProps, Row, Icon, Button } from '@umami/react-zen'; +import { + Column, + type ColumnProps, + Row, + Icon, + Button, + TooltipTrigger, + Tooltip, +} from '@umami/react-zen'; import { Maximize, Close } from '@/components/icons'; +import { useMessages } from '@/components/hooks'; export interface PanelProps extends ColumnProps { allowFullscreen?: boolean; @@ -16,6 +25,7 @@ const fullscreenStyles = { } as any; export function Panel({ allowFullscreen, style, children, ...props }: PanelProps) { + const { formatMessage, labels } = useMessages(); const [isFullscreen, setIsFullscreen] = useState(false); const handleFullscreen = () => { @@ -35,9 +45,12 @@ export function Panel({ allowFullscreen, style, children, ...props }: PanelProps > {allowFullscreen && ( - + + + {formatMessage(labels.expand)} + )} {children} diff --git a/src/components/messages.ts b/src/components/messages.ts index 91743807..62d98c56 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -324,6 +324,7 @@ export const labels = defineMessages({ pixels: { id: 'label.pixels', defaultMessage: 'Pixels' }, addBoard: { id: 'label.add-board', defaultMessage: 'Add board' }, cohort: { id: 'label.cohort', defaultMessage: 'Cohort' }, + expand: { id: 'label.expand', defaultMessage: 'Expand' }, }); export const messages = defineMessages({ diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index 406cf9ce..ecbe3e53 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -1,5 +1,6 @@ import debug from 'debug'; import { PrismaClient } from '@/generated/prisma/client'; +import { PrismaPg } from '@prisma/adapter-pg'; import { readReplicas } from '@prisma/extension-read-replicas'; import { formatInTimeZone } from 'date-fns-tz'; import { MYSQL, POSTGRESQL, getDatabaseType } from '@/lib/db'; @@ -353,7 +354,15 @@ function getClient(params?: { options, } = params || {}; + const url = new URL(process.env.DATABASE_URL); + + const adapter = new PrismaPg( + { connectionString: url.toString() }, + { schema: url.searchParams.get('schema') }, + ); + const prisma = new PrismaClient({ + adapter, errorFormat: 'pretty', ...(logQuery && PRISMA_LOG_OPTIONS), ...options, diff --git a/src/styles/global.css b/src/styles/global.css index 837a196e..37b16c33 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -15,11 +15,6 @@ a:hover { text-decoration: none; } -:where(svg) { - width: 1rem; - height: 1rem; -} - ::-webkit-scrollbar { width: 15px; background: transparent;