Lint format files. Updated rng function.
This commit is contained in:
@@ -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",
|
||||
|
||||
+5
-1
@@ -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.');
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
+15
-15
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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({
|
||||
</DataColumn>
|
||||
<DataColumn
|
||||
id="created"
|
||||
label={<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />}
|
||||
label={
|
||||
<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />
|
||||
}
|
||||
width="160px"
|
||||
>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
|
||||
@@ -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({
|
||||
</DataColumn>
|
||||
<DataColumn
|
||||
id="created"
|
||||
label={<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />}
|
||||
label={
|
||||
<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />
|
||||
}
|
||||
>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
</DataColumn>
|
||||
|
||||
@@ -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[] }) {
|
||||
</DataColumn>
|
||||
<DataColumn
|
||||
id="created"
|
||||
label={<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />}
|
||||
label={
|
||||
<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />
|
||||
}
|
||||
width="180px"
|
||||
>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
|
||||
@@ -15,13 +15,7 @@ export function BoardEntityBadge({
|
||||
return (
|
||||
<Row padding borderRadius="full" backgroundColor="surface-base" border gap="2">
|
||||
<Icon>
|
||||
{type === 'pixel' ? (
|
||||
<Grid2x2 />
|
||||
) : type === 'link' ? (
|
||||
<Link />
|
||||
) : (
|
||||
<Favicon domain={domain} />
|
||||
)}
|
||||
{type === 'pixel' ? <Grid2x2 /> : type === 'link' ? <Link /> : <Favicon domain={domain} />}
|
||||
</Icon>
|
||||
<Text size="sm">{name}</Text>
|
||||
</Row>
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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={<SortableLabel label={t(labels.description)} sortKey="description" />}
|
||||
/>
|
||||
<DataColumn id="type" label={<SortableLabel label={t(labels.boardType)} sortKey="type" />}>
|
||||
{({ type }: any) => type ? type.charAt(0).toUpperCase() + type.slice(1) : ''}
|
||||
{({ type }: any) => (type ? type.charAt(0).toUpperCase() + type.slice(1) : '')}
|
||||
</DataColumn>
|
||||
<DataColumn
|
||||
id="created"
|
||||
label={<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />}
|
||||
label={
|
||||
<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />
|
||||
}
|
||||
width="200px"
|
||||
>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
|
||||
@@ -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<BoardEntityType>(
|
||||
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({
|
||||
<Text weight="bold">Preview</Text>
|
||||
<Column border="left" paddingLeft="4" height="100%" style={{ minWidth: 0 }}>
|
||||
{hasSelectedEntity && previewConfig && (!needsWebsite || resolvedEntityId) ? (
|
||||
<BoardComponentRenderer config={previewConfig} websiteId={resolvedEntityId} entityType={resolvedEntityType} />
|
||||
<BoardComponentRenderer
|
||||
config={previewConfig}
|
||||
websiteId={resolvedEntityId}
|
||||
entityType={resolvedEntityType}
|
||||
/>
|
||||
) : (
|
||||
<Column alignItems="center" justifyContent="center" height="100%">
|
||||
<Text color="muted">
|
||||
|
||||
@@ -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 <BoardComponentRenderer config={component} websiteId={entityId} entityType={entityType} />;
|
||||
return (
|
||||
<BoardComponentRenderer config={component} websiteId={entityId} entityType={entityType} />
|
||||
);
|
||||
}, [component, definition?.requiresWebsite, entityId, entityType]);
|
||||
|
||||
const handleSelect = (config: BoardComponentConfig) => {
|
||||
@@ -95,9 +97,7 @@ export function BoardEditColumn({
|
||||
>
|
||||
<TooltipTrigger delay={0}>
|
||||
<Button variant="outline" onPress={() => setShowSelect(true)}>
|
||||
<Icon size="sm">
|
||||
{hasComponent ? <Pencil /> : <Plus />}
|
||||
</Icon>
|
||||
<Icon size="sm">{hasComponent ? <Pencil /> : <Plus />}</Icon>
|
||||
</Button>
|
||||
<Tooltip>{t(hasComponent ? labels.edit : labels.selectComponent)}</Tooltip>
|
||||
</TooltipTrigger>
|
||||
|
||||
@@ -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 (
|
||||
<DialogButton
|
||||
icon={<Share />}
|
||||
label={t(labels.share)}
|
||||
title={null}
|
||||
width="900px"
|
||||
>
|
||||
<DialogButton icon={<Share />} label={t(labels.share)} title={null} width="900px">
|
||||
<BoardShareDialog boardId={boardId} />
|
||||
</DialogButton>
|
||||
);
|
||||
|
||||
@@ -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 && (
|
||||
<Text>{t(messages.shareUrl)}</Text>
|
||||
)}
|
||||
{hasShares && <Text>{t(messages.shareUrl)}</Text>}
|
||||
{!showCreateForm &&
|
||||
(hasShares ? (
|
||||
<BoardSharesTable data={shares} />
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<PageBody>
|
||||
<Column
|
||||
margin="2"
|
||||
width="100%"
|
||||
maxWidth="800px"
|
||||
style={{ marginInline: 'auto' }}
|
||||
>
|
||||
<Column margin="2" width="100%" maxWidth="800px" style={{ marginInline: 'auto' }}>
|
||||
<>
|
||||
<Column marginTop="6">
|
||||
<Link href={renderUrl(`/boards/${boardId}`)}>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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) {
|
||||
</DataColumn>
|
||||
<DataColumn
|
||||
id="created"
|
||||
label={<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />}
|
||||
label={
|
||||
<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />
|
||||
}
|
||||
width="200px"
|
||||
>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
|
||||
@@ -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 && (
|
||||
<Text>{t(messages.shareUrl)}</Text>
|
||||
)}
|
||||
{hasShares && <Text>{t(messages.shareUrl)}</Text>}
|
||||
{!showCreateForm &&
|
||||
(hasShares ? (
|
||||
<SimpleSharesTable data={shares} />
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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) {
|
||||
</DataColumn>
|
||||
<DataColumn
|
||||
id="created"
|
||||
label={<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />}
|
||||
label={
|
||||
<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />
|
||||
}
|
||||
>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
</DataColumn>
|
||||
|
||||
@@ -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 && (
|
||||
<Text>{t(messages.shareUrl)}</Text>
|
||||
)}
|
||||
{hasShares && <Text>{t(messages.shareUrl)}</Text>}
|
||||
{!showCreateForm &&
|
||||
(hasShares ? (
|
||||
<SimpleSharesTable data={shares} />
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -4,5 +4,7 @@ import { ThemeModeSelector } from '@/components/input/ThemeModeSelector';
|
||||
export function ThemeSetting() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
return <ThemeModeSelector value={theme} onChange={value => setTheme(value as 'light' | 'dark')} />;
|
||||
return (
|
||||
<ThemeModeSelector value={theme} onChange={value => setTheme(value as 'light' | 'dark')} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -25,7 +25,9 @@ export function WebsitesTable({ showActions, renderLink, ...props }: WebsitesTab
|
||||
<DataColumn id="domain" label={<SortableLabel label={t(labels.domain)} sortKey="domain" />} />
|
||||
<DataColumn
|
||||
id="created"
|
||||
label={<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />}
|
||||
label={
|
||||
<SortableLabel label={t(labels.created)} sortKey="createdAt" defaultDirection="desc" />
|
||||
}
|
||||
width="200px"
|
||||
>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -94,9 +94,7 @@ function StepRow({
|
||||
<ActionSelect />
|
||||
</FormField>
|
||||
</Column>
|
||||
<Column>
|
||||
{valueField}
|
||||
</Column>
|
||||
<Column>{valueField}</Column>
|
||||
<Button onPress={onRemove}>
|
||||
<Icon size="sm">
|
||||
<X />
|
||||
|
||||
@@ -49,7 +49,14 @@ export function Goal({ id, name, type, parameters, websiteId, startDate, endDate
|
||||
</Column>
|
||||
{!isSharePage && (
|
||||
<Column>
|
||||
<ReportEditButton id={id} name={name} type={type} title={t(labels.goal)} minWidth="400px" minHeight="300px">
|
||||
<ReportEditButton
|
||||
id={id}
|
||||
name={name}
|
||||
type={type}
|
||||
title={t(labels.goal)}
|
||||
minWidth="400px"
|
||||
minHeight="300px"
|
||||
>
|
||||
{({ close }) => <GoalEditForm id={id} websiteId={websiteId} onClose={close} />}
|
||||
</ReportEditButton>
|
||||
</Column>
|
||||
|
||||
@@ -298,7 +298,12 @@ function ClickHeatmapView({
|
||||
</Text>
|
||||
</Row>
|
||||
) : (
|
||||
<Row alignItems="center" justifyContent="space-between" gap className={styles.summaryStats}>
|
||||
<Row
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap
|
||||
className={styles.summaryStats}
|
||||
>
|
||||
<Text color="muted" className={styles.summaryStat}>
|
||||
{viewport
|
||||
? `${visible.length} positions - ${formatLongNumber(totalClicks)} clicks - viewport ${viewport.width}x${viewport.height}`
|
||||
@@ -329,47 +334,49 @@ function ClickHeatmapView({
|
||||
<EmptyState message="No click data for this page yet." />
|
||||
) : (
|
||||
<>
|
||||
<div className={styles.snapshotClip}>
|
||||
{showSnapshot && !snapshotReady && <CanvasLoading />}
|
||||
{showSnapshot && snapshot?.imageUrl && <SnapshotImage snapshot={snapshot} onReady={handleSnapshotReady} />}
|
||||
</div>
|
||||
{showOverlay && (
|
||||
<div className={styles.overlay}>
|
||||
{visible.map((point, index) => {
|
||||
const intensity = Math.min(1, point.count / maxCount);
|
||||
const desiredSize = 24 + intensity * 36;
|
||||
const pointWidth = Math.max(overlayPageW, point.pageX);
|
||||
const pointHeight = Math.max(overlayPageH, point.pageY);
|
||||
const rawCenterX = (point.pageX / Math.max(1, pointWidth)) * 100;
|
||||
const rawCenterY = (point.pageY / Math.max(1, pointHeight)) * 100;
|
||||
const size = desiredSize;
|
||||
const centerX = Math.max(
|
||||
CLICK_EDGE_PERCENT,
|
||||
Math.min(100 - CLICK_EDGE_PERCENT, rawCenterX),
|
||||
);
|
||||
const centerY = Math.max(
|
||||
CLICK_EDGE_PERCENT,
|
||||
Math.min(100 - CLICK_EDGE_PERCENT, rawCenterY),
|
||||
);
|
||||
<div className={styles.snapshotClip}>
|
||||
{showSnapshot && !snapshotReady && <CanvasLoading />}
|
||||
{showSnapshot && snapshot?.imageUrl && (
|
||||
<SnapshotImage snapshot={snapshot} onReady={handleSnapshotReady} />
|
||||
)}
|
||||
</div>
|
||||
{showOverlay && (
|
||||
<div className={styles.overlay}>
|
||||
{visible.map((point, index) => {
|
||||
const intensity = Math.min(1, point.count / maxCount);
|
||||
const desiredSize = 24 + intensity * 36;
|
||||
const pointWidth = Math.max(overlayPageW, point.pageX);
|
||||
const pointHeight = Math.max(overlayPageH, point.pageY);
|
||||
const rawCenterX = (point.pageX / Math.max(1, pointWidth)) * 100;
|
||||
const rawCenterY = (point.pageY / Math.max(1, pointHeight)) * 100;
|
||||
const size = desiredSize;
|
||||
const centerX = Math.max(
|
||||
CLICK_EDGE_PERCENT,
|
||||
Math.min(100 - CLICK_EDGE_PERCENT, rawCenterX),
|
||||
);
|
||||
const centerY = Math.max(
|
||||
CLICK_EDGE_PERCENT,
|
||||
Math.min(100 - CLICK_EDGE_PERCENT, rawCenterY),
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`${point.pageX}-${point.pageY}-${index}`}
|
||||
className={styles.dot}
|
||||
style={{
|
||||
left: `${centerX}%`,
|
||||
top: `${centerY}%`,
|
||||
width: size,
|
||||
height: size,
|
||||
transform: 'translate(-50%, -50%)',
|
||||
opacity: 0.25 + intensity * 0.55,
|
||||
}}
|
||||
title={`${point.count} click${point.count === 1 ? '' : 's'}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
return (
|
||||
<div
|
||||
key={`${point.pageX}-${point.pageY}-${index}`}
|
||||
className={styles.dot}
|
||||
style={{
|
||||
left: `${centerX}%`,
|
||||
top: `${centerY}%`,
|
||||
width: size,
|
||||
height: size,
|
||||
transform: 'translate(-50%, -50%)',
|
||||
opacity: 0.25 + intensity * 0.55,
|
||||
}}
|
||||
title={`${point.count} click${point.count === 1 ? '' : 's'}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -405,8 +412,14 @@ function ScrollHeatmapView({
|
||||
useEffect(() => {
|
||||
setSnapshotReady(!(showPage && hasSnapshotImage));
|
||||
}, [hasSnapshotImage, showPage, snapshot?.id]);
|
||||
const { buckets = [], totalSessions = 0, pageW = 0, pageH = 0, viewportW = 0, viewportH = 0 } =
|
||||
scroll ?? {};
|
||||
const {
|
||||
buckets = [],
|
||||
totalSessions = 0,
|
||||
pageW = 0,
|
||||
pageH = 0,
|
||||
viewportW = 0,
|
||||
viewportH = 0,
|
||||
} = scroll ?? {};
|
||||
const baseWidth = Math.max(pageW, 1);
|
||||
const baseHeight = Math.max(pageH, 640);
|
||||
const renderWidth = snapshot?.pageW ?? baseWidth;
|
||||
@@ -451,7 +464,12 @@ function ScrollHeatmapView({
|
||||
</Text>
|
||||
</Row>
|
||||
) : (
|
||||
<Row alignItems="center" justifyContent="space-between" gap className={styles.summaryHeader}>
|
||||
<Row
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap
|
||||
className={styles.summaryHeader}
|
||||
>
|
||||
<Text color="muted" className={styles.summaryStat}>
|
||||
{hasScrollData
|
||||
? `${formatLongNumber(totalSessions)} sessions - page ${pageW}x${pageH}${viewportH ? ` - viewport ${viewportW}x${viewportH}` : ''}`
|
||||
@@ -481,33 +499,38 @@ function ScrollHeatmapView({
|
||||
<EmptyState message="No scroll data for this page yet." />
|
||||
) : (
|
||||
<div className={styles.canvasClip}>
|
||||
{showSnapshot && !snapshotReady && <CanvasLoading />}
|
||||
{showSnapshot && snapshot?.imageUrl && <SnapshotImage snapshot={snapshot} onReady={handleSnapshotReady} />}
|
||||
{showOverlay && (
|
||||
<div className={styles.overlay}>
|
||||
{bands.map(band => {
|
||||
const intensity = band.ratio;
|
||||
const hue = Math.round(60 - intensity * 60);
|
||||
{showSnapshot && !snapshotReady && <CanvasLoading />}
|
||||
{showSnapshot && snapshot?.imageUrl && (
|
||||
<SnapshotImage snapshot={snapshot} onReady={handleSnapshotReady} />
|
||||
)}
|
||||
{showOverlay && (
|
||||
<div className={styles.overlay}>
|
||||
{bands.map(band => {
|
||||
const intensity = band.ratio;
|
||||
const hue = Math.round(60 - intensity * 60);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={band.fromPct}
|
||||
className={styles.scrollBand}
|
||||
style={{
|
||||
top: `${band.fromPct}%`,
|
||||
height: `${Math.max(0, band.toPct - band.fromPct)}%`,
|
||||
background: intensity > 0 ? `hsla(${hue}, 90%, 55%, ${0.12 + intensity * 0.45})` : 'none',
|
||||
}}
|
||||
title={`${band.toPct}% depth - ${formatLongNumber(band.reached)} sessions reached`}
|
||||
>
|
||||
<span className={styles.scrollBandLabel}>
|
||||
{band.toPct}% depth - {Math.round(intensity * 100)}% reached
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
return (
|
||||
<div
|
||||
key={band.fromPct}
|
||||
className={styles.scrollBand}
|
||||
style={{
|
||||
top: `${band.fromPct}%`,
|
||||
height: `${Math.max(0, band.toPct - band.fromPct)}%`,
|
||||
background:
|
||||
intensity > 0
|
||||
? `hsla(${hue}, 90%, 55%, ${0.12 + intensity * 0.45})`
|
||||
: 'none',
|
||||
}}
|
||||
title={`${band.toPct}% depth - ${formatLongNumber(band.reached)} sessions reached`}
|
||||
>
|
||||
<span className={styles.scrollBandLabel}>
|
||||
{band.toPct}% depth - {Math.round(intensity * 100)}% reached
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -524,13 +547,7 @@ function ScrollHeatmapView({
|
||||
);
|
||||
}
|
||||
|
||||
function SnapshotImage({
|
||||
snapshot,
|
||||
onReady,
|
||||
}: {
|
||||
snapshot: HeatmapSnapshot;
|
||||
onReady: () => void;
|
||||
}) {
|
||||
function SnapshotImage({ snapshot, onReady }: { snapshot: HeatmapSnapshot; onReady: () => void }) {
|
||||
const [src, setSrc] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -52,7 +52,13 @@ export function HeatmapsPage({ websiteId }: { websiteId: string }) {
|
||||
return (
|
||||
<Column gap>
|
||||
<WebsiteControls websiteId={websiteId} />
|
||||
<Panel minHeight="900px" allowFullscreen minWidth="0" width="100%" style={{ overflow: 'hidden' }}>
|
||||
<Panel
|
||||
minHeight="900px"
|
||||
allowFullscreen
|
||||
minWidth="0"
|
||||
width="100%"
|
||||
style={{ overflow: 'hidden' }}
|
||||
>
|
||||
<Column gap="5" minWidth="0" width="100%" paddingTop="2">
|
||||
<Column gap="4" minWidth="0" width="100%">
|
||||
{isPhone ? (
|
||||
@@ -83,9 +89,7 @@ export function HeatmapsPage({ websiteId }: { websiteId: string }) {
|
||||
<Heatmap
|
||||
websiteId={websiteId}
|
||||
urlPath={urlPathByMode[mode]}
|
||||
onUrlPathChange={urlPath =>
|
||||
setUrlPathByMode(state => ({ ...state, [mode]: urlPath }))
|
||||
}
|
||||
onUrlPathChange={urlPath => setUrlPathByMode(state => ({ ...state, [mode]: urlPath }))}
|
||||
mode={mode}
|
||||
search={search}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Column, Grid, Icon, Row, Text } from '@umami/react-zen';
|
||||
import type { ReactNode } from 'react';
|
||||
import { differenceInCalendarDays } from 'date-fns';
|
||||
import type { ReactNode } from 'react';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { useLocale, useMessages, useResultQuery } from '@/components/hooks';
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
import { Column, Grid, Heading, ListItem, Row, Select, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
|
||||
import {
|
||||
Column,
|
||||
Grid,
|
||||
Heading,
|
||||
ListItem,
|
||||
Row,
|
||||
Select,
|
||||
Tab,
|
||||
TabList,
|
||||
TabPanel,
|
||||
Tabs,
|
||||
} from '@umami/react-zen';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { GridRow } from '@/components/common/GridRow';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { useDateRange, useMessages } from '@/components/hooks';
|
||||
import type { RevenueStatsData } from '@/components/hooks/queries/useRevenueStatsQuery';
|
||||
import { MetricCard } from '@/components/metrics/MetricCard';
|
||||
import { MetricsBar } from '@/components/metrics/MetricsBar';
|
||||
import { formatLongCurrency, formatLongNumber } from '@/lib/format';
|
||||
import type { RevenueStatsData } from '@/components/hooks/queries/useRevenueStatsQuery';
|
||||
|
||||
export interface RevenueMetricsBarProps {
|
||||
data: RevenueStatsData;
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { Grid } from '@umami/react-zen';
|
||||
import { useMemo } from 'react';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import {
|
||||
useMessages,
|
||||
useRevenueMetricsQuery,
|
||||
type RevenueMetricType,
|
||||
} from '@/components/hooks';
|
||||
import { type RevenueMetricType, useMessages, useRevenueMetricsQuery } from '@/components/hooks';
|
||||
import { ListTable } from '@/components/metrics/ListTable';
|
||||
import { MetricLabel } from '@/components/metrics/MetricLabel';
|
||||
import { formatLongCurrency } from '@/lib/format';
|
||||
|
||||
@@ -7,10 +7,7 @@ export interface RevenueSessionsDataTableProps {
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export function RevenueSessionsDataTable({
|
||||
websiteId,
|
||||
currency,
|
||||
}: RevenueSessionsDataTableProps) {
|
||||
export function RevenueSessionsDataTable({ websiteId, currency }: RevenueSessionsDataTableProps) {
|
||||
const { updateParams } = useNavigation();
|
||||
const queryResult = useRevenueSessionsQuery(websiteId, currency);
|
||||
|
||||
|
||||
@@ -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, useWebsiteNavItems } from '@/components/hooks';
|
||||
import { ArrowLeft } from '@/components/icons';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import { CohortDeleteButton } from '@/app/(main)/websites/[websiteId]/cohorts/CohortDeleteButton';
|
||||
import { CohortEditButton } from '@/app/(main)/websites/[websiteId]/cohorts/CohortEditButton';
|
||||
import { DateDistance } from '@/components/common/DateDistance';
|
||||
import Link from '@/components/common/Link';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
import { filtersObjectToArray } from '@/lib/params';
|
||||
|
||||
|
||||
@@ -7,7 +7,13 @@ import { Empty } from '@/components/common/Empty';
|
||||
import Link from '@/components/common/Link';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { Pager } from '@/components/common/Pager';
|
||||
import { useEventDataPivotQuery, useEventDataPropertiesQuery, useMessages, useMobile, useNavigation } from '@/components/hooks';
|
||||
import {
|
||||
useEventDataPivotQuery,
|
||||
useEventDataPropertiesQuery,
|
||||
useMessages,
|
||||
useMobile,
|
||||
useNavigation,
|
||||
} from '@/components/hooks';
|
||||
import type { EventPropertyFilter } from '@/lib/types';
|
||||
|
||||
export function EventDataPivotTable({
|
||||
@@ -41,7 +47,15 @@ export function EventDataPivotTable({
|
||||
const tableData = useMemo(() => {
|
||||
if (!pivotQuery.data?.data) return [];
|
||||
return pivotQuery.data.data.map(
|
||||
(row: { eventId: string; sessionId: string; eventName: string; urlPath: string; createdAt: string; propertyKeys: string[]; propertyValues: string[] }) => {
|
||||
(row: {
|
||||
eventId: string;
|
||||
sessionId: string;
|
||||
eventName: string;
|
||||
urlPath: string;
|
||||
createdAt: string;
|
||||
propertyKeys: string[];
|
||||
propertyValues: string[];
|
||||
}) => {
|
||||
const flat: Record<string, any> = {
|
||||
eventId: row.eventId,
|
||||
sessionId: row.sessionId,
|
||||
@@ -57,10 +71,7 @@ export function EventDataPivotTable({
|
||||
}, [pivotQuery.data]);
|
||||
|
||||
const tableQuery = useMemo(
|
||||
() =>
|
||||
pivotQuery.data
|
||||
? { ...pivotQuery.data, data: tableData }
|
||||
: undefined,
|
||||
() => (pivotQuery.data ? { ...pivotQuery.data, data: tableData } : undefined),
|
||||
[pivotQuery.data, tableData],
|
||||
);
|
||||
|
||||
@@ -110,13 +121,11 @@ export function EventDataPivotTable({
|
||||
</DataColumn>
|
||||
</DataTable>
|
||||
) : (
|
||||
<div style={{ width: '100%', maxWidth: '100%', overflowX: 'auto', overflowY: 'hidden' }}>
|
||||
<div
|
||||
style={{ width: '100%', maxWidth: '100%', overflowX: 'auto', overflowY: 'hidden' }}
|
||||
>
|
||||
<div style={{ width: tableMinWidth, minWidth: tableMinWidth }}>
|
||||
<DataTable
|
||||
data={tableQuery?.data}
|
||||
style={{ width: '100%' }}
|
||||
displayMode="table"
|
||||
>
|
||||
<DataTable data={tableQuery?.data} style={{ width: '100%' }} displayMode="table">
|
||||
<DataColumn id="session" label={t(labels.session)} width="72px">
|
||||
{(row: any) => (
|
||||
<Link href={updateParams({ session: row.sessionId })}>
|
||||
|
||||
@@ -10,10 +10,10 @@ import {
|
||||
Row,
|
||||
Text,
|
||||
} from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import { Avatar } from '@/components/common/Avatar';
|
||||
import { DateDistance } from '@/components/common/DateDistance';
|
||||
import { IconLabel } from '@/components/common/IconLabel';
|
||||
import Link from '@/components/common/Link';
|
||||
import { TypeIcon } from '@/components/common/TypeIcon';
|
||||
import { useFormat, useMessages, useNavigation } from '@/components/hooks';
|
||||
import { Eye, FileText } from '@/components/icons';
|
||||
|
||||
@@ -9,11 +9,7 @@ export function RealtimeHeader({ data }: { data: any }) {
|
||||
|
||||
return (
|
||||
<MetricsBar
|
||||
columns={
|
||||
isPhone
|
||||
? 'repeat(2, minmax(0, 1fr))'
|
||||
: 'repeat(auto-fit, minmax(160px, 1fr))'
|
||||
}
|
||||
columns={isPhone ? 'repeat(2, minmax(0, 1fr))' : 'repeat(auto-fit, minmax(160px, 1fr))'}
|
||||
>
|
||||
<MetricCard label={t(labels.views)} value={totals.views} />
|
||||
<MetricCard label={t(labels.visitors)} value={totals.visitors} />
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { Column, Heading, Row, SearchField, Text } from '@umami/react-zen';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { List, type RowComponentProps } from 'react-window';
|
||||
import { SessionModal } from '@/app/(main)/websites/[websiteId]/sessions/SessionModal';
|
||||
import { Avatar } from '@/components/common/Avatar';
|
||||
import { Empty } from '@/components/common/Empty';
|
||||
@@ -17,9 +20,6 @@ import { Eye, User } from '@/components/icons';
|
||||
import { FilterButtons } from '@/components/input/FilterButtons';
|
||||
import { Lightning } from '@/components/svg';
|
||||
import { BROWSERS, OS_NAMES } from '@/lib/constants';
|
||||
import { Column, Heading, Row, SearchField, Text } from '@umami/react-zen';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { List, type RowComponentProps } from 'react-window';
|
||||
|
||||
const TYPE_ALL = 'all';
|
||||
const TYPE_PAGEVIEW = 'pageview';
|
||||
@@ -136,9 +136,7 @@ export function RealtimeLog({ data }: { data: any }) {
|
||||
<Text wrap="nowrap">{getTime(row)}</Text>
|
||||
</Row>
|
||||
<IconLabel icon={getIcon(row)} style={{ minWidth: 0, flex: 1 }}>
|
||||
<Text truncate>
|
||||
{getDetail(row)}
|
||||
</Text>
|
||||
<Text truncate>{getDetail(row)}</Text>
|
||||
</IconLabel>
|
||||
</Row>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
'use client';
|
||||
import { Button, Column, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
|
||||
import { type Key, useState } from 'react';
|
||||
import { SessionModal } from '@/app/(main)/websites/[websiteId]/sessions/SessionModal';
|
||||
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
|
||||
import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder';
|
||||
@@ -6,8 +8,6 @@ import { Panel } from '@/components/common/Panel';
|
||||
import { useMessages, useSubscription, useWebsite } from '@/components/hooks';
|
||||
import { Video } from '@/components/icons';
|
||||
import { getItem, setItem } from '@/lib/storage';
|
||||
import { Button, Column, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
|
||||
import { type Key, useState } from 'react';
|
||||
import { ReplayModal } from './ReplayModal';
|
||||
import { ReplaysDataTable } from './ReplaysDataTable';
|
||||
import { SavedReplaysDataTable } from './SavedReplaysDataTable';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Button, DataColumn, DataTable, type DataTableProps, Icon } from '@umami/react-zen';
|
||||
import { Play } from 'lucide-react';
|
||||
import Link from '@/components/common/Link';
|
||||
import { Avatar } from '@/components/common/Avatar';
|
||||
import { DateDistance } from '@/components/common/DateDistance';
|
||||
import Link from '@/components/common/Link';
|
||||
import { TypeIcon } from '@/components/common/TypeIcon';
|
||||
import { useFormat, useMessages, useNavigation } from '@/components/hooks';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
import { useMobile } from '@/components/hooks';
|
||||
import { Column } from '@umami/react-zen';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useMobile } from '@/components/hooks';
|
||||
import 'rrweb-player/dist/style.css';
|
||||
|
||||
export function ReplayPlayer({ events }: { events: any[] }) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import { SegmentDeleteButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton';
|
||||
import { SegmentEditButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentEditButton';
|
||||
import { DateDistance } from '@/components/common/DateDistance';
|
||||
import Link from '@/components/common/Link';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
|
||||
export function SegmentsTable(props: DataTableProps) {
|
||||
|
||||
@@ -37,7 +37,10 @@ export function SessionDataPivotTable({
|
||||
return [];
|
||||
}, [providedPropertyKeys]);
|
||||
|
||||
const tableMinWidth = useMemo(() => `${72 + 220 + 180 + propertyKeys.length * 160}px`, [propertyKeys.length]);
|
||||
const tableMinWidth = useMemo(
|
||||
() => `${72 + 220 + 180 + propertyKeys.length * 160}px`,
|
||||
[propertyKeys.length],
|
||||
);
|
||||
|
||||
const tableData = useMemo(() => {
|
||||
if (!pivotQuery.data?.data) return [];
|
||||
@@ -120,7 +123,9 @@ export function SessionDataPivotTable({
|
||||
{isMobile ? (
|
||||
renderTable('cards')
|
||||
) : (
|
||||
<div style={{ width: '100%', maxWidth: '100%', overflowX: 'auto', overflowY: 'hidden' }}>
|
||||
<div
|
||||
style={{ width: '100%', maxWidth: '100%', overflowX: 'auto', overflowY: 'hidden' }}
|
||||
>
|
||||
<div style={{ width: tableMinWidth, minWidth: tableMinWidth }}>
|
||||
{renderTable('table')}
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
'use client';
|
||||
import { Column, DataColumn, DataTable, Grid, Row, Text } from '@umami/react-zen';
|
||||
import { useMemo } from 'react';
|
||||
import { DistributionBarChart } from '@/components/charts/DistributionBarChart';
|
||||
import { Empty } from '@/components/common/Empty';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { useMessages, useMobile, useSessionDataActivityStatsQuery } from '@/components/hooks';
|
||||
import { formatLongNumber } from '@/lib/format';
|
||||
import type { PropertyFilter } from '@/lib/types';
|
||||
import { Column, DataColumn, DataTable, Grid, Row, Text } from '@umami/react-zen';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export function SessionPropertyChart({
|
||||
websiteId,
|
||||
|
||||
@@ -34,7 +34,12 @@ export function SessionModal({ websiteId, ...props }: SessionModalProps) {
|
||||
<Dialog variant="sheet" className="rounded-lg">
|
||||
{({ close }) => (
|
||||
<Column padding="10">
|
||||
<SessionProfile websiteId={websiteId} sessionId={session} showReplays={!isSharePage} onClose={() => close()} />
|
||||
<SessionProfile
|
||||
websiteId={websiteId}
|
||||
sessionId={session}
|
||||
showReplays={!isSharePage}
|
||||
onClose={() => close()}
|
||||
/>
|
||||
</Column>
|
||||
)}
|
||||
</Dialog>
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
'use client';
|
||||
import { Avatar } from '@/components/common/Avatar';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { useMessages, useWebsiteSessionQuery } from '@/components/hooks';
|
||||
import {
|
||||
Button,
|
||||
Column,
|
||||
@@ -14,6 +11,9 @@ import {
|
||||
TextField,
|
||||
} from '@umami/react-zen';
|
||||
import { X } from 'lucide-react';
|
||||
import { Avatar } from '@/components/common/Avatar';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { useMessages, useWebsiteSessionQuery } from '@/components/hooks';
|
||||
import { SessionActivity } from './SessionActivity';
|
||||
import { SessionData } from './SessionData';
|
||||
import { SessionInfo } from './SessionInfo';
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { Column, ComboBox, Grid, Label, ListItem, Row } from '@umami/react-zen';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { useMessages, usePropertyFieldsQuery, useSessionDataPropertiesQuery } from '@/components/hooks';
|
||||
import { DATA_TYPE } from '@/lib/constants';
|
||||
import type { PropertyFilter } from '@/lib/types';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import {
|
||||
useMessages,
|
||||
usePropertyFieldsQuery,
|
||||
useSessionDataPropertiesQuery,
|
||||
} from '@/components/hooks';
|
||||
import { PropertyChart } from '@/components/property-data/PropertyChart';
|
||||
import { PropertyDateChart } from '@/components/property-data/PropertyDateChart';
|
||||
import { PropertyFilterBar } from '@/components/property-data/PropertyFilterBar';
|
||||
import { PropertyFilterButton } from '@/components/property-data/PropertyFilterButton';
|
||||
import { PropertyNumericChart } from '@/components/property-data/PropertyNumericChart';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { DATA_TYPE } from '@/lib/constants';
|
||||
import type { PropertyFilter } from '@/lib/types';
|
||||
import { SessionDataPivotTable } from '../session-data/SessionDataPivotTable';
|
||||
import { SessionPropertyChart } from '../session-data/SessionPropertyChart';
|
||||
|
||||
@@ -111,7 +115,9 @@ export function SessionProperties({ websiteId }: { websiteId: string }) {
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
{propertyName && <PropertyFilterBar filters={propertyFilters} onChange={setPropertyFilters} />}
|
||||
{propertyName && (
|
||||
<PropertyFilterBar filters={propertyFilters} onChange={setPropertyFilters} />
|
||||
)}
|
||||
{propertyName && selectedProperty?.dataType === DATA_TYPE.number && (
|
||||
<PropertyNumericChart
|
||||
source="session"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DataColumn, DataTable, type DataTableProps } from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import { Avatar } from '@/components/common/Avatar';
|
||||
import { DateDistance } from '@/components/common/DateDistance';
|
||||
import Link from '@/components/common/Link';
|
||||
import { TypeIcon } from '@/components/common/TypeIcon';
|
||||
import { useFormat, useMessages } from '@/components/hooks';
|
||||
|
||||
@@ -17,7 +17,11 @@ export function SessionsTable({
|
||||
<DataTable {...props}>
|
||||
<DataColumn id="id" label={t(labels.session)} width="100px">
|
||||
{(row: any) => (
|
||||
<Link href={getSessionHref ? getSessionHref(row) : `/websites/${websiteId}/sessions/${row.id}`}>
|
||||
<Link
|
||||
href={
|
||||
getSessionHref ? getSessionHref(row) : `/websites/${websiteId}/sessions/${row.id}`
|
||||
}
|
||||
>
|
||||
<Avatar seed={row.id} size={32} />
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -137,21 +137,21 @@ export function ShareEditForm({
|
||||
<TextField autoComplete="off" autoFocus={!isEditing} />
|
||||
</FormField>
|
||||
<Grid columns={{ base: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' }} gap="3">
|
||||
<FormField label={t(labels.filters)} name="allowFilter">
|
||||
<Switch
|
||||
isSelected={watch('allowFilter')}
|
||||
onChange={value => setValue('allowFilter', value, { shouldDirty: true })}
|
||||
>
|
||||
{t(labels.filtersEnabled)}
|
||||
</Switch>
|
||||
</FormField>
|
||||
<FormField label={t(labels.theme)} name="theme">
|
||||
<ThemeModeSelector
|
||||
value={watch('theme')}
|
||||
includeSystem
|
||||
onChange={value => setValue('theme', value, { shouldDirty: true })}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label={t(labels.filters)} name="allowFilter">
|
||||
<Switch
|
||||
isSelected={watch('allowFilter')}
|
||||
onChange={value => setValue('allowFilter', value, { shouldDirty: true })}
|
||||
>
|
||||
{t(labels.filtersEnabled)}
|
||||
</Switch>
|
||||
</FormField>
|
||||
<FormField label={t(labels.theme)} name="theme">
|
||||
<ThemeModeSelector
|
||||
value={watch('theme')}
|
||||
includeSystem
|
||||
onChange={value => setValue('theme', value, { shouldDirty: true })}
|
||||
/>
|
||||
</FormField>
|
||||
</Grid>
|
||||
<ListSeparator />
|
||||
<Grid columns={{ base: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' }} gap="3">
|
||||
|
||||
@@ -93,14 +93,18 @@ export function WebsiteReplaySettings({ websiteId }: { websiteId: string }) {
|
||||
const previous = replayEnabled;
|
||||
|
||||
setReplayEnabled(value);
|
||||
await saveRecorderConfig(getNextConfig({ replayEnabled: value }), () => setReplayEnabled(previous));
|
||||
await saveRecorderConfig(getNextConfig({ replayEnabled: value }), () =>
|
||||
setReplayEnabled(previous),
|
||||
);
|
||||
};
|
||||
|
||||
const handleHeatmapToggle = async (value: boolean) => {
|
||||
const previous = heatmapEnabled;
|
||||
|
||||
setHeatmapEnabled(value);
|
||||
await saveRecorderConfig(getNextConfig({ heatmapEnabled: value }), () => setHeatmapEnabled(previous));
|
||||
await saveRecorderConfig(getNextConfig({ heatmapEnabled: value }), () =>
|
||||
setHeatmapEnabled(previous),
|
||||
);
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Row } from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import { IconLabel } from '@/components/common/IconLabel';
|
||||
import Link from '@/components/common/Link';
|
||||
import { PageHeader } from '@/components/common/PageHeader';
|
||||
import { useMessages, useNavigation, useWebsite } from '@/components/hooks';
|
||||
import { ArrowLeft, Globe } from '@/components/icons';
|
||||
|
||||
@@ -34,7 +34,14 @@ export function WebsiteTrackingCode({
|
||||
<Column gap>
|
||||
<Label>{t(labels.trackingCode)}</Label>
|
||||
<Text color="muted">{t(messages.trackingCode)}</Text>
|
||||
<TextField value={code} isReadOnly allowCopy asTextArea resize="none" className="code-textarea" />
|
||||
<TextField
|
||||
value={code}
|
||||
isReadOnly
|
||||
allowCopy
|
||||
asTextArea
|
||||
resize="none"
|
||||
className="code-textarea"
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ import { anyObjectParam, filterParams, pagingParams } from '@/lib/schema';
|
||||
import { canUpdateBoard, canViewBoard } from '@/permissions';
|
||||
import { createShare, getSharesByEntityId } from '@/queries/prisma';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ boardId: string }> },
|
||||
) {
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ boardId: string }> }) {
|
||||
const schema = z.object({
|
||||
...filterParams,
|
||||
...pagingParams,
|
||||
@@ -39,10 +36,7 @@ export async function GET(
|
||||
return json(data);
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ boardId: string }> },
|
||||
) {
|
||||
export async function POST(request: Request, { params }: { params: Promise<{ boardId: string }> }) {
|
||||
const schema = z.object({
|
||||
name: z.string().max(200),
|
||||
parameters: anyObjectParam.optional(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { createBoard, getBoard, updateBoard } from '@/queries/prisma';
|
||||
import { z } from 'zod';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { auth, error } = await parseRequest(request);
|
||||
|
||||
@@ -8,10 +8,7 @@ import { anyObjectParam, filterParams, pagingParams } from '@/lib/schema';
|
||||
import { canUpdateLink, canViewLink } from '@/permissions';
|
||||
import { createShare, getSharesByEntityId } from '@/queries/prisma';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ linkId: string }> },
|
||||
) {
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ linkId: string }> }) {
|
||||
const schema = z.object({
|
||||
...filterParams,
|
||||
...pagingParams,
|
||||
@@ -39,10 +36,7 @@ export async function GET(
|
||||
return json(data);
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ linkId: string }> },
|
||||
) {
|
||||
export async function POST(request: Request, { params }: { params: Promise<{ linkId: string }> }) {
|
||||
const schema = z.object({
|
||||
name: z.string().max(200),
|
||||
parameters: anyObjectParam.optional(),
|
||||
|
||||
@@ -8,10 +8,7 @@ import { anyObjectParam, filterParams, pagingParams } from '@/lib/schema';
|
||||
import { canUpdatePixel, canViewPixel } from '@/permissions';
|
||||
import { createShare, getSharesByEntityId } from '@/queries/prisma';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ pixelId: string }> },
|
||||
) {
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ pixelId: string }> }) {
|
||||
const schema = z.object({
|
||||
...filterParams,
|
||||
...pagingParams,
|
||||
@@ -39,10 +36,7 @@ export async function GET(
|
||||
return json(data);
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ pixelId: string }> },
|
||||
) {
|
||||
export async function POST(request: Request, { params }: { params: Promise<{ pixelId: string }> }) {
|
||||
const schema = z.object({
|
||||
name: z.string().max(200),
|
||||
parameters: anyObjectParam.optional(),
|
||||
|
||||
@@ -3,8 +3,8 @@ import { z } from 'zod';
|
||||
import { REALTIME_RANGE } from '@/lib/constants';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { canViewWebsiteSection } from '@/permissions';
|
||||
import { filterParams, timezoneParam, unitParam } from '@/lib/schema';
|
||||
import { canViewWebsiteSection } from '@/permissions';
|
||||
import { getRealtimeData } from '@/queries/sql';
|
||||
|
||||
export async function GET(
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { isbot } from 'isbot';
|
||||
import { serializeError } from 'serialize-error';
|
||||
import { z } from 'zod';
|
||||
import { HEATMAP_EVENT_TYPE } from '@/lib/constants';
|
||||
import { secret } from '@/lib/crypto';
|
||||
import { getClientInfo, hasBlockedIp } from '@/lib/detect';
|
||||
import { parseToken } from '@/lib/jwt';
|
||||
import { fetchAccount, fetchTeam } from '@/lib/load';
|
||||
import { HEATMAP_EVENT_TYPE } from '@/lib/constants';
|
||||
import { getRecorderConfig } from '@/lib/recorder';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { badRequest, forbidden, json, serverError } from '@/lib/response';
|
||||
@@ -185,15 +185,15 @@ export async function POST(request: Request) {
|
||||
visitId,
|
||||
eventType: event.type === 'click' ? HEATMAP_EVENT_TYPE.click : HEATMAP_EVENT_TYPE.scroll,
|
||||
nodeId: null,
|
||||
x: event.type === 'click' ? event.x ?? null : null,
|
||||
y: event.type === 'click' ? event.y ?? null : null,
|
||||
pageX: event.type === 'click' ? event.pageX ?? null : null,
|
||||
pageY: event.type === 'click' ? event.pageY ?? null : null,
|
||||
x: event.type === 'click' ? (event.x ?? null) : null,
|
||||
y: event.type === 'click' ? (event.y ?? null) : null,
|
||||
pageX: event.type === 'click' ? (event.pageX ?? null) : null,
|
||||
pageY: event.type === 'click' ? (event.pageY ?? null) : null,
|
||||
pageW: event.pageW ?? null,
|
||||
viewportW: event.viewportW ?? null,
|
||||
viewportH: event.viewportH ?? null,
|
||||
pageH: event.pageH ?? null,
|
||||
scrollPct: event.type === 'scroll' ? event.scrollPct ?? null : null,
|
||||
scrollPct: event.type === 'scroll' ? (event.scrollPct ?? null) : null,
|
||||
urlPath: getUrlPath(event.url),
|
||||
createdAt: new Date(event.timestamp ?? fallbackMs),
|
||||
replayChunkIndex: null,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getRecorderConfig } from '@/lib/recorder';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getWebsite } from '@/queries/prisma';
|
||||
|
||||
export async function GET(
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { headers } from 'next/headers';
|
||||
import { Inter } from 'next/font/google';
|
||||
import { headers } from 'next/headers';
|
||||
import { Suspense } from 'react';
|
||||
import { getBaseUrl } from '@/lib/get-base-url';
|
||||
import { Providers } from './Providers';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
import { useShareTokenQuery } from '@/components/hooks';
|
||||
import { ENTITY_TYPE } from '@/lib/constants';
|
||||
import type { ShareParameters, WhiteLabel } from '@/lib/types';
|
||||
import { Loading } from '@umami/react-zen';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { createContext, type ReactNode, useEffect } from 'react';
|
||||
import { useShareTokenQuery } from '@/components/hooks';
|
||||
import { ENTITY_TYPE } from '@/lib/constants';
|
||||
import type { ShareParameters, WhiteLabel } from '@/lib/types';
|
||||
|
||||
export interface ShareData {
|
||||
shareId: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
import { Icon, Row, Text } from '@umami/react-zen';
|
||||
import { useShare } from '@/components/hooks';
|
||||
import { Logo } from '@/components/svg';
|
||||
import { Icon, Row, Text } from '@umami/react-zen';
|
||||
|
||||
const LOGO_SIZE = { sm: 24, md: 32, lg: 40 };
|
||||
const TEXT_SIZE = { sm: 'sm', md: 'base', lg: 'lg' } as const;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
import { useShare } from '@/components/hooks';
|
||||
import { Column, Row } from '@umami/react-zen';
|
||||
import { useShare } from '@/components/hooks';
|
||||
import { ShareBranding } from './ShareBranding';
|
||||
|
||||
export function ShareFooter() {
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
import { IconLabel } from '@/components/common/IconLabel';
|
||||
import { useMessages, useNavigation, useShare } from '@/components/hooks';
|
||||
import { AlignEndHorizontal, Clock, Eye, PanelLeft, Sheet, Tag, User } from '@/components/icons';
|
||||
import { LanguageButton } from '@/components/input/LanguageButton';
|
||||
import { PreferencesButton } from '@/components/input/PreferencesButton';
|
||||
import { allowShareFilter, excludeShareFilterParam, getShareTheme } from '@/lib/share';
|
||||
import { Funnel, Gauge, Lightning, Magnet, Money, Network, Path, Target } from '@/components/svg';
|
||||
import { buildPath } from '@/lib/url';
|
||||
import {
|
||||
Button,
|
||||
Column,
|
||||
@@ -17,7 +9,15 @@ import {
|
||||
Tooltip,
|
||||
TooltipTrigger,
|
||||
} from '@umami/react-zen';
|
||||
import { IconLabel } from '@/components/common/IconLabel';
|
||||
import Link from '@/components/common/Link';
|
||||
import { useMessages, useNavigation, useShare } from '@/components/hooks';
|
||||
import { AlignEndHorizontal, Clock, Eye, PanelLeft, Sheet, Tag, User } from '@/components/icons';
|
||||
import { LanguageButton } from '@/components/input/LanguageButton';
|
||||
import { PreferencesButton } from '@/components/input/PreferencesButton';
|
||||
import { Funnel, Gauge, Lightning, Magnet, Money, Network, Path, Target } from '@/components/svg';
|
||||
import { allowShareFilter, excludeShareFilterParam, getShareTheme } from '@/lib/share';
|
||||
import { buildPath } from '@/lib/url';
|
||||
import { ShareBranding } from './ShareBranding';
|
||||
|
||||
export function ShareNav({
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
'use client';
|
||||
import { Column, Grid, Row, useTheme } from '@umami/react-zen';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { BoardViewPage } from '@/app/(main)/boards/[boardId]/BoardViewPage';
|
||||
import { LinkPage } from '@/app/(main)/links/[linkId]/LinkPage';
|
||||
import { PixelPage } from '@/app/(main)/pixels/[pixelId]/PixelPage';
|
||||
@@ -7,10 +10,10 @@ import { BreakdownPage } from '@/app/(main)/websites/[websiteId]/(reports)/break
|
||||
import { FunnelsPage } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage';
|
||||
import { GoalsPage } from '@/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage';
|
||||
import { JourneysPage } from '@/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage';
|
||||
import { PerformancePage } from '@/app/(main)/websites/[websiteId]/(reports)/performance/PerformancePage';
|
||||
import { RetentionPage } from '@/app/(main)/websites/[websiteId]/(reports)/retention/RetentionPage';
|
||||
import { RevenuePage } from '@/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage';
|
||||
import { UTMPage } from '@/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage';
|
||||
import { PerformancePage } from '@/app/(main)/websites/[websiteId]/(reports)/performance/PerformancePage';
|
||||
import { ComparePage } from '@/app/(main)/websites/[websiteId]/compare/ComparePage';
|
||||
import { EventsPage } from '@/app/(main)/websites/[websiteId]/events/EventsPage';
|
||||
import { RealtimePage } from '@/app/(main)/websites/[websiteId]/realtime/RealtimePage';
|
||||
@@ -23,9 +26,6 @@ import { useShare } from '@/components/hooks';
|
||||
import { MobileMenuButton } from '@/components/input/MobileMenuButton';
|
||||
import { ENTITY_TYPE } from '@/lib/constants';
|
||||
import { getShareTheme } from '@/lib/share';
|
||||
import { Column, Grid, Row, useTheme } from '@umami/react-zen';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ShareFooter } from './ShareFooter';
|
||||
import { ShareNav } from './ShareNav';
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useTheme } from '@umami/react-zen';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { Chart, type ChartProps } from '@/components/charts/Chart';
|
||||
import { ChartTooltip } from '@/components/charts/ChartTooltip';
|
||||
import { useLocale } from '@/components/hooks';
|
||||
@@ -5,8 +7,6 @@ import { renderNumberLabels } from '@/lib/charts';
|
||||
import { getThemeColors } from '@/lib/colors';
|
||||
import { DATE_FORMATS, formatDate } from '@/lib/date';
|
||||
import { formatLongCurrency, formatLongNumber } from '@/lib/format';
|
||||
import { useTheme } from '@umami/react-zen';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
|
||||
const MemoChart = memo(Chart);
|
||||
|
||||
|
||||
@@ -127,31 +127,38 @@ function DistributionBarChartComponent({
|
||||
[chartData.labels, colors, horizontal, stacked],
|
||||
);
|
||||
|
||||
const handleTooltip = useCallback(({ tooltip }: { tooltip: any }) => {
|
||||
const { opacity, labelColors, dataPoints } = tooltip;
|
||||
const point = dataPoints?.[0];
|
||||
const nextTooltip = opacity
|
||||
? {
|
||||
title: (point?.label ?? '').toString(),
|
||||
color: labelColors?.[0]?.backgroundColor,
|
||||
value: `${formatLongNumber(
|
||||
Number(horizontal ? point?.raw?.x ?? point?.raw ?? 0 : point?.raw?.y ?? point?.raw ?? 0),
|
||||
)}${point?.dataset?.label ? ` ${point.dataset.label}` : ''}`,
|
||||
const handleTooltip = useCallback(
|
||||
({ tooltip }: { tooltip: any }) => {
|
||||
const { opacity, labelColors, dataPoints } = tooltip;
|
||||
const point = dataPoints?.[0];
|
||||
const nextTooltip = opacity
|
||||
? {
|
||||
title: (point?.label ?? '').toString(),
|
||||
color: labelColors?.[0]?.backgroundColor,
|
||||
value: `${formatLongNumber(
|
||||
Number(
|
||||
horizontal
|
||||
? (point?.raw?.x ?? point?.raw ?? 0)
|
||||
: (point?.raw?.y ?? point?.raw ?? 0),
|
||||
),
|
||||
)}${point?.dataset?.label ? ` ${point.dataset.label}` : ''}`,
|
||||
}
|
||||
: null;
|
||||
|
||||
setTooltip(prev => {
|
||||
if (
|
||||
prev?.title === nextTooltip?.title &&
|
||||
prev?.color === nextTooltip?.color &&
|
||||
prev?.value === nextTooltip?.value
|
||||
) {
|
||||
return prev;
|
||||
}
|
||||
: null;
|
||||
|
||||
setTooltip(prev => {
|
||||
if (
|
||||
prev?.title === nextTooltip?.title &&
|
||||
prev?.color === nextTooltip?.color &&
|
||||
prev?.value === nextTooltip?.value
|
||||
) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return nextTooltip;
|
||||
});
|
||||
}, [horizontal]);
|
||||
return nextTooltip;
|
||||
});
|
||||
},
|
||||
[horizontal],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -54,29 +54,29 @@
|
||||
background: var(--text-muted);
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .good {
|
||||
:global([data-theme="dark"]) .good {
|
||||
color: #86efac;
|
||||
background: rgba(22, 163, 74, 0.15);
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .good .dot {
|
||||
:global([data-theme="dark"]) .good .dot {
|
||||
background: #4ade80;
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .warning {
|
||||
:global([data-theme="dark"]) .warning {
|
||||
color: #fde047;
|
||||
background: rgba(202, 138, 4, 0.15);
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .warning .dot {
|
||||
:global([data-theme="dark"]) .warning .dot {
|
||||
background: #facc15;
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .danger {
|
||||
:global([data-theme="dark"]) .danger {
|
||||
color: #fca5a5;
|
||||
background: rgba(220, 38, 38, 0.15);
|
||||
}
|
||||
|
||||
:global([data-theme='dark']) .danger .dot {
|
||||
:global([data-theme="dark"]) .danger .dot {
|
||||
background: #f87171;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,7 @@ import { Button, Icon } from '@umami/react-zen';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Check, Copy } from '@/components/icons';
|
||||
|
||||
export function CopyButton({
|
||||
value,
|
||||
label = 'Copy',
|
||||
}: {
|
||||
value: string;
|
||||
label?: string;
|
||||
}) {
|
||||
export function CopyButton({ value, label = 'Copy' }: { value: string; label?: string }) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const timeoutRef = useRef<number | null>(null);
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ export function DataGrid({
|
||||
return stored === 'table' || stored === 'cards' ? stored : null;
|
||||
});
|
||||
|
||||
const displayMode: DisplayMode | undefined = isMobile ? 'cards' : userDisplayMode ?? undefined;
|
||||
const displayMode: DisplayMode | undefined = isMobile ? 'cards' : (userDisplayMode ?? undefined);
|
||||
|
||||
const handleToggleDisplayMode = () => {
|
||||
const next: DisplayMode = displayMode === 'cards' ? 'table' : 'cards';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Icon, Row, Text } from '@umami/react-zen';
|
||||
import Link, { type LinkProps } from '@/components/common/Link';
|
||||
import type { ReactNode } from 'react';
|
||||
import Link, { type LinkProps } from '@/components/common/Link';
|
||||
import { ExternalLink as LinkIcon } from '@/components/icons';
|
||||
|
||||
export function ExternalLink({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Icon, Row, Text } from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import { type HTMLAttributes, type ReactNode, useState } from 'react';
|
||||
import Link from '@/components/common/Link';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
import { ExternalLink } from '@/components/icons';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Button, type ButtonProps } from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import type { ReactNode } from 'react';
|
||||
import Link from '@/components/common/Link';
|
||||
import { useLocale } from '@/components/hooks';
|
||||
|
||||
export interface LinkButtonProps extends ButtonProps {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Column, Heading, Row, Text } from '@umami/react-zen';
|
||||
import Link from '@/components/common/Link';
|
||||
import { IconLabel } from '@/components/common/IconLabel';
|
||||
import Link from '@/components/common/Link';
|
||||
|
||||
interface NavMenuData {
|
||||
id: string;
|
||||
|
||||
@@ -11,13 +11,7 @@ export interface PagerProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Pager({
|
||||
page,
|
||||
pageSize,
|
||||
count,
|
||||
isCapped,
|
||||
onPageChange,
|
||||
}: PagerProps) {
|
||||
export function Pager({ page, pageSize, count, isCapped, onPageChange }: PagerProps) {
|
||||
const { t, labels } = useMessages();
|
||||
const maxPage = pageSize && count ? Math.ceil(+count / +pageSize) : 0;
|
||||
const lastPage = page === maxPage;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
import { Icon } from '@umami/react-zen';
|
||||
import { ChevronDown, ChevronUp } from '@/components/icons';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useNavigation } from '@/components/hooks';
|
||||
import { ChevronDown, ChevronUp } from '@/components/icons';
|
||||
|
||||
type SortDirection = 'asc' | 'desc';
|
||||
|
||||
@@ -13,11 +13,7 @@ export interface SortableLabelProps {
|
||||
defaultDirection?: SortDirection;
|
||||
}
|
||||
|
||||
export function SortableLabel({
|
||||
label,
|
||||
sortKey,
|
||||
defaultDirection = 'asc',
|
||||
}: SortableLabelProps) {
|
||||
export function SortableLabel({ label, sortKey, defaultDirection = 'asc' }: SortableLabelProps) {
|
||||
const { router, query, updateParams } = useNavigation();
|
||||
const isActive = query.orderBy === sortKey;
|
||||
const isDescending = query.sortDescending === 'true';
|
||||
|
||||
@@ -41,16 +41,16 @@ export * from './queries/useReplaysQuery';
|
||||
export * from './queries/useReportQuery';
|
||||
export * from './queries/useReportsQuery';
|
||||
export * from './queries/useResultQuery';
|
||||
export * from './queries/useRevenueSessionsQuery';
|
||||
export * from './queries/useRevenueMetricsQuery';
|
||||
export * from './queries/useRevenueChartQuery';
|
||||
export * from './queries/useRevenueMetricsQuery';
|
||||
export * from './queries/useRevenueSessionsQuery';
|
||||
export * from './queries/useRevenueStatsQuery';
|
||||
export * from './queries/useSavedReplaysQuery';
|
||||
export * from './queries/useSessionActivityQuery';
|
||||
export * from './queries/useSessionDataPropertiesQuery';
|
||||
export * from './queries/useSessionDataPivotQuery';
|
||||
export * from './queries/useSessionDataQuery';
|
||||
export * from './queries/useSessionDataActivityStatsQuery';
|
||||
export * from './queries/useSessionDataPivotQuery';
|
||||
export * from './queries/useSessionDataPropertiesQuery';
|
||||
export * from './queries/useSessionDataQuery';
|
||||
export * from './queries/useSessionDataValuesQuery';
|
||||
export * from './queries/useSessionReplaysQuery';
|
||||
export * from './queries/useShareTokenQuery';
|
||||
|
||||
@@ -3,10 +3,7 @@ import { useApi } from '../useApi';
|
||||
import { useModified } from '../useModified';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
|
||||
export function useLinkSharesQuery(
|
||||
{ linkId }: { linkId: string },
|
||||
options?: ReactQueryOptions,
|
||||
) {
|
||||
export function useLinkSharesQuery({ linkId }: { linkId: string }, options?: ReactQueryOptions) {
|
||||
const { modified } = useModified('shares');
|
||||
const { get } = useApi();
|
||||
|
||||
|
||||
@@ -3,10 +3,7 @@ import { useApi } from '../useApi';
|
||||
import { useModified } from '../useModified';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
|
||||
export function usePixelSharesQuery(
|
||||
{ pixelId }: { pixelId: string },
|
||||
options?: ReactQueryOptions,
|
||||
) {
|
||||
export function usePixelSharesQuery({ pixelId }: { pixelId: string }, options?: ReactQueryOptions) {
|
||||
const { modified } = useModified('shares');
|
||||
const { get } = useApi();
|
||||
|
||||
|
||||
@@ -20,7 +20,17 @@ export function usePropertyArraySeriesQuery(
|
||||
return useQuery<EventDataSeriesPoint[]>({
|
||||
queryKey: [
|
||||
`websites:${source}-data:array-series`,
|
||||
{ websiteId, propertyName, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params },
|
||||
{
|
||||
websiteId,
|
||||
propertyName,
|
||||
eventName,
|
||||
propertyFilters,
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...params,
|
||||
},
|
||||
],
|
||||
queryFn: () =>
|
||||
get(
|
||||
|
||||
@@ -21,7 +21,18 @@ export function usePropertyNumericSeriesQuery(
|
||||
return useQuery<any>({
|
||||
queryKey: [
|
||||
`websites:${source}-data:numeric-series`,
|
||||
{ websiteId, propertyName, metric, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params },
|
||||
{
|
||||
websiteId,
|
||||
propertyName,
|
||||
metric,
|
||||
eventName,
|
||||
propertyFilters,
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...params,
|
||||
},
|
||||
],
|
||||
queryFn: () =>
|
||||
get(
|
||||
|
||||
@@ -20,7 +20,17 @@ export function usePropertySeriesQuery(
|
||||
return useQuery<EventDataSeriesPoint[]>({
|
||||
queryKey: [
|
||||
`websites:${source}-data:property-series`,
|
||||
{ websiteId, propertyName, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params },
|
||||
{
|
||||
websiteId,
|
||||
propertyName,
|
||||
eventName,
|
||||
propertyFilters,
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...params,
|
||||
},
|
||||
],
|
||||
queryFn: () =>
|
||||
get(
|
||||
|
||||
@@ -21,7 +21,18 @@ export function usePropertyValuesQuery(
|
||||
return useQuery<any>({
|
||||
queryKey: [
|
||||
`websites:${source}-data:values`,
|
||||
{ websiteId, propertyName, dataType, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params },
|
||||
{
|
||||
websiteId,
|
||||
propertyName,
|
||||
dataType,
|
||||
eventName,
|
||||
propertyFilters,
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...params,
|
||||
},
|
||||
],
|
||||
queryFn: () =>
|
||||
get(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user