mirror of
https://github.com/umami-software/umami.git
synced 2026-02-08 22:57:12 +01:00
Refactored realtime.
This commit is contained in:
parent
cda3ba345b
commit
5108b91f80
16 changed files with 205 additions and 227 deletions
|
|
@ -5,7 +5,7 @@ import styles from './RealtimeHeader.module.css';
|
|||
|
||||
export function RealtimeHeader({ data }: { data: RealtimeData }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { pageviews, visitors, events, countries } = data || {};
|
||||
const { totals }: any = data || {};
|
||||
|
||||
return (
|
||||
<div className={styles.header}>
|
||||
|
|
@ -13,22 +13,22 @@ export function RealtimeHeader({ data }: { data: RealtimeData }) {
|
|||
<MetricCard
|
||||
className={styles.card}
|
||||
label={formatMessage(labels.views)}
|
||||
value={pageviews?.length}
|
||||
value={totals.views}
|
||||
/>
|
||||
<MetricCard
|
||||
className={styles.card}
|
||||
label={formatMessage(labels.visitors)}
|
||||
value={visitors?.length}
|
||||
value={totals.visitors}
|
||||
/>
|
||||
<MetricCard
|
||||
className={styles.card}
|
||||
label={formatMessage(labels.events)}
|
||||
value={events?.length}
|
||||
value={totals.events}
|
||||
/>
|
||||
<MetricCard
|
||||
className={styles.card}
|
||||
label={formatMessage(labels.countries)}
|
||||
value={countries?.length}
|
||||
value={totals.countries}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -54,20 +54,20 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
|
|||
},
|
||||
];
|
||||
|
||||
const getTime = ({ timestamp }) => format(timestamp, 'h:mm:ss');
|
||||
const getTime = ({ timestamp }) => format(timestamp * 1000, 'h:mm:ss');
|
||||
|
||||
const getColor = ({ id, sessionId }) => stringToColor(sessionId || id);
|
||||
|
||||
const getIcon = ({ __type }) => icons[__type];
|
||||
|
||||
const getDetail = (log: {
|
||||
__type: any;
|
||||
eventName: any;
|
||||
urlPath: any;
|
||||
browser: any;
|
||||
os: any;
|
||||
country: any;
|
||||
device: any;
|
||||
__type: string;
|
||||
eventName: string;
|
||||
urlPath: string;
|
||||
browser: string;
|
||||
os: string;
|
||||
country: string;
|
||||
device: string;
|
||||
}) => {
|
||||
const { __type, eventName, urlPath: url, browser, os, country, device } = log;
|
||||
|
||||
|
|
@ -141,8 +141,12 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
|
|||
return [];
|
||||
}
|
||||
|
||||
const { pageviews, visitors, events } = data;
|
||||
let logs = [...pageviews, ...visitors, ...events].sort(thenby.firstBy('createdAt', -1));
|
||||
const { events, visitors } = data;
|
||||
|
||||
let logs = [
|
||||
...events.map(e => ({ __type: e.eventName ? TYPE_EVENT : TYPE_PAGEVIEW, ...e })),
|
||||
...visitors.map(v => ({ __type: TYPE_SESSION, ...v })),
|
||||
].sort(thenby.firstBy('timestamp', -1));
|
||||
|
||||
if (search) {
|
||||
logs = logs.filter(({ eventName, urlPath, browser, os, country, device }) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Key, useContext, useMemo, useState } from 'react';
|
||||
import { Key, useContext, useState } from 'react';
|
||||
import { ButtonGroup, Button, Flexbox } from 'react-basics';
|
||||
import thenby from 'thenby';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
|
|
@ -11,7 +11,7 @@ import { WebsiteContext } from '../WebsiteProvider';
|
|||
export function RealtimeUrls({ data }: { data: RealtimeData }) {
|
||||
const website = useContext(WebsiteContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { pageviews } = data || {};
|
||||
const { referrers, urls } = data || {};
|
||||
const [filter, setFilter] = useState<Key>(FILTER_REFERRERS);
|
||||
const limit = 15;
|
||||
|
||||
|
|
@ -35,47 +35,29 @@ export function RealtimeUrls({ data }: { data: RealtimeData }) {
|
|||
);
|
||||
};
|
||||
|
||||
const [referrers = [], pages = []] = useMemo(() => {
|
||||
if (pageviews) {
|
||||
const referrers = percentFilter(
|
||||
pageviews
|
||||
.reduce((arr, { referrerDomain }) => {
|
||||
if (referrerDomain) {
|
||||
const row = arr.find(({ x }) => x === referrerDomain);
|
||||
const domains = percentFilter(
|
||||
Object.keys(referrers)
|
||||
.map(key => {
|
||||
return {
|
||||
x: key,
|
||||
y: referrers[key],
|
||||
};
|
||||
})
|
||||
.sort(thenby.firstBy('y', -1))
|
||||
.slice(0, limit),
|
||||
);
|
||||
|
||||
if (!row) {
|
||||
arr.push({ x: referrerDomain, y: 1 });
|
||||
} else {
|
||||
row.y += 1;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}, [])
|
||||
.sort(thenby.firstBy('y', -1))
|
||||
.slice(0, limit),
|
||||
);
|
||||
|
||||
const pages = percentFilter(
|
||||
pageviews
|
||||
.reduce((arr, { urlPath }) => {
|
||||
const row = arr.find(({ x }) => x === urlPath);
|
||||
|
||||
if (!row) {
|
||||
arr.push({ x: urlPath, y: 1 });
|
||||
} else {
|
||||
row.y += 1;
|
||||
}
|
||||
return arr;
|
||||
}, [])
|
||||
.sort(thenby.firstBy('y', -1))
|
||||
.slice(0, limit),
|
||||
);
|
||||
|
||||
return [referrers, pages];
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [pageviews]);
|
||||
const pages = percentFilter(
|
||||
Object.keys(urls)
|
||||
.map(key => {
|
||||
return {
|
||||
x: key,
|
||||
y: urls[key],
|
||||
};
|
||||
})
|
||||
.sort(thenby.firstBy('y', -1))
|
||||
.slice(0, limit),
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -89,7 +71,7 @@ export function RealtimeUrls({ data }: { data: RealtimeData }) {
|
|||
title={formatMessage(labels.referrers)}
|
||||
metric={formatMessage(labels.views)}
|
||||
renderLabel={renderLink}
|
||||
data={referrers}
|
||||
data={domains}
|
||||
/>
|
||||
)}
|
||||
{filter === FILTER_PAGES && (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
'use client';
|
||||
import { firstBy } from 'thenby';
|
||||
import { Grid, GridRow } from 'components/layout/Grid';
|
||||
import Page from 'components/layout/Page';
|
||||
import RealtimeChart from 'components/metrics/RealtimeChart';
|
||||
|
|
@ -10,6 +11,7 @@ import RealtimeUrls from './RealtimeUrls';
|
|||
import RealtimeCountries from './RealtimeCountries';
|
||||
import WebsiteHeader from '../WebsiteHeader';
|
||||
import WebsiteProvider from '../WebsiteProvider';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
|
||||
export function WebsiteRealtimePage({ websiteId }) {
|
||||
const { data, isLoading, error } = useRealtime(websiteId);
|
||||
|
|
@ -18,6 +20,12 @@ export function WebsiteRealtimePage({ websiteId }) {
|
|||
return <Page isLoading={isLoading} error={error} />;
|
||||
}
|
||||
|
||||
const countries = percentFilter(
|
||||
Object.keys(data.countries)
|
||||
.map(key => ({ x: key, y: data.countries[key] }))
|
||||
.sort(firstBy('y', -1)),
|
||||
);
|
||||
|
||||
return (
|
||||
<WebsiteProvider websiteId={websiteId}>
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
|
|
@ -29,8 +37,8 @@ export function WebsiteRealtimePage({ websiteId }) {
|
|||
<RealtimeLog data={data} />
|
||||
</GridRow>
|
||||
<GridRow columns="one-two">
|
||||
<RealtimeCountries data={data?.countries} />
|
||||
<WorldMap data={data?.countries} />
|
||||
<RealtimeCountries data={countries} />
|
||||
<WorldMap data={countries} />
|
||||
</GridRow>
|
||||
</Grid>
|
||||
</WebsiteProvider>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue