mirror of
https://github.com/umami-software/umami.git
synced 2026-02-10 23:57:12 +01:00
Updated events/sessions pages. Added DateDistance component.
This commit is contained in:
parent
8b64029409
commit
5b300f1ff5
13 changed files with 44 additions and 35 deletions
|
|
@ -3,7 +3,6 @@ import { TabList, Tab, Tabs, TabPanel, Column } from '@umami/react-zen';
|
||||||
import { EventsTable } from '@/components/metrics/EventsTable';
|
import { EventsTable } from '@/components/metrics/EventsTable';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { EventsDataTable } from './EventsDataTable';
|
import { EventsDataTable } from './EventsDataTable';
|
||||||
import { EventsMetricsBar } from './EventsMetricsBar';
|
|
||||||
import { Panel } from '@/components/common/Panel';
|
import { Panel } from '@/components/common/Panel';
|
||||||
import { EventsChart } from '@/components/metrics/EventsChart';
|
import { EventsChart } from '@/components/metrics/EventsChart';
|
||||||
import { GridRow } from '@/components/common/GridRow';
|
import { GridRow } from '@/components/common/GridRow';
|
||||||
|
|
@ -23,7 +22,6 @@ export function EventsPage({ websiteId }) {
|
||||||
return (
|
return (
|
||||||
<Column gap="3">
|
<Column gap="3">
|
||||||
<WebsiteControls websiteId={websiteId} />
|
<WebsiteControls websiteId={websiteId} />
|
||||||
<EventsMetricsBar websiteId={websiteId} />
|
|
||||||
<GridRow layout="two-one">
|
<GridRow layout="two-one">
|
||||||
<Panel gridColumn="span 2">
|
<Panel gridColumn="span 2">
|
||||||
<EventsChart websiteId={websiteId} focusLabel={label} />
|
<EventsChart websiteId={websiteId} focusLabel={label} />
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { DataTable, DataColumn, Icon, Row } from '@umami/react-zen';
|
import { DataTable, DataColumn, Icon, Row } from '@umami/react-zen';
|
||||||
import { useMessages, useNavigation, useTimezone } from '@/components/hooks';
|
import { useMessages, useNavigation } from '@/components/hooks';
|
||||||
import { Empty } from '@/components/common/Empty';
|
import { Empty } from '@/components/common/Empty';
|
||||||
import { Avatar } from '@/components/common/Avatar';
|
import { Avatar } from '@/components/common/Avatar';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Bolt, Eye } from '@/components/icons';
|
import { Bolt, Eye } from '@/components/icons';
|
||||||
|
import { DateDistance } from '@/components/common/DateDistance';
|
||||||
|
|
||||||
export function EventsTable({ data = [] }) {
|
export function EventsTable({ data = [] }) {
|
||||||
const { formatTimezoneDate } = useTimezone();
|
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { renderUrl } = useNavigation();
|
const { renderUrl } = useNavigation();
|
||||||
|
|
||||||
|
|
@ -34,8 +34,8 @@ export function EventsTable({ data = [] }) {
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</DataColumn>
|
</DataColumn>
|
||||||
<DataColumn id="created" label={formatMessage(labels.created)} width="1fr">
|
<DataColumn id="created" label={formatMessage(labels.created)} width="200px">
|
||||||
{(row: any) => formatTimezoneDate(row.createdAt, 'PPPpp')}
|
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||||
</DataColumn>
|
</DataColumn>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,8 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { TabList, Tab, Tabs, TabPanel, Column } from '@umami/react-zen';
|
import { TabList, Tab, Tabs, TabPanel, Column } from '@umami/react-zen';
|
||||||
import { SessionsDataTable } from './SessionsDataTable';
|
import { SessionsDataTable } from './SessionsDataTable';
|
||||||
import { SessionsMetricsBar } from './SessionsMetricsBar';
|
|
||||||
import { SessionProperties } from './SessionProperties';
|
import { SessionProperties } from './SessionProperties';
|
||||||
import { WorldMap } from '@/components/metrics/WorldMap';
|
|
||||||
import { GridRow } from '@/components/common/GridRow';
|
|
||||||
import { useMessages } from '@/components/hooks';
|
import { useMessages } from '@/components/hooks';
|
||||||
import { SessionsWeekly } from './SessionsWeekly';
|
|
||||||
import { Panel } from '@/components/common/Panel';
|
import { Panel } from '@/components/common/Panel';
|
||||||
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
|
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
|
||||||
|
|
||||||
|
|
@ -18,15 +14,6 @@ export function SessionsPage({ websiteId }) {
|
||||||
return (
|
return (
|
||||||
<Column gap="3">
|
<Column gap="3">
|
||||||
<WebsiteControls websiteId={websiteId} />
|
<WebsiteControls websiteId={websiteId} />
|
||||||
<SessionsMetricsBar websiteId={websiteId} />
|
|
||||||
<GridRow layout="two-one">
|
|
||||||
<Panel gridColumn="span 2" noPadding>
|
|
||||||
<WorldMap websiteId={websiteId} />
|
|
||||||
</Panel>
|
|
||||||
<Panel>
|
|
||||||
<SessionsWeekly websiteId={websiteId} />
|
|
||||||
</Panel>
|
|
||||||
</GridRow>
|
|
||||||
<Panel>
|
<Panel>
|
||||||
<Tabs selectedKey={tab} onSelectionChange={(value: any) => setTab(value)}>
|
<Tabs selectedKey={tab} onSelectionChange={(value: any) => setTab(value)}>
|
||||||
<TabList>
|
<TabList>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { DataColumn, DataTable } from '@umami/react-zen';
|
import { DataColumn, DataTable } from '@umami/react-zen';
|
||||||
import { useFormat, useMessages, useTimezone } from '@/components/hooks';
|
import { useFormat, useMessages } from '@/components/hooks';
|
||||||
import { Avatar } from '@/components/common/Avatar';
|
import { Avatar } from '@/components/common/Avatar';
|
||||||
import { TypeIcon } from '@/components/common/TypeIcon';
|
import { TypeIcon } from '@/components/common/TypeIcon';
|
||||||
|
import { DateDistance } from '@/components/common/DateDistance';
|
||||||
|
|
||||||
export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean }) {
|
export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean }) {
|
||||||
const { formatTimezoneDate } = useTimezone();
|
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { formatValue } = useFormat();
|
const { formatValue } = useFormat();
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ export function SessionsTable({ data = [] }: { data: any[]; showDomain?: boolean
|
||||||
)}
|
)}
|
||||||
</DataColumn>
|
</DataColumn>
|
||||||
<DataColumn id="lastAt" label={formatMessage(labels.lastSeen)}>
|
<DataColumn id="lastAt" label={formatMessage(labels.lastSeen)}>
|
||||||
{(row: any) => formatTimezoneDate(row.createdAt, 'PPPpp')}
|
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||||
</DataColumn>
|
</DataColumn>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await getWebsiteEvents(websiteId, { startDate, endDate }, query);
|
const data = await getWebsiteEvents(websiteId, { ...query, startDate, endDate }, query);
|
||||||
|
|
||||||
return json(data);
|
return json(data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const dateFormats = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface BarChartProps extends ChartProps {
|
export interface BarChartProps extends ChartProps {
|
||||||
unit: string;
|
unit?: string;
|
||||||
stacked?: boolean;
|
stacked?: boolean;
|
||||||
currency?: string;
|
currency?: string;
|
||||||
renderXLabel?: (label: string, index: number, values: any[]) => string;
|
renderXLabel?: (label: string, index: number, values: any[]) => string;
|
||||||
|
|
|
||||||
17
src/components/common/DateDistance.tsx
Normal file
17
src/components/common/DateDistance.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Tooltip, TooltipTrigger, Text, Focusable } from '@umami/react-zen';
|
||||||
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
|
import { useLocale, useTimezone } from '@/components/hooks';
|
||||||
|
|
||||||
|
export function DateDistance({ date }: { date: Date }) {
|
||||||
|
const { formatTimezoneDate } = useTimezone();
|
||||||
|
const { dateLocale } = useLocale();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TooltipTrigger delay={0}>
|
||||||
|
<Focusable>
|
||||||
|
<Text>{formatDistanceToNow(date, { addSuffix: true, locale: dateLocale })}</Text>
|
||||||
|
</Focusable>
|
||||||
|
<Tooltip>{formatTimezoneDate(date.toISOString(), 'PPPpp')}</Tooltip>
|
||||||
|
</TooltipTrigger>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import { useApi } from '../useApi';
|
||||||
import { useFilterParams } from '../useFilterParams';
|
import { useFilterParams } from '../useFilterParams';
|
||||||
import { ReactQueryOptions } from '@/lib/types';
|
import { ReactQueryOptions } from '@/lib/types';
|
||||||
|
|
||||||
export function useResultQuery<T>(
|
export function useResultQuery<T = any>(
|
||||||
type: string,
|
type: string,
|
||||||
params?: { [key: string]: any },
|
params?: { [key: string]: any },
|
||||||
options?: ReactQueryOptions<T>,
|
options?: ReactQueryOptions<T>,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import { useApi } from '../useApi';
|
import { useApi } from '../useApi';
|
||||||
import { usePagedQuery } from '../usePagedQuery';
|
|
||||||
import { useModified } from '../useModified';
|
import { useModified } from '../useModified';
|
||||||
|
|
||||||
export function useTeamsQuery(userId: string) {
|
export function useTeamsQuery(userId: string) {
|
||||||
const { get } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const { modified } = useModified(`teams`);
|
const { modified } = useModified(`teams`);
|
||||||
|
|
||||||
return usePagedQuery({
|
return useQuery({
|
||||||
queryKey: ['teams', { userId, modified }],
|
queryKey: ['teams', { userId, modified }],
|
||||||
queryFn: (params: any) => {
|
queryFn: (params: any) => {
|
||||||
return get(`/users/${userId}/teams`, params);
|
return get(`/users/${userId}/teams`, params);
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,11 @@ import { ReactQueryOptions } from '@/lib/types';
|
||||||
|
|
||||||
export function useWebsiteEventsQuery(websiteId: string, options?: ReactQueryOptions<any>) {
|
export function useWebsiteEventsQuery(websiteId: string, options?: ReactQueryOptions<any>) {
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
const params = useFilterParams(websiteId);
|
const filterParams = useFilterParams(websiteId);
|
||||||
|
|
||||||
return usePagedQuery({
|
return usePagedQuery({
|
||||||
queryKey: ['websites:events', { websiteId, ...params }],
|
queryKey: ['websites:events', { websiteId, ...filterParams }],
|
||||||
queryFn: pageParams =>
|
queryFn: () => get(`/websites/${websiteId}/events`, { ...filterParams, pageSize: 20 }),
|
||||||
get(`/websites/${websiteId}/events`, { ...params, ...pageParams, pageSize: 20 }),
|
|
||||||
enabled: !!websiteId,
|
enabled: !!websiteId,
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,19 @@ export function useFilterParams(websiteId: string) {
|
||||||
event,
|
event,
|
||||||
tag,
|
tag,
|
||||||
hostname,
|
hostname,
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
search,
|
||||||
},
|
},
|
||||||
} = useNavigation();
|
} = useNavigation();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
// Date range
|
||||||
startAt: +toUtc(startDate),
|
startAt: +toUtc(startDate),
|
||||||
endAt: +toUtc(endDate),
|
endAt: +toUtc(endDate),
|
||||||
unit,
|
unit,
|
||||||
timezone,
|
timezone,
|
||||||
|
// Filters
|
||||||
path,
|
path,
|
||||||
referrer,
|
referrer,
|
||||||
title,
|
title,
|
||||||
|
|
@ -44,5 +49,9 @@ export function useFilterParams(websiteId: string) {
|
||||||
event,
|
event,
|
||||||
tag,
|
tag,
|
||||||
hostname,
|
hostname,
|
||||||
|
// Paging
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
search,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export function usePagedQuery<T = any>({
|
||||||
const { query: queryParams } = useNavigation();
|
const { query: queryParams } = useNavigation();
|
||||||
const [params, setParams] = useState<PageParams>({
|
const [params, setParams] = useState<PageParams>({
|
||||||
search: '',
|
search: '',
|
||||||
page: +queryParams?.page || 1,
|
page: queryParams?.page || '1',
|
||||||
});
|
});
|
||||||
|
|
||||||
const { useQuery } = useApi();
|
const { useQuery } = useApi();
|
||||||
|
|
@ -25,7 +25,7 @@ export function usePagedQuery<T = any>({
|
||||||
return {
|
return {
|
||||||
result: data as PageResult<T>,
|
result: data as PageResult<T>,
|
||||||
query,
|
query,
|
||||||
filterParams: params,
|
params,
|
||||||
setParams,
|
setParams,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export interface PageResult<T> {
|
||||||
sortDescending?: boolean;
|
sortDescending?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PagedQueryResult<T> {
|
export interface PagedQueryResult<T = any> {
|
||||||
result: PageResult<T>;
|
result: PageResult<T>;
|
||||||
query: any;
|
query: any;
|
||||||
params: PageParams;
|
params: PageParams;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue