From 306ca4a43503443deb556f2fef9600d7b6408590 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 2 Jun 2026 22:35:07 -0700 Subject: [PATCH] Lint format files. Updated rng function. --- package.json | 1 - scripts/check-db.js | 6 +- scripts/download-country-names.js | 2 +- scripts/download-language-names.js | 2 +- src/app/(collect)/p/[slug]/route.ts | 2 +- src/app/(collect)/q/[slug]/route.ts | 2 +- src/app/(main)/MobileNav.tsx | 2 +- src/app/(main)/SideNav.tsx | 30 +-- src/app/(main)/admin/AdminNav.tsx | 4 +- .../(main)/admin/teams/AdminTeamsTable.tsx | 6 +- src/app/(main)/admin/users/UsersTable.tsx | 6 +- .../admin/websites/AdminWebsitesTable.tsx | 6 +- src/app/(main)/boards/BoardEntityBadge.tsx | 8 +- src/app/(main)/boards/BoardProvider.tsx | 2 +- src/app/(main)/boards/BoardsTable.tsx | 8 +- .../boards/[boardId]/BoardComponentSelect.tsx | 12 +- .../boards/[boardId]/BoardEditColumn.tsx | 18 +- .../boards/[boardId]/BoardShareButton.tsx | 9 +- .../boards/[boardId]/BoardShareDialog.tsx | 8 +- .../boards/[boardId]/BoardSharesTable.tsx | 2 +- .../boards/[boardId]/BoardViewHeader.tsx | 2 +- .../boards/[boardId]/edit/BoardEditPage.tsx | 13 +- .../(main)/boards/boardComponentRegistry.tsx | 2 +- .../console/[websiteId]/TestConsolePage.tsx | 2 +- src/app/(main)/links/LinkEditButton.tsx | 3 +- src/app/(main)/links/LinksTable.tsx | 6 +- .../(main)/links/[linkId]/LinkShareForm.tsx | 6 +- .../links/[linkId]/edit/LinkEditPage.tsx | 6 +- src/app/(main)/pixels/PixelEditButton.tsx | 3 +- src/app/(main)/pixels/PixelsTable.tsx | 6 +- .../pixels/[pixelId]/PixelShareForm.tsx | 6 +- .../pixels/[pixelId]/edit/PixelEditPage.tsx | 6 +- src/app/(main)/settings/SettingsNav.tsx | 2 +- .../settings/preferences/ThemeSetting.tsx | 4 +- src/app/(main)/teams/TeamsDataTable.tsx | 2 +- .../teams/[teamId]/TeamWebsitesTable.tsx | 2 +- src/app/(main)/websites/WebsitesDataTable.tsx | 2 +- src/app/(main)/websites/WebsitesTable.tsx | 4 +- .../(reports)/breakdown/BreakdownPage.tsx | 2 +- .../[websiteId]/(reports)/funnels/Funnel.tsx | 2 +- .../(reports)/funnels/FunnelEditForm.tsx | 4 +- .../[websiteId]/(reports)/goals/Goal.tsx | 9 +- .../(reports)/heatmaps/Heatmap.tsx | 171 ++++++++++-------- .../(reports)/heatmaps/HeatmapsPage.tsx | 12 +- .../(reports)/retention/Retention.tsx | 2 +- .../[websiteId]/(reports)/revenue/Revenue.tsx | 13 +- .../(reports)/revenue/RevenueMetricsBar.tsx | 2 +- .../(reports)/revenue/RevenueMetricsTable.tsx | 6 +- .../revenue/RevenueSessionsDataTable.tsx | 5 +- .../websites/[websiteId]/WebsiteNav.tsx | 2 +- .../[websiteId]/cohorts/CohortsTable.tsx | 2 +- .../event-data/EventDataPivotTable.tsx | 33 ++-- .../[websiteId]/events/EventsTable.tsx | 2 +- .../[websiteId]/realtime/RealtimeHeader.tsx | 6 +- .../[websiteId]/realtime/RealtimeLog.tsx | 10 +- .../[websiteId]/replays/ReplaysPage.tsx | 4 +- .../[websiteId]/replays/ReplaysTable.tsx | 2 +- .../replays/[replayId]/ReplayPlayer.tsx | 2 +- .../[websiteId]/segments/SegmentsTable.tsx | 2 +- .../session-data/SessionDataPivotTable.tsx | 9 +- .../session-data/SessionPropertyChart.tsx | 4 +- .../[websiteId]/sessions/SessionModal.tsx | 7 +- .../[websiteId]/sessions/SessionProfile.tsx | 6 +- .../sessions/SessionProperties.tsx | 16 +- .../[websiteId]/sessions/SessionsTable.tsx | 8 +- .../[websiteId]/settings/ShareEditForm.tsx | 30 +-- .../settings/WebsiteReplaySettings.tsx | 8 +- .../settings/WebsiteSettingsHeader.tsx | 2 +- .../settings/WebsiteTrackingCode.tsx | 9 +- src/app/api/boards/[boardId]/shares/route.ts | 10 +- src/app/api/dashboard/route.ts | 2 +- src/app/api/links/[linkId]/shares/route.ts | 10 +- src/app/api/pixels/[pixelId]/shares/route.ts | 10 +- src/app/api/realtime/[websiteId]/route.ts | 2 +- src/app/api/record/route.ts | 12 +- .../websites/[websiteId]/recorder/route.ts | 2 +- src/app/layout.tsx | 2 +- src/app/share/ShareProvider.tsx | 6 +- .../[slug]/[[...path]]/ShareBranding.tsx | 2 +- .../share/[slug]/[[...path]]/ShareFooter.tsx | 2 +- src/app/share/[slug]/[[...path]]/ShareNav.tsx | 16 +- .../share/[slug]/[[...path]]/SharePage.tsx | 8 +- src/components/charts/BarChart.tsx | 4 +- .../charts/DistributionBarChart.tsx | 53 +++--- src/components/common/Badge.module.css | 12 +- src/components/common/CopyButton.tsx | 8 +- src/components/common/DataGrid.tsx | 2 +- src/components/common/ExternalLink.tsx | 2 +- src/components/common/FilterLink.tsx | 2 +- src/components/common/LinkButton.tsx | 2 +- src/components/common/NavMenu.tsx | 2 +- src/components/common/Pager.tsx | 8 +- src/components/common/SortableLabel.tsx | 10 +- src/components/hooks/index.ts | 10 +- .../hooks/queries/useLinkSharesQuery.ts | 5 +- .../hooks/queries/usePixelSharesQuery.ts | 5 +- .../queries/usePropertyArraySeriesQuery.ts | 12 +- .../queries/usePropertyNumericSeriesQuery.ts | 13 +- .../hooks/queries/usePropertySeriesQuery.ts | 12 +- .../hooks/queries/usePropertyValuesQuery.ts | 13 +- .../hooks/queries/useRevenueStatsQuery.ts | 5 +- .../queries/useSessionDataPropertiesQuery.ts | 3 +- src/components/hooks/useFilterParameters.ts | 6 +- src/components/hooks/useSubscription.ts | 2 +- src/components/input/DialogButton.tsx | 11 +- src/components/input/FilterBar.tsx | 6 +- src/components/input/FilterEditForm.tsx | 7 +- src/components/input/LookupField.tsx | 4 +- src/components/input/ThemeModeSelector.tsx | 2 +- src/components/metrics/ActiveUsers.tsx | 2 +- .../metrics/PerformanceCard.module.css | 1 - .../property-data/PropertyChart.tsx | 4 +- .../property-data/PropertyDateChart.tsx | 96 ++++++++-- .../property-data/PropertyFilterButton.tsx | 2 +- .../property-data/PropertyFilterEditForm.tsx | 21 ++- .../property-data/PropertyFilterRecord.tsx | 64 +++++-- .../property-data/PropertyNumericChart.tsx | 79 ++++++-- src/components/share/SimpleShareEditForm.tsx | 30 +-- src/components/share/SimpleSharesTable.tsx | 2 +- src/lib/api-url.test.ts | 4 +- src/lib/api-url.ts | 5 +- src/lib/boards.ts | 11 +- src/lib/generate.ts | 11 +- src/lib/heatmap-r2.ts | 6 +- src/lib/params.ts | 67 +++---- src/lib/request.ts | 4 +- src/permissions/link.ts | 6 +- src/permissions/pixel.ts | 6 +- src/queries/prisma/user.ts | 4 +- src/queries/sql/events/getEventData.ts | 16 +- .../sql/heatmap/ensureHeatmapSnapshot.ts | 50 ++--- src/queries/sql/heatmap/getHeatmap.ts | 26 +-- src/queries/sql/index.ts | 6 +- .../pageviews/getPageviewExpandedMetrics.ts | 14 +- .../sql/pageviews/getPageviewMetrics.ts | 7 +- .../sessions/getSessionDataActivityStats.ts | 27 ++- .../sql/sessions/getSessionDataArraySeries.ts | 18 +- .../sql/sessions/getSessionDataDateSeries.ts | 18 +- .../sessions/getSessionDataNumericSeries.ts | 18 +- .../sessions/getSessionDataNumericStats.ts | 18 +- .../sql/sessions/getSessionDataPivot.ts | 6 +- .../sql/sessions/getSessionDataProperties.ts | 6 +- .../sessions/getSessionDataPropertySeries.ts | 18 +- src/store/app.ts | 5 +- 144 files changed, 962 insertions(+), 626 deletions(-) diff --git a/package.json b/package.json index a8a017700..9a71fddd3 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,6 @@ "playwright-core": "^1.60.0", "prisma": "^7.8.0", "prop-types": "^15.8.1", - "pure-rand": "^8.4.0", "react": "^19.2.6", "react-aria-components": "^1.17.0", "react-dom": "^19.2.6", diff --git a/scripts/check-db.js b/scripts/check-db.js index aaa128af5..100cba031 100644 --- a/scripts/check-db.js +++ b/scripts/check-db.js @@ -68,7 +68,11 @@ async function checkDatabaseVersion() { async function applyMigration() { if (!process.env.SKIP_DB_MIGRATION) { const directUrl = process.env.DIRECT_DATABASE_URL || process.env.DATABASE_URL; - console.log(execSync('prisma migrate deploy', { env: { ...process.env, DATABASE_URL: directUrl } }).toString()); + console.log( + execSync('prisma migrate deploy', { + env: { ...process.env, DATABASE_URL: directUrl }, + }).toString(), + ); success('Database is up to date.'); } diff --git a/scripts/download-country-names.js b/scripts/download-country-names.js index 474869d44..71cf58691 100644 --- a/scripts/download-country-names.js +++ b/scripts/download-country-names.js @@ -1,9 +1,9 @@ /* eslint-disable no-console */ +import fs from 'node:fs'; import https from 'node:https'; import path from 'node:path'; import chalk from 'chalk'; -import fs from 'node:fs'; const src = path.resolve(process.cwd(), 'public/intl/messages'); const dest = path.resolve(process.cwd(), 'public/intl/country'); diff --git a/scripts/download-language-names.js b/scripts/download-language-names.js index 17d7aa72e..b10285674 100644 --- a/scripts/download-language-names.js +++ b/scripts/download-language-names.js @@ -1,9 +1,9 @@ /* eslint-disable no-console */ +import fs from 'node:fs'; import https from 'node:https'; import path from 'node:path'; import chalk from 'chalk'; -import fs from 'node:fs'; const src = path.resolve(process.cwd(), 'public/intl/messages'); const dest = path.resolve(process.cwd(), 'public/intl/language'); diff --git a/src/app/(collect)/p/[slug]/route.ts b/src/app/(collect)/p/[slug]/route.ts index 36ba5a892..d7fc24167 100644 --- a/src/app/(collect)/p/[slug]/route.ts +++ b/src/app/(collect)/p/[slug]/route.ts @@ -49,7 +49,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ slug payload: { pixel: pixel.id, url: request.url, - referrer: request.headers.get("referer") || undefined, + referrer: request.headers.get('referer') || undefined, }, }; diff --git a/src/app/(collect)/q/[slug]/route.ts b/src/app/(collect)/q/[slug]/route.ts index f585fc02e..5d4229e90 100644 --- a/src/app/(collect)/q/[slug]/route.ts +++ b/src/app/(collect)/q/[slug]/route.ts @@ -47,7 +47,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ slug payload: { link: link.id, url: request.url, - referrer: request.headers.get("referer") || undefined, + referrer: request.headers.get('referer') || undefined, }, }; diff --git a/src/app/(main)/MobileNav.tsx b/src/app/(main)/MobileNav.tsx index ff54eb75f..1ef458638 100644 --- a/src/app/(main)/MobileNav.tsx +++ b/src/app/(main)/MobileNav.tsx @@ -1,7 +1,7 @@ import { Column, Grid, Row, Text } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav'; import { IconLabel } from '@/components/common/IconLabel'; +import Link from '@/components/common/Link'; import { useMessages, useNavigation } from '@/components/hooks'; import { Globe, Grid2x2, LayoutDashboard, LinkIcon } from '@/components/icons'; import { MobileMenuButton } from '@/components/input/MobileMenuButton'; diff --git a/src/app/(main)/SideNav.tsx b/src/app/(main)/SideNav.tsx index 2f2c27ec4..c44011654 100644 --- a/src/app/(main)/SideNav.tsx +++ b/src/app/(main)/SideNav.tsx @@ -1,18 +1,3 @@ -import { AdminNav } from '@/app/(main)/admin/AdminNav'; -import { SettingsNav } from '@/app/(main)/settings/SettingsNav'; -import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav'; -import { IconLabel } from '@/components/common/IconLabel'; -import { useGlobalState, useMessages, useNavigation } from '@/components/hooks'; -import { - Globe, - Grid2x2, - LayoutDashboard, - LinkIcon, - PanelLeft, - PanelsLeftBottom, -} from '@/components/icons'; -import { UserButton } from '@/components/input/UserButton'; -import { Logo } from '@/components/svg'; import { Button, type ButtonProps, @@ -24,7 +9,22 @@ import { Tooltip, TooltipTrigger, } from '@umami/react-zen'; +import { AdminNav } from '@/app/(main)/admin/AdminNav'; +import { SettingsNav } from '@/app/(main)/settings/SettingsNav'; +import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav'; +import { IconLabel } from '@/components/common/IconLabel'; import Link from '@/components/common/Link'; +import { useGlobalState, useMessages, useNavigation } from '@/components/hooks'; +import { + Globe, + Grid2x2, + LayoutDashboard, + LinkIcon, + PanelLeft, + PanelsLeftBottom, +} from '@/components/icons'; +import { UserButton } from '@/components/input/UserButton'; +import { Logo } from '@/components/svg'; export function SideNav(props: any) { const { t, labels } = useMessages(); diff --git a/src/app/(main)/admin/AdminNav.tsx b/src/app/(main)/admin/AdminNav.tsx index 7df3ff546..f8d8dc51b 100644 --- a/src/app/(main)/admin/AdminNav.tsx +++ b/src/app/(main)/admin/AdminNav.tsx @@ -1,9 +1,9 @@ +import { Column, Focusable, Row, Tooltip, TooltipTrigger } from '@umami/react-zen'; import { IconLabel } from '@/components/common/IconLabel'; +import Link from '@/components/common/Link'; import { NavMenu } from '@/components/common/NavMenu'; import { useMessages, useNavigation } from '@/components/hooks'; import { ArrowLeft, Globe, User, Users } from '@/components/icons'; -import { Column, Focusable, Row, Tooltip, TooltipTrigger } from '@umami/react-zen'; -import Link from '@/components/common/Link'; export function AdminNav({ onItemClick }: { onItemClick?: () => void }) { const { t, labels } = useMessages(); diff --git a/src/app/(main)/admin/teams/AdminTeamsTable.tsx b/src/app/(main)/admin/teams/AdminTeamsTable.tsx index 1f7cca5be..24002f2d9 100644 --- a/src/app/(main)/admin/teams/AdminTeamsTable.tsx +++ b/src/app/(main)/admin/teams/AdminTeamsTable.tsx @@ -1,7 +1,7 @@ import { DataColumn, DataTable, Dialog, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { useState } from 'react'; import { DateDistance } from '@/components/common/DateDistance'; +import Link from '@/components/common/Link'; import { SortableLabel } from '@/components/common/SortableLabel'; import { useMessages } from '@/components/hooks'; import { Edit, Trash } from '@/components/icons'; @@ -48,7 +48,9 @@ export function AdminTeamsTable({ } + label={ + + } width="160px" > {(row: any) => } diff --git a/src/app/(main)/admin/users/UsersTable.tsx b/src/app/(main)/admin/users/UsersTable.tsx index 299cf3da3..55d46b7c9 100644 --- a/src/app/(main)/admin/users/UsersTable.tsx +++ b/src/app/(main)/admin/users/UsersTable.tsx @@ -1,7 +1,7 @@ import { DataColumn, DataTable, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { useState } from 'react'; import { DateDistance } from '@/components/common/DateDistance'; +import Link from '@/components/common/Link'; import { SortableLabel } from '@/components/common/SortableLabel'; import { useMessages } from '@/components/hooks'; import { Edit, Trash } from '@/components/icons'; @@ -40,7 +40,9 @@ export function UsersTable({ } + label={ + + } > {(row: any) => } diff --git a/src/app/(main)/admin/websites/AdminWebsitesTable.tsx b/src/app/(main)/admin/websites/AdminWebsitesTable.tsx index edf048120..12698e730 100644 --- a/src/app/(main)/admin/websites/AdminWebsitesTable.tsx +++ b/src/app/(main)/admin/websites/AdminWebsitesTable.tsx @@ -1,8 +1,8 @@ import { DataColumn, DataTable, Dialog, Icon, MenuItem, Modal, Row, Text } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { useState } from 'react'; import { WebsiteDeleteForm } from '@/app/(main)/websites/[websiteId]/settings/WebsiteDeleteForm'; import { DateDistance } from '@/components/common/DateDistance'; +import Link from '@/components/common/Link'; import { SortableLabel } from '@/components/common/SortableLabel'; import { useMessages } from '@/components/hooks'; import { Edit, Trash, Users } from '@/components/icons'; @@ -48,7 +48,9 @@ export function AdminWebsitesTable({ data = [], ...props }: { data: any[] }) { } + label={ + + } width="180px" > {(row: any) => } diff --git a/src/app/(main)/boards/BoardEntityBadge.tsx b/src/app/(main)/boards/BoardEntityBadge.tsx index 31d7081ab..70d4784f8 100644 --- a/src/app/(main)/boards/BoardEntityBadge.tsx +++ b/src/app/(main)/boards/BoardEntityBadge.tsx @@ -15,13 +15,7 @@ export function BoardEntityBadge({ return ( - {type === 'pixel' ? ( - - ) : type === 'link' ? ( - - ) : ( - - )} + {type === 'pixel' ? : type === 'link' ? : } {name} diff --git a/src/app/(main)/boards/BoardProvider.tsx b/src/app/(main)/boards/BoardProvider.tsx index dc5168424..4ec649520 100644 --- a/src/app/(main)/boards/BoardProvider.tsx +++ b/src/app/(main)/boards/BoardProvider.tsx @@ -3,8 +3,8 @@ import { Loading, useToast } from '@umami/react-zen'; import { createContext, type ReactNode, useCallback, useEffect, useRef, useState } from 'react'; import { v4 as uuid } from 'uuid'; import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks'; -import { BOARD_TYPES, getBoardType } from '@/lib/boards'; import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery'; +import { BOARD_TYPES, getBoardType } from '@/lib/boards'; import type { Board, BoardParameters } from '@/lib/types'; import { getComponentDefinition } from './boardComponentRegistry'; diff --git a/src/app/(main)/boards/BoardsTable.tsx b/src/app/(main)/boards/BoardsTable.tsx index 0465012cc..346e92497 100644 --- a/src/app/(main)/boards/BoardsTable.tsx +++ b/src/app/(main)/boards/BoardsTable.tsx @@ -1,6 +1,6 @@ import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { DateDistance } from '@/components/common/DateDistance'; +import Link from '@/components/common/Link'; import { SortableLabel } from '@/components/common/SortableLabel'; import { useMessages, useNavigation } from '@/components/hooks'; import { BoardDeleteButton } from './BoardDeleteButton'; @@ -23,11 +23,13 @@ export function BoardsTable(props: DataTableProps) { label={} /> }> - {({ type }: any) => type ? type.charAt(0).toUpperCase() + type.slice(1) : ''} + {({ type }: any) => (type ? type.charAt(0).toUpperCase() + type.slice(1) : '')} } + label={ + + } width="200px" > {(row: any) => } diff --git a/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx b/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx index 3a03ffea0..0e01eee5a 100644 --- a/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx +++ b/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx @@ -13,7 +13,6 @@ import { useMessages } from '@/components/hooks'; import { LinkSelect } from '@/components/input/LinkSelect'; import { PixelSelect } from '@/components/input/PixelSelect'; import { WebsiteSelect } from '@/components/input/WebsiteSelect'; -import type { BoardComponentConfig } from '@/lib/types'; import { BOARD_ENTITY_TYPES, type BoardEntityType, @@ -22,6 +21,7 @@ import { isBoardComponentSupported, isOpenBoardType, } from '@/lib/boards'; +import type { BoardComponentConfig } from '@/lib/types'; import { type ComponentDefinition, type ConfigField, @@ -53,9 +53,7 @@ export function BoardComponentSelect({ const [selectedEntityType, setSelectedEntityType] = useState( initialEntity.entityType || boardEntityType || BOARD_ENTITY_TYPES.website, ); - const [selectedEntityId, setSelectedEntityId] = useState( - initialEntity.entityId || boardEntityId, - ); + const [selectedEntityId, setSelectedEntityId] = useState(initialEntity.entityId || boardEntityId); const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); @@ -370,7 +368,11 @@ export function BoardComponentSelect({ Preview {hasSelectedEntity && previewConfig && (!needsWebsite || resolvedEntityId) ? ( - + ) : ( diff --git a/src/app/(main)/boards/[boardId]/BoardEditColumn.tsx b/src/app/(main)/boards/[boardId]/BoardEditColumn.tsx index 0a89ea25c..cdc053a43 100644 --- a/src/app/(main)/boards/[boardId]/BoardEditColumn.tsx +++ b/src/app/(main)/boards/[boardId]/BoardEditColumn.tsx @@ -1,8 +1,3 @@ -import { Panel } from '@/components/common/Panel'; -import { useBoard, useMessages, useNavigation } from '@/components/hooks'; -import { Pencil, Plus, X } from '@/components/icons'; -import { getBoardEntity, getBoardType, getResolvedComponentEntity } from '@/lib/boards'; -import type { BoardComponentConfig } from '@/lib/types'; import { Box, Button, @@ -15,6 +10,11 @@ import { TooltipTrigger, } from '@umami/react-zen'; import { useMemo, useState } from 'react'; +import { Panel } from '@/components/common/Panel'; +import { useBoard, useMessages, useNavigation } from '@/components/hooks'; +import { Pencil, Plus, X } from '@/components/icons'; +import { getBoardEntity, getBoardType, getResolvedComponentEntity } from '@/lib/boards'; +import type { BoardComponentConfig } from '@/lib/types'; import { getComponentDefinition } from '../boardComponentRegistry'; import { BoardComponentRenderer } from './BoardComponentRenderer'; import { BoardComponentSelect } from './BoardComponentSelect'; @@ -48,7 +48,9 @@ export function BoardEditColumn({ return null; } - return ; + return ( + + ); }, [component, definition?.requiresWebsite, entityId, entityType]); const handleSelect = (config: BoardComponentConfig) => { @@ -95,9 +97,7 @@ export function BoardEditColumn({ > {t(hasComponent ? labels.edit : labels.selectComponent)} diff --git a/src/app/(main)/boards/[boardId]/BoardShareButton.tsx b/src/app/(main)/boards/[boardId]/BoardShareButton.tsx index 77d6cc609..86c8d05c7 100644 --- a/src/app/(main)/boards/[boardId]/BoardShareButton.tsx +++ b/src/app/(main)/boards/[boardId]/BoardShareButton.tsx @@ -1,5 +1,5 @@ -import { Share } from '@/components/icons'; import { useMessages } from '@/components/hooks'; +import { Share } from '@/components/icons'; import { DialogButton } from '@/components/input/DialogButton'; import { BoardShareDialog } from './BoardShareDialog'; @@ -7,12 +7,7 @@ export function BoardShareButton({ boardId }: { boardId: string }) { const { t, labels } = useMessages(); return ( - } - label={t(labels.share)} - title={null} - width="900px" - > + } label={t(labels.share)} title={null} width="900px"> ); diff --git a/src/app/(main)/boards/[boardId]/BoardShareDialog.tsx b/src/app/(main)/boards/[boardId]/BoardShareDialog.tsx index ba7a84774..14989a0b4 100644 --- a/src/app/(main)/boards/[boardId]/BoardShareDialog.tsx +++ b/src/app/(main)/boards/[boardId]/BoardShareDialog.tsx @@ -1,9 +1,9 @@ import { Button, Column, Heading, Row, Text } from '@umami/react-zen'; import { useState } from 'react'; -import { Plus } from '@/components/icons'; -import { LoadingPanel } from '@/components/common/LoadingPanel'; import { IconLabel } from '@/components/common/IconLabel'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; import { useBoardSharesQuery, useMessages } from '@/components/hooks'; +import { Plus } from '@/components/icons'; import { BoardShareCreateForm } from './BoardShareCreateForm'; import { BoardSharesTable } from './BoardSharesTable'; @@ -49,9 +49,7 @@ function BoardShareDialogContent({ onCancel={() => setIsCreating(false)} /> )} - {hasShares && ( - {t(messages.shareUrl)} - )} + {hasShares && {t(messages.shareUrl)}} {!showCreateForm && (hasShares ? ( diff --git a/src/app/(main)/boards/[boardId]/BoardSharesTable.tsx b/src/app/(main)/boards/[boardId]/BoardSharesTable.tsx index c3b30c297..2fb307a20 100644 --- a/src/app/(main)/boards/[boardId]/BoardSharesTable.tsx +++ b/src/app/(main)/boards/[boardId]/BoardSharesTable.tsx @@ -1,8 +1,8 @@ +import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; import { ShareDeleteButton } from '@/app/(main)/websites/[websiteId]/settings/ShareDeleteButton'; import { CopyButton } from '@/components/common/CopyButton'; import { ExternalLink } from '@/components/common/ExternalLink'; import { useConfig, useMessages, useMobile } from '@/components/hooks'; -import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; import { SimpleShareEditButton } from '@/components/share/SimpleShareEditButton'; export function BoardSharesTable(props: DataTableProps) { diff --git a/src/app/(main)/boards/[boardId]/BoardViewHeader.tsx b/src/app/(main)/boards/[boardId]/BoardViewHeader.tsx index 8533e4534..7c07b7d64 100644 --- a/src/app/(main)/boards/[boardId]/BoardViewHeader.tsx +++ b/src/app/(main)/boards/[boardId]/BoardViewHeader.tsx @@ -3,8 +3,8 @@ import { IconLabel } from '@/components/common/IconLabel'; import { LinkButton } from '@/components/common/LinkButton'; import { PageHeader } from '@/components/common/PageHeader'; import { useBoard, useMessages, useNavigation } from '@/components/hooks'; -import { getBoardEntity } from '@/lib/boards'; import { Edit, LayoutDashboard } from '@/components/icons'; +import { getBoardEntity } from '@/lib/boards'; import { BoardEntityBadge } from '../BoardEntityBadge'; import { useBoardEntityBadgeProps } from '../useBoardEntityBadgeProps'; diff --git a/src/app/(main)/boards/[boardId]/edit/BoardEditPage.tsx b/src/app/(main)/boards/[boardId]/edit/BoardEditPage.tsx index 69c813822..083390be3 100644 --- a/src/app/(main)/boards/[boardId]/edit/BoardEditPage.tsx +++ b/src/app/(main)/boards/[boardId]/edit/BoardEditPage.tsx @@ -1,12 +1,12 @@ 'use client'; import { Column } from '@umami/react-zen'; -import Link from '@/components/common/Link'; -import { BoardEditForm } from '@/app/(main)/boards/BoardEditForm'; import { BoardShareDialog } from '@/app/(main)/boards/[boardId]/BoardShareDialog'; +import { BoardEditForm } from '@/app/(main)/boards/BoardEditForm'; import { IconLabel } from '@/components/common/IconLabel'; -import { Panel } from '@/components/common/Panel'; +import Link from '@/components/common/Link'; import { PageBody } from '@/components/common/PageBody'; import { PageHeader } from '@/components/common/PageHeader'; +import { Panel } from '@/components/common/Panel'; import { useBoardQuery, useMessages, useNavigation } from '@/components/hooks'; import { ArrowLeft, LayoutDashboard } from '@/components/icons'; @@ -17,12 +17,7 @@ export function BoardEditPage({ boardId }: { boardId: string }) { return ( - + <> diff --git a/src/app/(main)/boards/boardComponentRegistry.tsx b/src/app/(main)/boards/boardComponentRegistry.tsx index 7d9dc9cd5..3607b733a 100644 --- a/src/app/(main)/boards/boardComponentRegistry.tsx +++ b/src/app/(main)/boards/boardComponentRegistry.tsx @@ -1,3 +1,4 @@ +import type { ComponentType } from 'react'; import { TextBlock } from '@/app/(main)/boards/TextBlock'; import { LinkMetricsBar } from '@/app/(main)/links/[linkId]/LinkMetricsBar'; import { PixelMetricsBar } from '@/app/(main)/pixels/[pixelId]/PixelMetricsBar'; @@ -16,7 +17,6 @@ import { EventsChart } from '@/components/metrics/EventsChart'; import { MetricsTable } from '@/components/metrics/MetricsTable'; import { WeeklyTraffic } from '@/components/metrics/WeeklyTraffic'; import { WorldMap } from '@/components/metrics/WorldMap'; -import type { ComponentType } from 'react'; export interface ConfigField { name: string; diff --git a/src/app/(main)/console/[websiteId]/TestConsolePage.tsx b/src/app/(main)/console/[websiteId]/TestConsolePage.tsx index e5dcd345a..575685dec 100644 --- a/src/app/(main)/console/[websiteId]/TestConsolePage.tsx +++ b/src/app/(main)/console/[websiteId]/TestConsolePage.tsx @@ -1,8 +1,8 @@ 'use client'; import { Button, Column, Grid, Heading } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import Script from 'next/script'; import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart'; +import Link from '@/components/common/Link'; import { PageBody } from '@/components/common/PageBody'; import { PageHeader } from '@/components/common/PageHeader'; import { Panel } from '@/components/common/Panel'; diff --git a/src/app/(main)/links/LinkEditButton.tsx b/src/app/(main)/links/LinkEditButton.tsx index 44598a5db..9c5d23330 100644 --- a/src/app/(main)/links/LinkEditButton.tsx +++ b/src/app/(main)/links/LinkEditButton.tsx @@ -1,7 +1,6 @@ import { Icon } from '@umami/react-zen'; import { LinkButton } from '@/components/common/LinkButton'; -import { useNavigation } from '@/components/hooks'; -import { useMessages } from '@/components/hooks'; +import { useMessages, useNavigation } from '@/components/hooks'; import { Edit } from '@/components/icons'; export function LinkEditButton({ linkId }: { linkId: string }) { diff --git a/src/app/(main)/links/LinksTable.tsx b/src/app/(main)/links/LinksTable.tsx index 953adf98d..885e737e3 100644 --- a/src/app/(main)/links/LinksTable.tsx +++ b/src/app/(main)/links/LinksTable.tsx @@ -1,7 +1,7 @@ import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { DateDistance } from '@/components/common/DateDistance'; import { ExternalLink } from '@/components/common/ExternalLink'; +import Link from '@/components/common/Link'; import { SortableLabel } from '@/components/common/SortableLabel'; import { useMessages, useNavigation, useSlug } from '@/components/hooks'; import { LinkDeleteButton } from './LinkDeleteButton'; @@ -44,7 +44,9 @@ export function LinksTable({ showActions, ...props }: LinksTableProps) { } + label={ + + } width="200px" > {(row: any) => } diff --git a/src/app/(main)/links/[linkId]/LinkShareForm.tsx b/src/app/(main)/links/[linkId]/LinkShareForm.tsx index 3486a71ea..a486c6fb0 100644 --- a/src/app/(main)/links/[linkId]/LinkShareForm.tsx +++ b/src/app/(main)/links/[linkId]/LinkShareForm.tsx @@ -1,7 +1,7 @@ import { Button, Column, Heading, Row, Text } from '@umami/react-zen'; import { useState } from 'react'; -import { LoadingPanel } from '@/components/common/LoadingPanel'; import { IconLabel } from '@/components/common/IconLabel'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; import { useLinkSharesQuery, useMessages } from '@/components/hooks'; import { Plus } from '@/components/icons'; import { SimpleShareCreateForm } from '@/components/share/SimpleShareCreateForm'; @@ -49,9 +49,7 @@ function LinkShareFormContent({ onCancel={() => setIsCreating(false)} /> )} - {hasShares && ( - {t(messages.shareUrl)} - )} + {hasShares && {t(messages.shareUrl)}} {!showCreateForm && (hasShares ? ( diff --git a/src/app/(main)/links/[linkId]/edit/LinkEditPage.tsx b/src/app/(main)/links/[linkId]/edit/LinkEditPage.tsx index c87bec864..013ef02da 100644 --- a/src/app/(main)/links/[linkId]/edit/LinkEditPage.tsx +++ b/src/app/(main)/links/[linkId]/edit/LinkEditPage.tsx @@ -1,12 +1,12 @@ 'use client'; import { Column } from '@umami/react-zen'; -import Link from '@/components/common/Link'; +import { LinkShareForm } from '@/app/(main)/links/[linkId]/LinkShareForm'; import { LinkEditForm } from '@/app/(main)/links/LinkEditForm'; import { LinkProvider } from '@/app/(main)/links/LinkProvider'; -import { LinkShareForm } from '@/app/(main)/links/[linkId]/LinkShareForm'; -import { Panel } from '@/components/common/Panel'; import { IconLabel } from '@/components/common/IconLabel'; +import Link from '@/components/common/Link'; import { PageHeader } from '@/components/common/PageHeader'; +import { Panel } from '@/components/common/Panel'; import { useLink, useMessages, useNavigation } from '@/components/hooks'; import { ArrowLeft, Link as LinkIcon } from '@/components/icons'; diff --git a/src/app/(main)/pixels/PixelEditButton.tsx b/src/app/(main)/pixels/PixelEditButton.tsx index 8a8f141d6..d96e8ea21 100644 --- a/src/app/(main)/pixels/PixelEditButton.tsx +++ b/src/app/(main)/pixels/PixelEditButton.tsx @@ -1,7 +1,6 @@ import { Icon } from '@umami/react-zen'; import { LinkButton } from '@/components/common/LinkButton'; -import { useNavigation } from '@/components/hooks'; -import { useMessages } from '@/components/hooks'; +import { useMessages, useNavigation } from '@/components/hooks'; import { Edit } from '@/components/icons'; export function PixelEditButton({ pixelId }: { pixelId: string }) { diff --git a/src/app/(main)/pixels/PixelsTable.tsx b/src/app/(main)/pixels/PixelsTable.tsx index 362bffa78..e949603da 100644 --- a/src/app/(main)/pixels/PixelsTable.tsx +++ b/src/app/(main)/pixels/PixelsTable.tsx @@ -1,7 +1,7 @@ import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { DateDistance } from '@/components/common/DateDistance'; import { ExternalLink } from '@/components/common/ExternalLink'; +import Link from '@/components/common/Link'; import { SortableLabel } from '@/components/common/SortableLabel'; import { useMessages, useNavigation, useSlug } from '@/components/hooks'; import { PixelDeleteButton } from './PixelDeleteButton'; @@ -35,7 +35,9 @@ export function PixelsTable({ showActions, ...props }: PixelsTableProps) { } + label={ + + } > {(row: any) => } diff --git a/src/app/(main)/pixels/[pixelId]/PixelShareForm.tsx b/src/app/(main)/pixels/[pixelId]/PixelShareForm.tsx index 4c31bbd74..1044cff7a 100644 --- a/src/app/(main)/pixels/[pixelId]/PixelShareForm.tsx +++ b/src/app/(main)/pixels/[pixelId]/PixelShareForm.tsx @@ -1,7 +1,7 @@ import { Button, Column, Heading, Row, Text } from '@umami/react-zen'; import { useState } from 'react'; -import { LoadingPanel } from '@/components/common/LoadingPanel'; import { IconLabel } from '@/components/common/IconLabel'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; import { useMessages, usePixelSharesQuery } from '@/components/hooks'; import { Plus } from '@/components/icons'; import { SimpleShareCreateForm } from '@/components/share/SimpleShareCreateForm'; @@ -49,9 +49,7 @@ function PixelShareFormContent({ onCancel={() => setIsCreating(false)} /> )} - {hasShares && ( - {t(messages.shareUrl)} - )} + {hasShares && {t(messages.shareUrl)}} {!showCreateForm && (hasShares ? ( diff --git a/src/app/(main)/pixels/[pixelId]/edit/PixelEditPage.tsx b/src/app/(main)/pixels/[pixelId]/edit/PixelEditPage.tsx index d339c756e..04e3ea753 100644 --- a/src/app/(main)/pixels/[pixelId]/edit/PixelEditPage.tsx +++ b/src/app/(main)/pixels/[pixelId]/edit/PixelEditPage.tsx @@ -1,12 +1,12 @@ 'use client'; import { Column } from '@umami/react-zen'; -import Link from '@/components/common/Link'; +import { PixelShareForm } from '@/app/(main)/pixels/[pixelId]/PixelShareForm'; import { PixelEditForm } from '@/app/(main)/pixels/PixelEditForm'; import { PixelProvider } from '@/app/(main)/pixels/PixelProvider'; -import { PixelShareForm } from '@/app/(main)/pixels/[pixelId]/PixelShareForm'; -import { Panel } from '@/components/common/Panel'; import { IconLabel } from '@/components/common/IconLabel'; +import Link from '@/components/common/Link'; import { PageHeader } from '@/components/common/PageHeader'; +import { Panel } from '@/components/common/Panel'; import { useMessages, useNavigation, usePixel } from '@/components/hooks'; import { ArrowLeft, Grid2x2 } from '@/components/icons'; diff --git a/src/app/(main)/settings/SettingsNav.tsx b/src/app/(main)/settings/SettingsNav.tsx index 8c97b9d6c..0f8139245 100644 --- a/src/app/(main)/settings/SettingsNav.tsx +++ b/src/app/(main)/settings/SettingsNav.tsx @@ -1,6 +1,6 @@ import { Column, Focusable, Row, Text, Tooltip, TooltipTrigger } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { IconLabel } from '@/components/common/IconLabel'; +import Link from '@/components/common/Link'; import { useMessages, useNavigation } from '@/components/hooks'; import { ArrowLeft, Settings2, UserCircle, Users } from '@/components/icons'; diff --git a/src/app/(main)/settings/preferences/ThemeSetting.tsx b/src/app/(main)/settings/preferences/ThemeSetting.tsx index 091a78e2e..b9938fa92 100644 --- a/src/app/(main)/settings/preferences/ThemeSetting.tsx +++ b/src/app/(main)/settings/preferences/ThemeSetting.tsx @@ -4,5 +4,7 @@ import { ThemeModeSelector } from '@/components/input/ThemeModeSelector'; export function ThemeSetting() { const { theme, setTheme } = useTheme(); - return setTheme(value as 'light' | 'dark')} />; + return ( + setTheme(value as 'light' | 'dark')} /> + ); } diff --git a/src/app/(main)/teams/TeamsDataTable.tsx b/src/app/(main)/teams/TeamsDataTable.tsx index 6decff1be..a2dbce597 100644 --- a/src/app/(main)/teams/TeamsDataTable.tsx +++ b/src/app/(main)/teams/TeamsDataTable.tsx @@ -1,5 +1,5 @@ -import Link from '@/components/common/Link'; import { DataGrid } from '@/components/common/DataGrid'; +import Link from '@/components/common/Link'; import { useLoginQuery, useNavigation, useUserTeamsQuery } from '@/components/hooks'; import { TeamsTable } from './TeamsTable'; diff --git a/src/app/(main)/teams/[teamId]/TeamWebsitesTable.tsx b/src/app/(main)/teams/[teamId]/TeamWebsitesTable.tsx index e57a10775..b06840d1e 100644 --- a/src/app/(main)/teams/[teamId]/TeamWebsitesTable.tsx +++ b/src/app/(main)/teams/[teamId]/TeamWebsitesTable.tsx @@ -1,7 +1,7 @@ import { DataColumn, DataTable, Row } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { TeamMemberEditButton } from '@/app/(main)/teams/[teamId]/TeamMemberEditButton'; import { TeamMemberRemoveButton } from '@/app/(main)/teams/[teamId]/TeamMemberRemoveButton'; +import Link from '@/components/common/Link'; import { SortableLabel } from '@/components/common/SortableLabel'; import { useMessages } from '@/components/hooks'; import { ROLES } from '@/lib/constants'; diff --git a/src/app/(main)/websites/WebsitesDataTable.tsx b/src/app/(main)/websites/WebsitesDataTable.tsx index 552784871..28da0e41c 100644 --- a/src/app/(main)/websites/WebsitesDataTable.tsx +++ b/src/app/(main)/websites/WebsitesDataTable.tsx @@ -1,6 +1,6 @@ import { Icon, Row } from '@umami/react-zen'; -import Link from '@/components/common/Link'; import { DataGrid } from '@/components/common/DataGrid'; +import Link from '@/components/common/Link'; import { useLoginQuery, useNavigation, useUserWebsitesQuery } from '@/components/hooks'; import { Favicon } from '@/index'; import { WebsitesTable } from './WebsitesTable'; diff --git a/src/app/(main)/websites/WebsitesTable.tsx b/src/app/(main)/websites/WebsitesTable.tsx index e1ed4a7d1..5034db68c 100644 --- a/src/app/(main)/websites/WebsitesTable.tsx +++ b/src/app/(main)/websites/WebsitesTable.tsx @@ -25,7 +25,9 @@ export function WebsitesTable({ showActions, renderLink, ...props }: WebsitesTab } /> } + label={ + + } width="200px" > {(row: any) => } diff --git a/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx index 1c3ad7c6d..05b914cea 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx @@ -6,8 +6,8 @@ import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteContro import { Panel } from '@/components/common/Panel'; import { useDateRange, useMessages, useResultQuery } from '@/components/hooks'; import { ListCheck } from '@/components/icons'; -import { DownloadButton } from '@/components/input/DownloadButton'; import { DialogButton } from '@/components/input/DialogButton'; +import { DownloadButton } from '@/components/input/DownloadButton'; import { Breakdown } from './Breakdown'; export function BreakdownPage({ websiteId }: { websiteId: string }) { diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx index 4d599f70d..2525195fd 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx @@ -1,3 +1,4 @@ +import { Box, Column, Grid, Icon, ProgressBar, Row, Text } from '@umami/react-zen'; import { LoadingPanel } from '@/components/common/LoadingPanel'; import { useMessages, useNavigation, useOperatorLabels, useResultQuery } from '@/components/hooks'; import { File, User } from '@/components/icons'; @@ -6,7 +7,6 @@ import { ChangeLabel } from '@/components/metrics/ChangeLabel'; import { Lightning } from '@/components/svg'; import { formatLongNumber } from '@/lib/format'; import type { FunnelResult } from '@/queries/sql/reports/getFunnel'; -import { Box, Column, Grid, Icon, ProgressBar, Row, Text } from '@umami/react-zen'; import { FunnelEditForm } from './FunnelEditForm'; interface FunnelProps { diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx index f8baa5c9e..99cc52bf5 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx @@ -94,9 +94,7 @@ function StepRow({ - - {valueField} - + {valueField} - - {dialog} - + {dialog} ); } diff --git a/src/components/input/FilterBar.tsx b/src/components/input/FilterBar.tsx index d8c121222..4b3c97eb7 100644 --- a/src/components/input/FilterBar.tsx +++ b/src/components/input/FilterBar.tsx @@ -163,7 +163,11 @@ const FilterItem = ({ name, label, operator, value, onRemove }) => { theme="dark" > - + {label} diff --git a/src/components/input/FilterEditForm.tsx b/src/components/input/FilterEditForm.tsx index 81c198f97..247a698ca 100644 --- a/src/components/input/FilterEditForm.tsx +++ b/src/components/input/FilterEditForm.tsx @@ -115,7 +115,12 @@ export function FilterEditForm({ websiteId, onChange, onClose }: FilterEditFormP - + diff --git a/src/components/input/LookupField.tsx b/src/components/input/LookupField.tsx index daa95aa0c..ba17f18f4 100644 --- a/src/components/input/LookupField.tsx +++ b/src/components/input/LookupField.tsx @@ -1,8 +1,8 @@ -import { Empty } from '@/components/common/Empty'; -import { useMessages, useWebsiteValuesQuery } from '@/components/hooks'; import { ComboBox, type ComboBoxProps, ListItem, Loading, useDebounce } from '@umami/react-zen'; import { endOfDay, subMonths } from 'date-fns'; import { type SetStateAction, useMemo, useState } from 'react'; +import { Empty } from '@/components/common/Empty'; +import { useMessages, useWebsiteValuesQuery } from '@/components/hooks'; export interface LookupFieldProps extends Omit { websiteId: string; diff --git a/src/components/input/ThemeModeSelector.tsx b/src/components/input/ThemeModeSelector.tsx index ad4d6a920..b90910672 100644 --- a/src/components/input/ThemeModeSelector.tsx +++ b/src/components/input/ThemeModeSelector.tsx @@ -1,5 +1,5 @@ -import type { ReactNode } from 'react'; import { Button, Icon, Row } from '@umami/react-zen'; +import type { ReactNode } from 'react'; import { Monitor, Moon, Sun } from '@/components/icons'; export type ThemeMode = 'light' | 'dark' | 'system'; diff --git a/src/components/metrics/ActiveUsers.tsx b/src/components/metrics/ActiveUsers.tsx index 8f0a68c2a..d08aeaeae 100644 --- a/src/components/metrics/ActiveUsers.tsx +++ b/src/components/metrics/ActiveUsers.tsx @@ -42,4 +42,4 @@ export function ActiveUsers({ } return {content}; -} \ No newline at end of file +} diff --git a/src/components/metrics/PerformanceCard.module.css b/src/components/metrics/PerformanceCard.module.css index 9e0d1f296..bf8399e64 100644 --- a/src/components/metrics/PerformanceCard.module.css +++ b/src/components/metrics/PerformanceCard.module.css @@ -9,4 +9,3 @@ .card.selected { box-shadow: 0 0 0 1px var(--text-primary); } - diff --git a/src/components/property-data/PropertyChart.tsx b/src/components/property-data/PropertyChart.tsx index 0700ff1a7..886bd4775 100644 --- a/src/components/property-data/PropertyChart.tsx +++ b/src/components/property-data/PropertyChart.tsx @@ -37,7 +37,9 @@ export function PropertyChart({ }) { const { t, labels } = useMessages(); const { timezone } = useTimezone(); - const { dateRange: { startDate, endDate, unit } } = useDateRange({ timezone }); + const { + dateRange: { startDate, endDate, unit }, + } = useDateRange({ timezone }); const { locale, dateLocale } = useLocale(); const propertySeriesQuery = usePropertySeriesQuery( source, diff --git a/src/components/property-data/PropertyDateChart.tsx b/src/components/property-data/PropertyDateChart.tsx index 4eb83d6ea..6d2cc25f2 100644 --- a/src/components/property-data/PropertyDateChart.tsx +++ b/src/components/property-data/PropertyDateChart.tsx @@ -5,18 +5,23 @@ import { format, formatDistance, isValid, + type Locale, startOfDay, startOfMonth, startOfWeek, startOfYear, - type Locale, } from 'date-fns'; import { toZonedTime } from 'date-fns-tz'; import { type ReactNode, useCallback, useMemo } from 'react'; import { BarChart } from '@/components/charts/BarChart'; import { PieChart } from '@/components/charts/PieChart'; import { LoadingPanel } from '@/components/common/LoadingPanel'; -import { useLocale, useMessages, usePropertyDateSeriesQuery, useTimezone } from '@/components/hooks'; +import { + useLocale, + useMessages, + usePropertyDateSeriesQuery, + useTimezone, +} from '@/components/hooks'; import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import { ListTable } from '@/components/metrics/ListTable'; import { MetricsBar } from '@/components/metrics/MetricsBar'; @@ -30,7 +35,11 @@ type DateChartUnit = 'day' | 'week' | 'month' | 'year'; type ParsedDateRow = EventDataDateSeriesPoint & { date: Date }; function parseDateValue(value: string) { - const normalized = value?.trim().replace(' ', 'T').replace(/Z$/, '').replace(/\.\d+$/, ''); + const normalized = value + ?.trim() + .replace(' ', 'T') + .replace(/Z$/, '') + .replace(/\.\d+$/, ''); const [datePart = '', timePart = '00:00:00'] = normalized.split('T'); const [year = 0, month = 1, day = 1] = datePart.split('-').map(Number); const [hour = 0, minute = 0, second = 0] = timePart.split(':').map(Number); @@ -52,9 +61,17 @@ function InsightCard({ label, value, hint }: { label: string; value: string; hin height="100%" style={{ minWidth: 0 }} > - {label} - {value} - {hint && {hint}} + + {label} + + + {value} + + {hint && ( + + {hint} + + )} ); } @@ -98,7 +115,13 @@ export function PropertyDateChart({ const { locale, dateLocale } = useLocale(); const { timezone } = useTimezone(); const { colors } = useMemo(() => getThemeColors(theme), [theme]); - const query = usePropertyDateSeriesQuery(source, websiteId, propertyName, propertyFilters, eventName); + const query = usePropertyDateSeriesQuery( + source, + websiteId, + propertyName, + propertyFilters, + eventName, + ); const rows = useMemo(() => query.data ?? [], [query.data]); const total = useMemo(() => rows.reduce((sum, { y }) => sum + y, 0), [rows]); @@ -119,7 +142,8 @@ export function PropertyDateChart({ const minPropertyDate = exactDateRows[0]?.date ?? null; const maxPropertyDate = exactDateRows[exactDateRows.length - 1]?.date ?? null; const chartUnit = useMemo( - () => (minPropertyDate && maxPropertyDate ? getChartUnit(minPropertyDate, maxPropertyDate) : 'day'), + () => + minPropertyDate && maxPropertyDate ? getChartUnit(minPropertyDate, maxPropertyDate) : 'day', [maxPropertyDate, minPropertyDate], ); @@ -216,17 +240,28 @@ export function PropertyDateChart({ }, {} as Record, ); - return Object.values(dayTotals).sort((a, b) => b.count - a.count || b.date.getTime() - a.date.getTime())[0]; + return Object.values(dayTotals).sort( + (a, b) => b.count - a.count || b.date.getTime() - a.date.getTime(), + )[0]; }, [exactDateRows, total]); - const topWeekday = useMemo(() => [...weekdayTableData].sort((a, b) => b.count - a.count)[0], [weekdayTableData]); - const weekdayLabels = useMemo(() => weekdayTableData.map(({ label }) => label), [weekdayTableData]); + const topWeekday = useMemo( + () => [...weekdayTableData].sort((a, b) => b.count - a.count)[0], + [weekdayTableData], + ); + const weekdayLabels = useMemo( + () => weekdayTableData.map(({ label }) => label), + [weekdayTableData], + ); const weekdayColorMap = useMemo( () => - weekdayLabels.reduce((obj, label, index) => { - obj[label] = CHART_COLORS[index % CHART_COLORS.length]; - return obj; - }, {} as Record), + weekdayLabels.reduce( + (obj, label, index) => { + obj[label] = CHART_COLORS[index % CHART_COLORS.length]; + return obj; + }, + {} as Record, + ), [weekdayLabels], ); @@ -246,27 +281,48 @@ export function PropertyDateChart({ return ( - + diff --git a/src/components/property-data/PropertyFilterButton.tsx b/src/components/property-data/PropertyFilterButton.tsx index b5beb3de6..c8b671886 100644 --- a/src/components/property-data/PropertyFilterButton.tsx +++ b/src/components/property-data/PropertyFilterButton.tsx @@ -1,9 +1,9 @@ 'use client'; import { useMessages } from '@/components/hooks'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import { ListFilter } from '@/components/icons'; import { DialogButton } from '@/components/input/DialogButton'; import type { PropertyFilter } from '@/lib/types'; -import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import { PropertyFilterEditForm } from './PropertyFilterEditForm'; export function PropertyFilterButton({ diff --git a/src/components/property-data/PropertyFilterEditForm.tsx b/src/components/property-data/PropertyFilterEditForm.tsx index 6f5e9bce6..8b3a996eb 100644 --- a/src/components/property-data/PropertyFilterEditForm.tsx +++ b/src/components/property-data/PropertyFilterEditForm.tsx @@ -1,13 +1,25 @@ 'use client'; -import { Button, Column, Grid, Icon, List, ListItem, Menu, MenuItem, MenuTrigger, Popover, Row } from '@umami/react-zen'; +import { + Button, + Column, + Grid, + Icon, + List, + ListItem, + Menu, + MenuItem, + MenuTrigger, + Popover, + Row, +} from '@umami/react-zen'; import { format } from 'date-fns'; import { useState } from 'react'; import { Empty } from '@/components/common/Empty'; import { useMessages, useMobile, usePropertyFieldsQuery } from '@/components/hooks'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import { Plus } from '@/components/icons'; import { DATA_TYPE, OPERATORS } from '@/lib/constants'; import type { PropertyFilter } from '@/lib/types'; -import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import { PropertyFilterRecord } from './PropertyFilterRecord'; export function PropertyFilterEditForm({ @@ -76,7 +88,10 @@ export function PropertyFilterEditForm({ style={{ maxHeight: 'calc(100vh - 2rem)', overflowY: 'auto' }} > {(fields as any[]).map(field => ( - + {field.propertyName} ))} diff --git a/src/components/property-data/PropertyFilterRecord.tsx b/src/components/property-data/PropertyFilterRecord.tsx index 9a36df9f4..4e2b9c03f 100644 --- a/src/components/property-data/PropertyFilterRecord.tsx +++ b/src/components/property-data/PropertyFilterRecord.tsx @@ -1,16 +1,32 @@ 'use client'; -import { Button, Calendar, Column, ComboBox, Dialog, DialogTrigger, Grid, Icon, Label, ListItem, Loading, Popover, Row, Select, TextField } from '@umami/react-zen'; +import { + Button, + Calendar, + Column, + ComboBox, + Dialog, + DialogTrigger, + Grid, + Icon, + Label, + ListItem, + Loading, + Popover, + Row, + Select, + TextField, +} from '@umami/react-zen'; import { format, parseISO } from 'date-fns'; import { useState } from 'react'; import { DateDisplay } from '@/components/common/DateDisplay'; import { Empty } from '@/components/common/Empty'; import { MultiSelect } from '@/components/common/MultiSelect'; import { useMessages, usePropertyValuesQuery } from '@/components/hooks'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import { X } from '@/components/icons'; import { DATA_TYPE, OPERATORS } from '@/lib/constants'; import { getMaxSelectableDate } from '@/lib/date'; import type { Operator, PropertyFilter } from '@/lib/types'; -import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; const STRING_OPERATORS: Operator[] = [ OPERATORS.equals, @@ -92,19 +108,32 @@ export function PropertyFilterRecord({ const operatorLabel = (op: Operator) => { switch (op) { - case OPERATORS.equals: return t(labels.is); - case OPERATORS.notEquals: return t(labels.isNot); - case OPERATORS.contains: return t(labels.contains); - case OPERATORS.doesNotContain: return t(labels.doesNotContain); - case OPERATORS.regex: return t(labels.regexMatch); - case OPERATORS.notRegex: return t(labels.regexNotMatch); - case OPERATORS.greaterThan: return t(labels.greaterThan); - case OPERATORS.lessThan: return t(labels.lessThan); - case OPERATORS.greaterThanEquals: return t(labels.greaterThanEquals); - case OPERATORS.lessThanEquals: return t(labels.lessThanEquals); - case OPERATORS.before: return t(labels.before); - case OPERATORS.after: return t(labels.after); - default: return op; + case OPERATORS.equals: + return t(labels.is); + case OPERATORS.notEquals: + return t(labels.isNot); + case OPERATORS.contains: + return t(labels.contains); + case OPERATORS.doesNotContain: + return t(labels.doesNotContain); + case OPERATORS.regex: + return t(labels.regexMatch); + case OPERATORS.notRegex: + return t(labels.regexNotMatch); + case OPERATORS.greaterThan: + return t(labels.greaterThan); + case OPERATORS.lessThan: + return t(labels.lessThan); + case OPERATORS.greaterThanEquals: + return t(labels.greaterThanEquals); + case OPERATORS.lessThanEquals: + return t(labels.lessThanEquals); + case OPERATORS.before: + return t(labels.before); + case OPERATORS.after: + return t(labels.after); + default: + return op; } }; @@ -123,7 +152,10 @@ export function PropertyFilterRecord({ - handleOperatorChange(value as Operator)} + > {operators.map(op => ( {operatorLabel(op)} diff --git a/src/components/property-data/PropertyNumericChart.tsx b/src/components/property-data/PropertyNumericChart.tsx index aad0149a7..9b177ddd6 100644 --- a/src/components/property-data/PropertyNumericChart.tsx +++ b/src/components/property-data/PropertyNumericChart.tsx @@ -36,16 +36,44 @@ export function PropertyNumericChart({ const { t, labels } = useMessages(); const { theme } = useTheme(); const { timezone } = useTimezone(); - const { dateRange: { startDate, endDate, unit } } = useDateRange({ timezone }); + const { + dateRange: { startDate, endDate, unit }, + } = useDateRange({ timezone }); const { locale, dateLocale } = useLocale(); const { colors } = useMemo(() => getThemeColors(theme), [theme]); - const sumQuery = usePropertyNumericSeriesQuery(source, websiteId, propertyName, 'sum', propertyFilters, eventName); - const avgQuery = usePropertyNumericSeriesQuery(source, websiteId, propertyName, 'avg', propertyFilters, eventName); - const statsQuery = usePropertyNumericStatsQuery(source, websiteId, propertyName, propertyFilters, eventName); + const sumQuery = usePropertyNumericSeriesQuery( + source, + websiteId, + propertyName, + 'sum', + propertyFilters, + eventName, + ); + const avgQuery = usePropertyNumericSeriesQuery( + source, + websiteId, + propertyName, + 'avg', + propertyFilters, + eventName, + ); + const statsQuery = usePropertyNumericStatsQuery( + source, + websiteId, + propertyName, + propertyFilters, + eventName, + ); - const sumRows = useMemo(() => (sumQuery.data as { t: string; y: number }[] | undefined) ?? [], [sumQuery.data]); - const avgRows = useMemo(() => (avgQuery.data as { t: string; y: number }[] | undefined) ?? [], [avgQuery.data]); + const sumRows = useMemo( + () => (sumQuery.data as { t: string; y: number }[] | undefined) ?? [], + [sumQuery.data], + ); + const avgRows = useMemo( + () => (avgQuery.data as { t: string; y: number }[] | undefined) ?? [], + [avgQuery.data], + ); const stats = statsQuery.data; const chartData: any = useMemo(() => { @@ -85,7 +113,20 @@ export function PropertyNumericChart({ }, ], }; - }, [avgQuery.data, avgRows, colors, dateLocale, endDate, labels.average, labels.sum, startDate, sumQuery.data, sumRows, t, unit]); + }, [ + avgQuery.data, + avgRows, + colors, + dateLocale, + endDate, + labels.average, + labels.sum, + startDate, + sumQuery.data, + sumRows, + t, + unit, + ]); const renderXLabel = useCallback(renderDateLabels(unit, locale), [unit, locale]); @@ -99,11 +140,27 @@ export function PropertyNumericChart({ minHeight="100px" > - - + + - - + + - - setValue('allowFilter', value, { shouldDirty: true })} - > - {t(labels.filtersEnabled)} - - - - setValue('theme', value, { shouldDirty: true })} - /> - + + setValue('allowFilter', value, { shouldDirty: true })} + > + {t(labels.filtersEnabled)} + + + + setValue('theme', value, { shouldDirty: true })} + /> + {onClose && ( diff --git a/src/components/share/SimpleSharesTable.tsx b/src/components/share/SimpleSharesTable.tsx index 13313f7b9..7af3e946d 100644 --- a/src/components/share/SimpleSharesTable.tsx +++ b/src/components/share/SimpleSharesTable.tsx @@ -1,8 +1,8 @@ +import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; import { ShareDeleteButton } from '@/app/(main)/websites/[websiteId]/settings/ShareDeleteButton'; import { CopyButton } from '@/components/common/CopyButton'; import { ExternalLink } from '@/components/common/ExternalLink'; import { useConfig, useMessages, useMobile } from '@/components/hooks'; -import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; import { SimpleShareEditButton } from './SimpleShareEditButton'; export function SimpleSharesTable(props: DataTableProps) { diff --git a/src/lib/api-url.test.ts b/src/lib/api-url.test.ts index 322315b00..be4720295 100644 --- a/src/lib/api-url.test.ts +++ b/src/lib/api-url.test.ts @@ -30,8 +30,6 @@ describe('getApiUrl', () => { }); test('returns absolute input urls unchanged', () => { - expect(getApiUrl('https://example.com/api/websites')).toBe( - 'https://example.com/api/websites', - ); + expect(getApiUrl('https://example.com/api/websites')).toBe('https://example.com/api/websites'); }); }); diff --git a/src/lib/api-url.ts b/src/lib/api-url.ts index 8cc790c1b..7d6e9d74d 100644 --- a/src/lib/api-url.ts +++ b/src/lib/api-url.ts @@ -3,10 +3,7 @@ type ApiUrlOptions = { basePath?: string; }; -const APP_ROUTE_PATTERNS: RegExp[] = [ - /^\/auth(\/|$)/, - /^\/config(\/|$)/, -]; +const APP_ROUTE_PATTERNS: RegExp[] = [/^\/auth(\/|$)/, /^\/config(\/|$)/]; function trimTrailingSlash(value: string) { return value.replace(/\/+$/, ''); diff --git a/src/lib/boards.ts b/src/lib/boards.ts index 77199fb88..c53865584 100644 --- a/src/lib/boards.ts +++ b/src/lib/boards.ts @@ -1,5 +1,5 @@ -import type { Board, BoardComponentConfig, BoardParameters } from './types'; import { isBoardComponentSupportedByEntityType } from './boardComponentCompatibility'; +import type { Board, BoardComponentConfig, BoardParameters } from './types'; export const BOARD_TYPES = { dashboard: 'dashboard', @@ -72,9 +72,7 @@ export function isOpenBoardType(type?: string) { } export function requiresBoardEntity(type?: string) { - return ( - type === BOARD_TYPES.website || type === BOARD_TYPES.pixel || type === BOARD_TYPES.link - ); + return type === BOARD_TYPES.website || type === BOARD_TYPES.pixel || type === BOARD_TYPES.link; } export function getBoardEntity(board?: Pick | Partial): { @@ -141,10 +139,7 @@ export function getResolvedComponentEntity( return getComponentEntity(config); } -export function isBoardComponentSupported( - componentType: string, - entityType?: BoardEntityType, -) { +export function isBoardComponentSupported(componentType: string, entityType?: BoardEntityType) { return isBoardComponentSupportedByEntityType(componentType, entityType); } diff --git a/src/lib/generate.ts b/src/lib/generate.ts index 752c0b609..0d3a0de84 100644 --- a/src/lib/generate.ts +++ b/src/lib/generate.ts @@ -1,11 +1,8 @@ -import { uniformInt } from 'pure-rand/distribution/uniformInt'; -import { xoroshiro128plus } from 'pure-rand/generator/xoroshiro128plus'; - -const seed = Date.now() ^ (Math.random() * 0x100000000); -const rng = xoroshiro128plus(seed); - export function random(min: number, max: number) { - return uniformInt(rng, min, max); + const range = max - min + 1; + const buf = new Uint32Array(1); + globalThis.crypto.getRandomValues(buf); + return min + (buf[0] % range); } export function getRandomChars( diff --git a/src/lib/heatmap-r2.ts b/src/lib/heatmap-r2.ts index 76c8b7343..4da5d06d6 100644 --- a/src/lib/heatmap-r2.ts +++ b/src/lib/heatmap-r2.ts @@ -52,11 +52,7 @@ function getClient() { return client; } -export async function putHeatmapSnapshot( - objectKey: string, - imageData: Buffer, - mimeType: string, -) { +export async function putHeatmapSnapshot(objectKey: string, imageData: Buffer, mimeType: string) { await getClient().send( new PutObjectCommand({ Bucket: getBucket(), diff --git a/src/lib/params.ts b/src/lib/params.ts index 50cb6db2d..17341fd53 100644 --- a/src/lib/params.ts +++ b/src/lib/params.ts @@ -108,42 +108,44 @@ export function parsePropertyFilters( query: Record, prefixes: string[] = ['pf'], ): PropertyFilter[] { - return Object.entries(query) - .flatMap(([key, val]) => { - const prefix = getPropertyFilterPrefix(key, prefixes); + return Object.entries(query).flatMap(([key, val]) => { + const prefix = getPropertyFilterPrefix(key, prefixes); - if (!prefix) { - return []; - } + if (!prefix) { + return []; + } - const stringValue = String(val); - const withoutPrefix = key.slice(prefix.length + 1); - const propertyName = withoutPrefix.replace(/\d+$/, ''); // strip trailing index digits - const prefixedDotMatch = stringValue.match(/^(\d+)\.([^.]+)\.(.*)$/); - const untypedDotMatch = stringValue.match(/^([^.]+)\.(.*)$/); - const explicitDataType = prefixedDotMatch ? Number(prefixedDotMatch[1]) : undefined; - const rawOperator = prefixedDotMatch ? prefixedDotMatch[2] : untypedDotMatch?.[1]; - const operator = resolveOperator(rawOperator); + const stringValue = String(val); + const withoutPrefix = key.slice(prefix.length + 1); + const propertyName = withoutPrefix.replace(/\d+$/, ''); // strip trailing index digits + const prefixedDotMatch = stringValue.match(/^(\d+)\.([^.]+)\.(.*)$/); + const untypedDotMatch = stringValue.match(/^([^.]+)\.(.*)$/); + const explicitDataType = prefixedDotMatch ? Number(prefixedDotMatch[1]) : undefined; + const rawOperator = prefixedDotMatch ? prefixedDotMatch[2] : untypedDotMatch?.[1]; + const operator = resolveOperator(rawOperator); - if (!operator || (explicitDataType !== undefined && !VALID_EVENT_DATA_TYPES.includes(explicitDataType))) { - return []; - } + if ( + !operator || + (explicitDataType !== undefined && !VALID_EVENT_DATA_TYPES.includes(explicitDataType)) + ) { + return []; + } - const value = prefixedDotMatch ? prefixedDotMatch[3] : untypedDotMatch?.[2]; + const value = prefixedDotMatch ? prefixedDotMatch[3] : untypedDotMatch?.[2]; - if (value === undefined) { - return []; - } + if (value === undefined) { + return []; + } - return [ - { - propertyName, - dataType: explicitDataType ?? DATA_TYPE.string, - operator, - value, - }, - ]; - }); + return [ + { + propertyName, + dataType: explicitDataType ?? DATA_TYPE.string, + operator, + value, + }, + ]; + }); } export function parseEventPropertyFilters(query: Record) { @@ -159,7 +161,10 @@ export function serializePropertyFilters( filters.map(f => { const n = counts[f.propertyName] ?? 0; counts[f.propertyName] = n + 1; - return [`${prefix}_${f.propertyName}${n > 0 ? n : ''}`, `${f.dataType}.${f.operator}.${f.value}`]; + return [ + `${prefix}_${f.propertyName}${n > 0 ? n : ''}`, + `${f.dataType}.${f.operator}.${f.value}`, + ]; }), ); } diff --git a/src/lib/request.ts b/src/lib/request.ts index 87c4872ad..4aa2e8a7a 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -1,3 +1,5 @@ +import { startOfMonth, subMonths } from 'date-fns'; +import { z } from 'zod'; import { checkAuth } from '@/lib/auth'; import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS } from '@/lib/constants'; import { getAllowedUnits, getMinimumUnit, maxDate, parseDateRange } from '@/lib/date'; @@ -6,8 +8,6 @@ import { filtersArrayToObject } from '@/lib/params'; import { badRequest, unauthorized } from '@/lib/response'; import type { QueryFilters } from '@/lib/types'; import { getWebsiteSegment } from '@/queries/prisma'; -import { startOfMonth, subMonths } from 'date-fns'; -import { z } from 'zod'; export async function parseRequest( request: Request, diff --git a/src/permissions/link.ts b/src/permissions/link.ts index f274c7b25..be6eef71a 100644 --- a/src/permissions/link.ts +++ b/src/permissions/link.ts @@ -8,7 +8,11 @@ export async function canViewLink({ user, shareToken }: Auth, linkId: string) { return true; } - if (shareToken?.linkId === linkId || shareToken?.websiteId === linkId || shareToken?.linkIds?.includes(linkId)) { + if ( + shareToken?.linkId === linkId || + shareToken?.websiteId === linkId || + shareToken?.linkIds?.includes(linkId) + ) { return true; } diff --git a/src/permissions/pixel.ts b/src/permissions/pixel.ts index 79b1b5976..061363063 100644 --- a/src/permissions/pixel.ts +++ b/src/permissions/pixel.ts @@ -8,7 +8,11 @@ export async function canViewPixel({ user, shareToken }: Auth, pixelId: string) return true; } - if (shareToken?.pixelId === pixelId || shareToken?.websiteId === pixelId || shareToken?.pixelIds?.includes(pixelId)) { + if ( + shareToken?.pixelId === pixelId || + shareToken?.websiteId === pixelId || + shareToken?.pixelIds?.includes(pixelId) + ) { return true; } diff --git a/src/queries/prisma/user.ts b/src/queries/prisma/user.ts index 905c3f6b2..99bb2f49e 100644 --- a/src/queries/prisma/user.ts +++ b/src/queries/prisma/user.ts @@ -130,9 +130,7 @@ export async function deleteUser(userId: string) { const teamIds = teams.map(a => a.id); - const ownedFilter = cloudMode - ? { userId } - : { OR: [{ userId }, { teamId: { in: teamIds } }] }; + const ownedFilter = cloudMode ? { userId } : { OR: [{ userId }, { teamId: { in: teamIds } }] }; const [links, pixels, boards] = await Promise.all([ client.link.findMany({ diff --git a/src/queries/sql/events/getEventData.ts b/src/queries/sql/events/getEventData.ts index 4a3fac860..ebd0df983 100644 --- a/src/queries/sql/events/getEventData.ts +++ b/src/queries/sql/events/getEventData.ts @@ -39,10 +39,9 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { group by website_event.event_id `; - const count = await rawQuery( - `select count(*) as num from (${eventQuery}) t`, - queryParams, - ).then((res: any) => res[0].num); + const count = await rawQuery(`select count(*) as num from (${eventQuery}) t`, queryParams).then( + (res: any) => res[0].num, + ); const data = await rawQuery( ` @@ -106,10 +105,9 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) { group by event_data.event_id `; - const count = await rawQuery( - `select count(*) as num from (${eventQuery}) t`, - queryParams, - ).then((res: any) => res[0].num); + const count = await rawQuery(`select count(*) as num from (${eventQuery}) t`, queryParams).then( + (res: any) => res[0].num, + ); const data = await rawQuery( ` @@ -149,4 +147,4 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) { ); return { data, count, page: +page, pageSize: size }; -} \ No newline at end of file +} diff --git a/src/queries/sql/heatmap/ensureHeatmapSnapshot.ts b/src/queries/sql/heatmap/ensureHeatmapSnapshot.ts index a194deb42..54e727e84 100644 --- a/src/queries/sql/heatmap/ensureHeatmapSnapshot.ts +++ b/src/queries/sql/heatmap/ensureHeatmapSnapshot.ts @@ -1,9 +1,9 @@ import { serializeError } from 'serialize-error'; import { getApiUrl } from '@/lib/api-url'; import clickhouse from '@/lib/clickhouse'; -import prisma from '@/lib/prisma'; import { uuid } from '@/lib/crypto'; import { getHeatmapSnapshot, putHeatmapSnapshot } from '@/lib/heatmap-r2'; +import prisma from '@/lib/prisma'; import { getWebsite } from '@/queries/prisma'; const SNAPSHOT_STATUS = { @@ -78,7 +78,12 @@ async function measurePage(page: any) { const rootClientWidth = root?.clientWidth || 0; const docClientWidth = doc?.clientWidth || 0; const bodyClientWidth = body?.clientWidth || 0; - const visibleWidth = Math.max(window.innerWidth, rootClientWidth, docClientWidth, bodyClientWidth); + const visibleWidth = Math.max( + window.innerWidth, + rootClientWidth, + docClientWidth, + bodyClientWidth, + ); const rootScrollWidth = root?.scrollWidth || 0; const docScrollWidth = doc?.scrollWidth || 0; const bodyScrollWidth = body?.scrollWidth || 0; @@ -299,7 +304,9 @@ async function findClickhouseSnapshot( return null; } - const status = Object.entries(CLICKHOUSE_SNAPSHOT_STATUS).find(([, value]) => value === row.status)?.[0]; + const status = Object.entries(CLICKHOUSE_SNAPSHOT_STATUS).find( + ([, value]) => value === row.status, + )?.[0]; if (!status) { return null; @@ -325,7 +332,10 @@ function getSnapshotImageUrl(websiteId: string, snapshotId: string) { function mapSnapshot(websiteId: string, row: SnapshotRecord): HeatmapSnapshotImage { return { id: row.id, - imageUrl: row.status === SNAPSHOT_STATUS.ready && row.hasImage ? getSnapshotImageUrl(websiteId, row.id) : null, + imageUrl: + row.status === SNAPSHOT_STATUS.ready && row.hasImage + ? getSnapshotImageUrl(websiteId, row.id) + : null, status: row.status, mimeType: row.mimeType, pageW: Number(row.pageW), @@ -566,7 +576,12 @@ async function insertClickhouseSnapshotRecord({ ]); } -function getSnapshotObjectKey(websiteId: string, snapshotId: string, viewportW: number, viewportH: number) { +function getSnapshotObjectKey( + websiteId: string, + snapshotId: string, + viewportW: number, + viewportH: number, +) { return `${websiteId}/${viewportW}x${viewportH}/${snapshotId}.png`; } @@ -624,7 +639,9 @@ async function captureSnapshot( let dimensions = await measurePage(page); let currentWidth = initialViewportW; let captureWidth = - dimensions.pageW > initialViewportW + 24 ? Math.max(initialViewportW, dimensions.pageW) : initialViewportW; + dimensions.pageW > initialViewportW + 24 + ? Math.max(initialViewportW, dimensions.pageW) + : initialViewportW; for (let i = 0; i < 3; i++) { if (captureWidth <= currentWidth) { @@ -684,17 +701,11 @@ export async function ensureHeatmapSnapshot({ const updatedAt = existing?.updatedAt ? new Date(existing.updatedAt) : null; const ageMs = updatedAt ? Date.now() - updatedAt.getTime() : Number.POSITIVE_INFINITY; - if ( - existing?.status === SNAPSHOT_STATUS.pending && - ageMs < SNAPSHOT_PENDING_WINDOW_MS - ) { + if (existing?.status === SNAPSHOT_STATUS.pending && ageMs < SNAPSHOT_PENDING_WINDOW_MS) { return mapSnapshot(websiteId, existing); } - if ( - existing?.status === SNAPSHOT_STATUS.failed && - ageMs < SNAPSHOT_RETRY_DELAY_MS - ) { + if (existing?.status === SNAPSHOT_STATUS.failed && ageMs < SNAPSHOT_RETRY_DELAY_MS) { return mapSnapshot(websiteId, existing); } @@ -738,10 +749,9 @@ export async function ensureHeatmapSnapshot({ try { const capture = await captureSnapshot(captureUrl, viewportW, viewportH, pageW); - const objectKey = - clickhouse.enabled - ? getSnapshotObjectKey(websiteId, snapshotId, viewportW, viewportH) - : null; + const objectKey = clickhouse.enabled + ? getSnapshotObjectKey(websiteId, snapshotId, viewportW, viewportH) + : null; if (objectKey) { await putHeatmapSnapshot(objectKey, capture.imageData, capture.mimeType); @@ -798,9 +808,7 @@ export async function getHeatmapSnapshotImage( snapshotId: string, ): Promise<{ mimeType: string; imageData: Buffer } | null> { if (clickhouse.enabled) { - const rows = await clickhouse.rawQuery< - { mimeType: string; objectKey: string }[] - >( + const rows = await clickhouse.rawQuery<{ mimeType: string; objectKey: string }[]>( ` select mime_type as mimeType, diff --git a/src/queries/sql/heatmap/getHeatmap.ts b/src/queries/sql/heatmap/getHeatmap.ts index 1e4bd8b34..785956bcd 100644 --- a/src/queries/sql/heatmap/getHeatmap.ts +++ b/src/queries/sql/heatmap/getHeatmap.ts @@ -5,8 +5,8 @@ import { filtersObjectToArray } from '@/lib/params'; import prisma from '@/lib/prisma'; import type { QueryFilters } from '@/lib/types'; import { - type HeatmapSnapshotImage, ensureHeatmapSnapshot, + type HeatmapSnapshotImage, shouldSkipSnapshot, } from './ensureHeatmapSnapshot'; @@ -543,15 +543,13 @@ function pickSnapshotViewport( } } - let bestViewport: - | { - width: number; - height: number; - count: number; - maxPageW: number; - maxPageH: number; - } - | null = null; + let bestViewport: { + width: number; + height: number; + count: number; + maxPageW: number; + maxPageH: number; + } | null = null; for (const bucket of viewportBuckets.values()) { if (!bestViewport || bucket.count > bestViewport.count) { @@ -626,7 +624,9 @@ function getRelationalHeatmapPathFilterContext(filters: QueryFilters) { ); const joinedClauses = - filters.match === 'any' ? clauses.filter(Boolean).join('\n or ') : clauses.filter(Boolean).join('\n and '); + filters.match === 'any' + ? clauses.filter(Boolean).join('\n or ') + : clauses.filter(Boolean).join('\n and '); return { filterQuery: @@ -680,7 +680,9 @@ function getClickhouseHeatmapPathFilterContext(filters: QueryFilters) { ); const joinedClauses = - filters.match === 'any' ? clauses.filter(Boolean).join('\n or ') : clauses.filter(Boolean).join('\n and '); + filters.match === 'any' + ? clauses.filter(Boolean).join('\n or ') + : clauses.filter(Boolean).join('\n and '); return { filterQuery: diff --git a/src/queries/sql/index.ts b/src/queries/sql/index.ts index a5bbb4193..bd0196e73 100644 --- a/src/queries/sql/index.ts +++ b/src/queries/sql/index.ts @@ -44,14 +44,14 @@ export * from './reports/getUTM'; export * from './sessions/createSession'; export * from './sessions/getSessionActivity'; export * from './sessions/getSessionData'; +export * from './sessions/getSessionDataActivityStats'; export * from './sessions/getSessionDataArraySeries'; export * from './sessions/getSessionDataDateSeries'; -export * from './sessions/getSessionDataProperties'; -export * from './sessions/getSessionDataPropertySeries'; export * from './sessions/getSessionDataNumericSeries'; export * from './sessions/getSessionDataNumericStats'; export * from './sessions/getSessionDataPivot'; -export * from './sessions/getSessionDataActivityStats'; +export * from './sessions/getSessionDataProperties'; +export * from './sessions/getSessionDataPropertySeries'; export * from './sessions/getSessionDataValues'; export * from './sessions/getSessionExpandedMetrics'; export * from './sessions/getSessionMetrics'; diff --git a/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts b/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts index c1ca8cd0c..2eeeeca5f 100644 --- a/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts +++ b/src/queries/sql/pageviews/getPageviewExpandedMetrics.ts @@ -75,13 +75,15 @@ async function relationalQuery( `; } - const selectColumn = type === 'fullPath' - ? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end` - : column; + const selectColumn = + type === 'fullPath' + ? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end` + : column; - const groupByColumn = type === 'fullPath' - ? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end` - : column; + const groupByColumn = + type === 'fullPath' + ? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end` + : column; return rawQuery( ` diff --git a/src/queries/sql/pageviews/getPageviewMetrics.ts b/src/queries/sql/pageviews/getPageviewMetrics.ts index cfc8d0c7f..8a78cb0d2 100644 --- a/src/queries/sql/pageviews/getPageviewMetrics.ts +++ b/src/queries/sql/pageviews/getPageviewMetrics.ts @@ -71,9 +71,10 @@ async function relationalQuery( column = `x.${FILTER_COLUMNS[type] || type}`; } - const selectColumn = type === 'fullPath' - ? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end` - : column; + const selectColumn = + type === 'fullPath' + ? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end` + : column; return rawQuery( ` diff --git a/src/queries/sql/sessions/getSessionDataActivityStats.ts b/src/queries/sql/sessions/getSessionDataActivityStats.ts index 939f437c0..724ba4844 100644 --- a/src/queries/sql/sessions/getSessionDataActivityStats.ts +++ b/src/queries/sql/sessions/getSessionDataActivityStats.ts @@ -7,7 +7,12 @@ import type { PropertyFilter, PropertyLeaderboardRow, QueryFilters } from '@/lib const FUNCTION_NAME = 'getSessionDataActivityStats'; export async function getSessionDataActivityStats( - ...args: [websiteId: string, propertyName: string, filters: QueryFilters, propertyFilters?: PropertyFilter[]] + ...args: [ + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + ] ): Promise { return runQuery({ [PRISMA]: () => relationalQuery(...args), @@ -28,8 +33,12 @@ async function relationalQuery( websiteId, timezone, }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); - + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); + return rawQuery( ` with filtered_sessions as ( @@ -110,8 +119,16 @@ async function clickhouseQuery( ) { const { timezone = 'UTC' } = filters; const { rawQuery, parseFilters, getPropertyFilterQuery } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` diff --git a/src/queries/sql/sessions/getSessionDataArraySeries.ts b/src/queries/sql/sessions/getSessionDataArraySeries.ts index 89e876d45..840d6b468 100644 --- a/src/queries/sql/sessions/getSessionDataArraySeries.ts +++ b/src/queries/sql/sessions/getSessionDataArraySeries.ts @@ -33,7 +33,11 @@ async function relationalQuery( websiteId, timezone, }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` @@ -71,8 +75,16 @@ async function clickhouseQuery( ): Promise { const { timezone = 'UTC', unit = 'day' } = filters; const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` diff --git a/src/queries/sql/sessions/getSessionDataDateSeries.ts b/src/queries/sql/sessions/getSessionDataDateSeries.ts index 15b762959..8c17bf929 100644 --- a/src/queries/sql/sessions/getSessionDataDateSeries.ts +++ b/src/queries/sql/sessions/getSessionDataDateSeries.ts @@ -33,7 +33,11 @@ async function relationalQuery( websiteId, timezone, }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` @@ -69,8 +73,16 @@ async function clickhouseQuery( ): Promise { const { timezone = 'UTC' } = filters; const { rawQuery, parseFilters, getDateStringSQL, getPropertyFilterQuery } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` diff --git a/src/queries/sql/sessions/getSessionDataNumericSeries.ts b/src/queries/sql/sessions/getSessionDataNumericSeries.ts index e74ac8f56..64f74fc25 100644 --- a/src/queries/sql/sessions/getSessionDataNumericSeries.ts +++ b/src/queries/sql/sessions/getSessionDataNumericSeries.ts @@ -35,7 +35,11 @@ async function relationalQuery( websiteId, timezone, }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); const aggSql = metric === 'avg' ? 'avg(cast(session_data.number_value as decimal))' @@ -83,8 +87,16 @@ async function clickhouseQuery( ): Promise<{ t: string; y: number }[]> { const { timezone = 'UTC', unit = 'day' } = filters; const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); const aggSql = metric === 'avg' ? 'avg(session_data.number_value)' diff --git a/src/queries/sql/sessions/getSessionDataNumericStats.ts b/src/queries/sql/sessions/getSessionDataNumericStats.ts index 7f6ee775f..c7dfdad28 100644 --- a/src/queries/sql/sessions/getSessionDataNumericStats.ts +++ b/src/queries/sql/sessions/getSessionDataNumericStats.ts @@ -33,7 +33,11 @@ async function relationalQuery( websiteId, timezone, }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` @@ -75,8 +79,16 @@ async function clickhouseQuery( ): Promise { const { timezone = 'UTC' } = filters; const { rawQuery, parseFilters, getPropertyFilterQuery } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` diff --git a/src/queries/sql/sessions/getSessionDataPivot.ts b/src/queries/sql/sessions/getSessionDataPivot.ts index 9e9445853..f8e313ba9 100644 --- a/src/queries/sql/sessions/getSessionDataPivot.ts +++ b/src/queries/sql/sessions/getSessionDataPivot.ts @@ -128,7 +128,11 @@ async function clickhouseQuery( const { timezone = 'UTC' } = filters; const { pagedRawQuery, parseFilters, getPropertyFilterQuery, getDateStringSQL } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( propertyFilters, 'session', diff --git a/src/queries/sql/sessions/getSessionDataProperties.ts b/src/queries/sql/sessions/getSessionDataProperties.ts index 38708b116..1d81c7bd0 100644 --- a/src/queries/sql/sessions/getSessionDataProperties.ts +++ b/src/queries/sql/sessions/getSessionDataProperties.ts @@ -85,7 +85,11 @@ async function clickhouseQuery( ): Promise<{ propertyName: string; dataType: number; total: number }[]> { const { timezone = 'UTC' } = filters; const { rawQuery, parseFilters, getPropertyFilterQuery } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( propertyFilters, 'session', diff --git a/src/queries/sql/sessions/getSessionDataPropertySeries.ts b/src/queries/sql/sessions/getSessionDataPropertySeries.ts index f66620b1e..f8ba5be1d 100644 --- a/src/queries/sql/sessions/getSessionDataPropertySeries.ts +++ b/src/queries/sql/sessions/getSessionDataPropertySeries.ts @@ -33,7 +33,11 @@ async function relationalQuery( websiteId, timezone, }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` @@ -70,8 +74,16 @@ async function clickhouseQuery( ): Promise { const { timezone = 'UTC', unit = 'day' } = filters; const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); - const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` diff --git a/src/store/app.ts b/src/store/app.ts index 0893c506a..851332e26 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -32,10 +32,7 @@ export function setLocale(locale: string) { store.setState({ locale }); } -export function setShareData( - share: object | null, - shareToken: { token?: string } | null, -) { +export function setShareData(share: object | null, shareToken: { token?: string } | null) { store.setState({ share, shareToken }); }