mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 12:47:13 +01:00
Refactor filter handling for queries.
This commit is contained in:
parent
5b300f1ff5
commit
ee6c68d27c
107 changed files with 731 additions and 835 deletions
|
|
@ -2,6 +2,7 @@
|
|||
import { Button, Grid, Column, Heading } from '@umami/react-zen';
|
||||
import Link from 'next/link';
|
||||
import Script from 'next/script';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { PageBody } from '@/components/common/PageBody';
|
||||
import { EventsChart } from '@/components/metrics/EventsChart';
|
||||
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
|
||||
|
|
@ -115,87 +116,91 @@ export function TestConsolePage({ websiteId }: { websiteId: string }) {
|
|||
src={`${process.env.basePath || ''}/script.js`}
|
||||
data-cache="true"
|
||||
/>
|
||||
<Grid columns="1fr 1fr 1fr" gap>
|
||||
<Column gap>
|
||||
<Heading>Page links</Heading>
|
||||
<div>
|
||||
<Link href={`/console/${websiteId}?page=1`}>page one</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={`/console/${websiteId}?page=2 `}>page two</Link>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://www.google.com" data-umami-event="external-link-direct">
|
||||
external link (direct)
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href="https://www.google.com"
|
||||
data-umami-event="external-link-tab"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
external link (tab)
|
||||
</a>
|
||||
</div>
|
||||
</Column>
|
||||
<Column gap>
|
||||
<Heading>Click events</Heading>
|
||||
<Button id="send-event-button" data-umami-event="button-click" variant="primary">
|
||||
Send event
|
||||
</Button>
|
||||
<Button
|
||||
id="send-event-data-button"
|
||||
data-umami-event="button-click"
|
||||
data-umami-event-name="bob"
|
||||
data-umami-event-id="123"
|
||||
variant="primary"
|
||||
>
|
||||
Send event with data
|
||||
</Button>
|
||||
<Button
|
||||
id="generate-revenue-button"
|
||||
data-umami-event="checkout-cart"
|
||||
data-umami-event-revenue={(Math.random() * 10000).toFixed(2).toString()}
|
||||
data-umami-event-currency="USD"
|
||||
variant="primary"
|
||||
>
|
||||
Generate revenue data
|
||||
</Button>
|
||||
<Button
|
||||
id="button-with-div-button"
|
||||
data-umami-event="button-click"
|
||||
data-umami-event-name={'bob'}
|
||||
data-umami-event-id="123"
|
||||
variant="primary"
|
||||
>
|
||||
<div>Button with div</div>
|
||||
</Button>
|
||||
<div data-umami-event="div-click">DIV with attribute</div>
|
||||
<div data-umami-event="div-click-one">
|
||||
<div data-umami-event="div-click-two">
|
||||
<div data-umami-event="div-click-three">Nested DIV</div>
|
||||
<Panel>
|
||||
<Grid columns="1fr 1fr 1fr" gap>
|
||||
<Column gap>
|
||||
<Heading>Page links</Heading>
|
||||
<div>
|
||||
<Link href={`/console/${websiteId}?page=1`}>page one</Link>
|
||||
</div>
|
||||
</div>
|
||||
</Column>
|
||||
<Column gap>
|
||||
<Heading>Javascript events</Heading>
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunScript}>
|
||||
Run script
|
||||
</Button>
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunIdentify}>
|
||||
Run identify
|
||||
</Button>
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunRevenue}>
|
||||
Revenue script
|
||||
</Button>
|
||||
</Column>
|
||||
</Grid>
|
||||
<div>
|
||||
<Link href={`/console/${websiteId}?page=2 `}>page two</Link>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://www.google.com" data-umami-event="external-link-direct">
|
||||
external link (direct)
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href="https://www.google.com"
|
||||
data-umami-event="external-link-tab"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
external link (tab)
|
||||
</a>
|
||||
</div>
|
||||
</Column>
|
||||
<Column gap>
|
||||
<Heading>Click events</Heading>
|
||||
<Button id="send-event-button" data-umami-event="button-click" variant="primary">
|
||||
Send event
|
||||
</Button>
|
||||
<Button
|
||||
id="send-event-data-button"
|
||||
data-umami-event="button-click"
|
||||
data-umami-event-name="bob"
|
||||
data-umami-event-id="123"
|
||||
variant="primary"
|
||||
>
|
||||
Send event with data
|
||||
</Button>
|
||||
<Button
|
||||
id="generate-revenue-button"
|
||||
data-umami-event="checkout-cart"
|
||||
data-umami-event-revenue={(Math.random() * 10000).toFixed(2).toString()}
|
||||
data-umami-event-currency="USD"
|
||||
variant="primary"
|
||||
>
|
||||
Generate revenue data
|
||||
</Button>
|
||||
<Button
|
||||
id="button-with-div-button"
|
||||
data-umami-event="button-click"
|
||||
data-umami-event-name={'bob'}
|
||||
data-umami-event-id="123"
|
||||
variant="primary"
|
||||
>
|
||||
<div>Button with div</div>
|
||||
</Button>
|
||||
<div data-umami-event="div-click">DIV with attribute</div>
|
||||
<div data-umami-event="div-click-one">
|
||||
<div data-umami-event="div-click-two">
|
||||
<div data-umami-event="div-click-three">Nested DIV</div>
|
||||
</div>
|
||||
</div>
|
||||
</Column>
|
||||
<Column gap>
|
||||
<Heading>Javascript events</Heading>
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunScript}>
|
||||
Run script
|
||||
</Button>
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunIdentify}>
|
||||
Run identify
|
||||
</Button>
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunRevenue}>
|
||||
Revenue script
|
||||
</Button>
|
||||
</Column>
|
||||
</Grid>
|
||||
</Panel>
|
||||
<Heading>Pageviews</Heading>
|
||||
<WebsiteChart websiteId={websiteId} />
|
||||
<Heading>Events</Heading>
|
||||
<EventsChart websiteId={websiteId} />
|
||||
<Panel>
|
||||
<EventsChart websiteId={websiteId} />
|
||||
</Panel>
|
||||
</Column>
|
||||
</PageBody>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export function PasswordEditForm({ onSave, onClose }) {
|
|||
});
|
||||
};
|
||||
|
||||
const samePassword = (value: string, values: { [key: string]: any }) => {
|
||||
const samePassword = (value: string, values: Record<string, any>) => {
|
||||
if (value !== values.newPassword) {
|
||||
return formatMessage(messages.noMatchPassword);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { WebsitesTable } from '@/app/(main)/settings/websites/WebsitesTable';
|
||||
import { DataGrid } from '@/components/common/DataGrid';
|
||||
import { useWebsites } from '@/components/hooks';
|
||||
import { useWebsitesQuery } from '@/components/hooks';
|
||||
|
||||
export function UserWebsites({ userId }) {
|
||||
const queryResult = useWebsites({ userId });
|
||||
const queryResult = useWebsitesQuery({ userId });
|
||||
|
||||
return (
|
||||
<DataGrid queryResult={queryResult}>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { WebsitesTable } from '@/app/(main)/settings/websites/WebsitesTable';
|
||||
import { DataGrid } from '@/components/common/DataGrid';
|
||||
import { useWebsites } from '@/components/hooks';
|
||||
import { useWebsitesQuery } from '@/components/hooks';
|
||||
|
||||
export function WebsitesDataTable({
|
||||
teamId,
|
||||
|
|
@ -16,10 +16,10 @@ export function WebsitesDataTable({
|
|||
showActions?: boolean;
|
||||
children?: ReactNode;
|
||||
}) {
|
||||
const queryResult = useWebsites({ teamId });
|
||||
const queryResult = useWebsitesQuery({ teamId });
|
||||
|
||||
return (
|
||||
<DataGrid queryResult={queryResult} renderEmpty={() => children}>
|
||||
<DataGrid queryResult={queryResult} renderEmpty={() => children} allowSearch allowPaging>
|
||||
{({ data }) => (
|
||||
<WebsitesTable
|
||||
teamId={teamId}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export function WebsitesTable({
|
|||
return (
|
||||
<DataTable data={data}>
|
||||
<DataColumn id="name" label={formatMessage(labels.name)}>
|
||||
{(row: any) => <Link href={renderUrl(`/websites/${row.id}`)}>{row.name}</Link>}
|
||||
{(row: any) => <Link href={renderUrl(`/websites/${row.id}`, false)}>{row.name}</Link>}
|
||||
</DataColumn>
|
||||
<DataColumn id="domain" label={formatMessage(labels.domain)} />
|
||||
{showActions && (
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { LoadingPanel } from '@/components/common/LoadingPanel';
|
|||
import { PageviewsChart } from '@/components/metrics/PageviewsChart';
|
||||
import { useWebsitePageviewsQuery } from '@/components/hooks/queries/useWebsitePageviewsQuery';
|
||||
import { useDateRange } from '@/components/hooks';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
|
||||
export function WebsiteChart({
|
||||
websiteId,
|
||||
|
|
@ -48,16 +47,14 @@ export function WebsiteChart({
|
|||
}, [data, startDate, endDate, unit]);
|
||||
|
||||
return (
|
||||
<Panel height="520px">
|
||||
<LoadingPanel data={data} isFetching={isFetching} isLoading={isLoading} error={error}>
|
||||
<PageviewsChart
|
||||
key={value}
|
||||
data={chartData}
|
||||
minDate={startDate}
|
||||
maxDate={endDate}
|
||||
unit={unit}
|
||||
/>
|
||||
</LoadingPanel>
|
||||
</Panel>
|
||||
<LoadingPanel data={data} isFetching={isFetching} isLoading={isLoading} error={error}>
|
||||
<PageviewsChart
|
||||
key={value}
|
||||
data={chartData}
|
||||
minDate={startDate}
|
||||
maxDate={endDate}
|
||||
unit={unit}
|
||||
/>
|
||||
</LoadingPanel>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
'use client';
|
||||
import { Column } from '@umami/react-zen';
|
||||
import { useNavigation } from '@/components/hooks';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { WebsiteChart } from './WebsiteChart';
|
||||
import { WebsiteExpandedView } from './WebsiteExpandedView';
|
||||
import { WebsiteMetricsBar } from './WebsiteMetricsBar';
|
||||
|
|
@ -16,8 +17,10 @@ export function WebsiteDetailsPage({ websiteId }: { websiteId: string }) {
|
|||
return (
|
||||
<Column gap>
|
||||
<WebsiteControls websiteId={websiteId} allowCompare={true} />
|
||||
<WebsiteMetricsBar websiteId={websiteId} showFilter={true} showChange={true} />
|
||||
<WebsiteChart websiteId={websiteId} compareMode={compare} />
|
||||
<WebsiteMetricsBar websiteId={websiteId} showChange={true} />
|
||||
<Panel>
|
||||
<WebsiteChart websiteId={websiteId} compareMode={compare} />
|
||||
</Panel>
|
||||
{!view && !compare && <WebsiteTableView websiteId={websiteId} />}
|
||||
{view && !compare && <WebsiteExpandedView websiteId={websiteId} />}
|
||||
{compare && <WebsiteCompareTables websiteId={websiteId} />}
|
||||
|
|
|
|||
|
|
@ -11,13 +11,12 @@ import {
|
|||
import { Fragment } from 'react';
|
||||
import { More, Share, Edit } from '@/components/icons';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
import { InputItem } from '@/lib/types';
|
||||
|
||||
export function WebsiteMenu({ websiteId }: { websiteId: string }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { router, updateParams, renderUrl } = useNavigation();
|
||||
|
||||
const menuItems: InputItem[] = [
|
||||
const menuItems = [
|
||||
{ id: 'share', label: formatMessage(labels.share), icon: <Share /> },
|
||||
{ id: 'edit', label: formatMessage(labels.edit), icon: <Edit />, seperator: true },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,26 +3,18 @@ import { MetricCard } from '@/components/metrics/MetricCard';
|
|||
import { MetricsBar } from '@/components/metrics/MetricsBar';
|
||||
import { formatShortTime, formatLongNumber } from '@/lib/format';
|
||||
import { useWebsiteStatsQuery } from '@/components/hooks/queries/useWebsiteStatsQuery';
|
||||
import { useWebsites } from '@/store/websites';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
|
||||
export function WebsiteMetricsBar({
|
||||
websiteId,
|
||||
showChange = false,
|
||||
compareMode = false,
|
||||
}: {
|
||||
websiteId: string;
|
||||
showChange?: boolean;
|
||||
compareMode?: boolean;
|
||||
showFilter?: boolean;
|
||||
}) {
|
||||
const { dateRange } = useDateRange(websiteId);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const dateCompare = useWebsites(state => state[websiteId]?.dateCompare);
|
||||
const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(
|
||||
websiteId,
|
||||
compareMode && dateCompare,
|
||||
);
|
||||
const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(websiteId);
|
||||
const isAllTime = dateRange.value === 'all';
|
||||
|
||||
const { pageviews, visitors, visits, bounces, totaltime, previous } = data || {};
|
||||
|
|
@ -87,8 +79,7 @@ export function WebsiteMetricsBar({
|
|||
change={change}
|
||||
formatValue={formatValue}
|
||||
reverseColors={reverseColors}
|
||||
showChange={!isAllTime && (compareMode || showChange)}
|
||||
showPrevious={!isAllTime && compareMode}
|
||||
showChange={!isAllTime}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { LoadingPanel } from '@/components/common/LoadingPanel';
|
|||
import { Panel } from '@/components/common/Panel';
|
||||
|
||||
export function GoalsPage({ websiteId }: { websiteId: string }) {
|
||||
const { result, query } = useReportsQuery({ websiteId, type: 'goal' });
|
||||
const { data, isLoading, error } = useReportsQuery({ websiteId, type: 'goal' });
|
||||
const {
|
||||
dateRange: { startDate, endDate },
|
||||
} = useDateRange(websiteId);
|
||||
|
|
@ -20,14 +20,16 @@ export function GoalsPage({ websiteId }: { websiteId: string }) {
|
|||
<SectionHeader>
|
||||
<GoalAddButton websiteId={websiteId} />
|
||||
</SectionHeader>
|
||||
<LoadingPanel data={result?.data} isLoading={query?.isLoading} error={query?.error}>
|
||||
<Grid columns="1fr 1fr" gap>
|
||||
{result?.data?.map((report: any) => (
|
||||
<Panel key={report.id}>
|
||||
<Goal {...report} startDate={startDate} endDate={endDate} />
|
||||
</Panel>
|
||||
))}
|
||||
</Grid>
|
||||
<LoadingPanel data={data} isLoading={isLoading} error={error}>
|
||||
{data && (
|
||||
<Grid columns="1fr 1fr" gap>
|
||||
{data['data'].map((report: any) => (
|
||||
<Panel key={report.id}>
|
||||
<Goal {...report} startDate={startDate} endDate={endDate} />
|
||||
</Panel>
|
||||
))}
|
||||
</Grid>
|
||||
)}
|
||||
</LoadingPanel>
|
||||
</Column>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export function UTM({ websiteId, startDate, endDate }: UTMProps) {
|
|||
);
|
||||
}
|
||||
|
||||
function toArray(data: { [key: string]: number } = {}) {
|
||||
function toArray(data: Record<string, number> = {}) {
|
||||
return Object.keys(data)
|
||||
.map(key => {
|
||||
return { name: key, value: data[key] };
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export function SessionsDataTable({
|
|||
const queryResult = useWebsiteSessionsQuery(websiteId);
|
||||
|
||||
return (
|
||||
<DataGrid queryResult={queryResult} allowSearch={true} renderEmpty={() => children}>
|
||||
<DataGrid queryResult={queryResult} renderEmpty={() => children} allowPaging>
|
||||
{({ data }) => <SessionsTable data={data} showDomain={!websiteId} />}
|
||||
</DataGrid>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { Icon, TextField, Column, Row, Label, Text } from '@umami/react-zen';
|
||||
import { useFormat, useLocale, useMessages, useRegionNames, useTimezone } from '@/components/hooks';
|
||||
import { useFormat, useLocale, useMessages, useRegionNames } from '@/components/hooks';
|
||||
import { TypeIcon } from '@/components/common/TypeIcon';
|
||||
import { Location, KeyRound, Calendar } from '@/components/icons';
|
||||
import { DateDistance } from '@/components/common/DateDistance';
|
||||
|
||||
export function SessionInfo({ data }) {
|
||||
const { locale } = useLocale();
|
||||
const { formatTimezoneDate } = useTimezone();
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { formatValue } = useFormat();
|
||||
const { getRegionName } = useRegionNames(locale);
|
||||
|
|
@ -22,11 +22,11 @@ export function SessionInfo({ data }) {
|
|||
</Info>
|
||||
|
||||
<Info label={formatMessage(labels.lastSeen)} icon={<Calendar />}>
|
||||
{formatTimezoneDate(data?.lastAt, 'PPPPpp')}
|
||||
<DateDistance date={new Date(data.lastAt)} />
|
||||
</Info>
|
||||
|
||||
<Info label={formatMessage(labels.firstSeen)} icon={<Calendar />}>
|
||||
{formatTimezoneDate(data?.firstAt, 'PPPPpp')}
|
||||
<DateDistance date={new Date(data.firstAt)} />
|
||||
</Info>
|
||||
|
||||
<Info
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { getRealtimeData } from '@/queries';
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { startOfMinute, subMinutes } from 'date-fns';
|
||||
import { REALTIME_RANGE } from '@/lib/constants';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
|
|
@ -16,15 +16,19 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { timezone } = query;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const startDate = subMinutes(startOfMinute(new Date()), REALTIME_RANGE);
|
||||
const filters = await getQueryFilters({
|
||||
...query,
|
||||
websiteId,
|
||||
startAt: subMinutes(startOfMinute(new Date()), REALTIME_RANGE).getTime(),
|
||||
endAt: Date.now(),
|
||||
});
|
||||
|
||||
const data = await getRealtimeData(websiteId, { startDate, timezone });
|
||||
const data = await getRealtimeData(websiteId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { getGoal } from '@/queries/sql/reports/getGoal';
|
||||
import { reportResultSchema } from '@/lib/schema';
|
||||
|
||||
|
|
@ -15,21 +15,22 @@ export async function POST(request: Request) {
|
|||
websiteId,
|
||||
dateRange: { startDate, endDate },
|
||||
parameters: { type, value, property, operator },
|
||||
...filters
|
||||
} = body;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = await getQueryFilters(body.filters);
|
||||
|
||||
const data = await getGoal(websiteId, {
|
||||
...filters,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
type,
|
||||
value,
|
||||
property,
|
||||
operator,
|
||||
filters,
|
||||
});
|
||||
|
||||
return json(data);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewTeam } from '@/lib/auth';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { pagingParams } from '@/lib/schema';
|
||||
import { getTeamWebsites } from '@/queries';
|
||||
|
||||
|
|
@ -20,7 +20,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ team
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const websites = await getTeamWebsites(teamId, query);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const websites = await getTeamWebsites(teamId, filters);
|
||||
|
||||
return json(websites);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { json, unauthorized } from '@/lib/response';
|
|||
import { getAllUserWebsitesIncludingTeamOwner } from '@/queries/prisma/website';
|
||||
import { getEventUsage } from '@/queries/sql/events/getEventUsage';
|
||||
import { getEventDataUsage } from '@/queries/sql/events/getEventDataUsage';
|
||||
import { parseRequest, getRequestDateRange } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ userId: string }> }) {
|
||||
const schema = z.object({
|
||||
|
|
@ -22,14 +22,14 @@ export async function GET(request: Request, { params }: { params: Promise<{ user
|
|||
}
|
||||
|
||||
const { userId } = await params;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const websites = await getAllUserWebsitesIncludingTeamOwner(userId);
|
||||
|
||||
const websiteIds = websites.map(a => a.id);
|
||||
|
||||
const websiteEventUsage = await getEventUsage(websiteIds, startDate, endDate);
|
||||
const eventDataUsage = await getEventDataUsage(websiteIds, startDate, endDate);
|
||||
const websiteEventUsage = await getEventUsage(websiteIds, filters);
|
||||
const eventDataUsage = await getEventDataUsage(websiteIds, filters);
|
||||
|
||||
const websiteUsage = websites.map(a => ({
|
||||
websiteId: a.id,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { z } from 'zod';
|
|||
import { unauthorized, json } from '@/lib/response';
|
||||
import { getUserWebsites } from '@/queries/prisma/website';
|
||||
import { pagingParams } from '@/lib/schema';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ userId: string }> }) {
|
||||
const schema = z.object({
|
||||
|
|
@ -21,7 +21,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ user
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const websites = await getUserWebsites(userId, query);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const websites = await getUserWebsites(userId, filters);
|
||||
|
||||
return json(websites);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getEventDataEvents } from '@/queries/sql/events/getEventDataEvents';
|
||||
|
|
@ -20,16 +20,16 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { event } = query;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const { event } = query;
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getEventDataEvents(websiteId, {
|
||||
startDate,
|
||||
endDate,
|
||||
...filters,
|
||||
event,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getEventDataFields } from '@/queries';
|
||||
|
|
@ -20,16 +20,14 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getEventDataFields(websiteId, {
|
||||
startDate,
|
||||
endDate,
|
||||
});
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getEventDataFields(websiteId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getEventDataProperties } from '@/queries';
|
||||
|
|
@ -21,14 +21,15 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { propertyName } = query;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getEventDataProperties(websiteId, { startDate, endDate, propertyName });
|
||||
const { propertyName } = query;
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getEventDataProperties(websiteId, { ...filters, propertyName });
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getEventDataStats } from '@/queries';
|
||||
|
|
@ -21,13 +21,14 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getEventDataStats(websiteId, { startDate, endDate });
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getEventDataStats(websiteId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getEventDataValues } from '@/queries';
|
||||
|
|
@ -22,16 +22,16 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { eventName, propertyName } = query;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const { eventName, propertyName } = query;
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getEventDataValues(websiteId, {
|
||||
startDate,
|
||||
endDate,
|
||||
...filters,
|
||||
eventName,
|
||||
propertyName,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { pagingParams } from '@/lib/schema';
|
||||
|
|
@ -22,13 +22,14 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getWebsiteEvents(websiteId, { ...query, startDate, endDate }, query);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getWebsiteEvents(websiteId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { parseRequest, getRequestDateRange, getRequestFilters } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { filterParams, timezoneParam, unitParam } from '@/lib/schema';
|
||||
|
|
@ -24,20 +24,12 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { timezone } = query;
|
||||
const { startDate, endDate, unit } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const filters = {
|
||||
...getRequestFilters(query),
|
||||
startDate,
|
||||
endDate,
|
||||
timezone,
|
||||
unit,
|
||||
};
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
|
||||
const data = await getEventMetrics(websiteId, filters);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
VIDEO_DOMAINS,
|
||||
PAID_AD_PARAMS,
|
||||
} from '@/lib/constants';
|
||||
import { getRequestFilters, getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { json, unauthorized, badRequest } from '@/lib/response';
|
||||
import { getPageviewMetrics, getSessionMetrics, getChannelMetrics } from '@/queries';
|
||||
import { filterParams } from '@/lib/schema';
|
||||
|
|
@ -45,13 +45,8 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const column = FILTER_COLUMNS[type] || type;
|
||||
const filters = {
|
||||
...getRequestFilters(query),
|
||||
startDate,
|
||||
endDate,
|
||||
};
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
|
||||
if (search) {
|
||||
filters[type] = {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getRequestFilters, getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { unitParam, timezoneParam, filterParams } from '@/lib/schema';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { dateRangeParams, filterParams } from '@/lib/schema';
|
||||
import { getCompareDate } from '@/lib/date';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { getPageviewStats, getSessionStats } from '@/queries';
|
||||
|
|
@ -11,11 +11,7 @@ export async function GET(
|
|||
{ params }: { params: Promise<{ websiteId: string }> },
|
||||
) {
|
||||
const schema = z.object({
|
||||
startAt: z.coerce.number().int(),
|
||||
endAt: z.coerce.number().int(),
|
||||
unit: unitParam,
|
||||
timezone: timezoneParam,
|
||||
compare: z.string().optional(),
|
||||
...dateRangeParams,
|
||||
...filterParams,
|
||||
});
|
||||
|
||||
|
|
@ -26,32 +22,23 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { timezone, compare } = query;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const { startDate, endDate, unit } = await getRequestDateRange(query);
|
||||
|
||||
const filters = {
|
||||
...getRequestFilters(query),
|
||||
startDate,
|
||||
endDate,
|
||||
timezone,
|
||||
unit,
|
||||
};
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
|
||||
const [pageviews, sessions] = await Promise.all([
|
||||
getPageviewStats(websiteId, filters),
|
||||
getSessionStats(websiteId, filters),
|
||||
]);
|
||||
|
||||
if (compare) {
|
||||
if (filters.compare) {
|
||||
const { startDate: compareStartDate, endDate: compareEndDate } = getCompareDate(
|
||||
compare,
|
||||
startDate,
|
||||
endDate,
|
||||
filters.compare,
|
||||
filters.startDate,
|
||||
filters.endDate,
|
||||
);
|
||||
|
||||
const [comparePageviews, compareSessions] = await Promise.all([
|
||||
|
|
@ -70,8 +57,8 @@ export async function GET(
|
|||
return json({
|
||||
pageviews,
|
||||
sessions,
|
||||
startDate,
|
||||
endDate,
|
||||
startDate: filters.startDate,
|
||||
endDate: filters.endDate,
|
||||
compare: {
|
||||
pageviews: comparePageviews,
|
||||
sessions: compareSessions,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getSessionDataProperties } from '@/queries';
|
||||
|
|
@ -22,13 +22,13 @@ export async function GET(
|
|||
|
||||
const { websiteId } = await params;
|
||||
const { propertyName } = query;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getSessionDataProperties(websiteId, { startDate, endDate, propertyName });
|
||||
const data = await getSessionDataProperties(websiteId, { ...filters, propertyName });
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { getSessionDataValues } from '@/queries';
|
||||
import { z } from 'zod';
|
||||
|
|
@ -22,15 +22,14 @@ export async function GET(
|
|||
|
||||
const { propertyName } = query;
|
||||
const { websiteId } = await params;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getSessionDataValues(websiteId, {
|
||||
startDate,
|
||||
endDate,
|
||||
...filters,
|
||||
propertyName,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { parseRequest, getRequestDateRange } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getSessionActivity } from '@/queries';
|
||||
|
|
@ -20,13 +20,14 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId, sessionId } = await params;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getSessionActivity(websiteId, sessionId, startDate, endDate);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getSessionActivity(websiteId, sessionId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { pagingParams } from '@/lib/schema';
|
||||
import { dateRangeParams, filterParams, pagingParams } from '@/lib/schema';
|
||||
import { getWebsiteSessions } from '@/queries';
|
||||
|
||||
export async function GET(
|
||||
|
|
@ -10,8 +10,8 @@ export async function GET(
|
|||
{ params }: { params: Promise<{ websiteId: string }> },
|
||||
) {
|
||||
const schema = z.object({
|
||||
startAt: z.coerce.number().int(),
|
||||
endAt: z.coerce.number().int(),
|
||||
...dateRangeParams,
|
||||
...filterParams,
|
||||
...pagingParams,
|
||||
});
|
||||
|
||||
|
|
@ -21,14 +21,15 @@ export async function GET(
|
|||
return error();
|
||||
}
|
||||
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const { websiteId } = await params;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getWebsiteSessions(websiteId, { startDate, endDate }, query);
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
|
||||
const data = await getWebsiteSessions(websiteId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { parseRequest, getRequestDateRange, getRequestFilters } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { filterParams } from '@/lib/schema';
|
||||
|
|
@ -27,15 +27,9 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const filters = getRequestFilters(query);
|
||||
|
||||
const metrics = await getWebsiteSessionStats(websiteId, {
|
||||
...filters,
|
||||
startDate,
|
||||
endDate,
|
||||
});
|
||||
const metrics = await getWebsiteSessionStats(websiteId, filters);
|
||||
|
||||
const data = Object.keys(metrics[0]).reduce((obj, key) => {
|
||||
obj[key] = {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { getRequestDateRange, parseRequest } from '@/lib/request';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { pagingParams, timezoneParam } from '@/lib/schema';
|
||||
|
|
@ -23,14 +23,14 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { timezone } = query;
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const data = await getWebsiteSessionsWeekly(websiteId, { startDate, endDate, timezone });
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const data = await getWebsiteSessionsWeekly(websiteId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
import { parseRequest, getRequestDateRange, getRequestFilters } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { getCompareDate } from '@/lib/date';
|
||||
import { filterParams } from '@/lib/schema';
|
||||
import { getWebsiteStats } from '@/queries';
|
||||
|
||||
|
|
@ -24,32 +23,20 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { compare } = query;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const { startDate: compareStartDate, endDate: compareEndDate } = getCompareDate(
|
||||
compare,
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
const filters = await getQueryFilters({ ...query, websiteId });
|
||||
|
||||
const filters = getRequestFilters(query);
|
||||
|
||||
const metrics = await getWebsiteStats(websiteId, {
|
||||
...filters,
|
||||
startDate,
|
||||
endDate,
|
||||
});
|
||||
const data = await getWebsiteStats(websiteId, filters);
|
||||
|
||||
const previous = await getWebsiteStats(websiteId, {
|
||||
...filters,
|
||||
startDate: compareStartDate,
|
||||
endDate: compareEndDate,
|
||||
startDate: filters.compareStartDate,
|
||||
endDate: filters.compareEndDate,
|
||||
});
|
||||
|
||||
return json({ ...metrics, previous });
|
||||
return json({ ...data, previous });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { z } from 'zod';
|
|||
import { canViewWebsite } from '@/lib/auth';
|
||||
import { EVENT_COLUMNS, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants';
|
||||
import { getValues } from '@/queries';
|
||||
import { parseRequest, getRequestDateRange } from '@/lib/request';
|
||||
import { parseRequest, getQueryFilters } from '@/lib/request';
|
||||
import { badRequest, json, unauthorized } from '@/lib/response';
|
||||
|
||||
export async function GET(
|
||||
|
|
@ -23,7 +23,7 @@ export async function GET(
|
|||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
const { type, search } = query;
|
||||
const { type } = query;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
|
|
@ -33,9 +33,9 @@ export async function GET(
|
|||
return badRequest('Invalid type.');
|
||||
}
|
||||
|
||||
const { startDate, endDate } = await getRequestDateRange(query);
|
||||
const filters = await getQueryFilters(query);
|
||||
|
||||
const values = await getValues(websiteId, FILTER_COLUMNS[type], startDate, endDate, search);
|
||||
const values = await getValues(websiteId, FILTER_COLUMNS[type], { ...filters });
|
||||
|
||||
return json(values.filter(n => n).sort());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue