mirror of
https://github.com/umami-software/umami.git
synced 2026-02-07 06:07:17 +01:00
Merge branch 'dev' into os-names
This commit is contained in:
commit
37e28bbf74
472 changed files with 5460 additions and 5026 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { useMemo } from 'react';
|
||||
import { StatusLight } from 'react-basics';
|
||||
import useApi from 'components/hooks/useApi';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useApi } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import styles from './ActiveUsers.module.css';
|
||||
|
||||
export function ActiveUsers({
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import classNames from 'classnames';
|
|||
import Chart from 'chart.js/auto';
|
||||
import HoverTooltip from 'components/common/HoverTooltip';
|
||||
import Legend from 'components/metrics/Legend';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import useTheme from 'components/hooks/useTheme';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useTheme } from 'components/hooks';
|
||||
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
|
||||
import { renderNumberLabels } from 'lib/charts';
|
||||
import styles from './BarChart.module.css';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import FilterLink from 'components/common/FilterLink';
|
||||
import MetricsTable, { MetricsTableProps } from 'components/metrics/MetricsTable';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useFormat from 'components/hooks/useFormat';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useFormat } from 'components/hooks';
|
||||
|
||||
export function BrowsersTable(props: MetricsTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import { emptyFilter } from 'lib/filters';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useCountryNames from 'components/hooks/useCountryNames';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useCountryNames } from 'components/hooks';
|
||||
|
||||
export function CitiesTable(props: MetricsTableProps) {
|
||||
const { locale } = useLocale();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import FilterLink from 'components/common/FilterLink';
|
||||
import useCountryNames from 'components/hooks/useCountryNames';
|
||||
import { useCountryNames } from 'components/hooks';
|
||||
import { useLocale, useMessages, useFormat } from 'components/hooks';
|
||||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useState } from 'react';
|
||||
import { Button, ButtonGroup, Calendar } from 'react-basics';
|
||||
import { isAfter, isBefore, isSameDay, startOfDay, endOfDay } from 'date-fns';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { FILTER_DAY, FILTER_RANGE } from 'lib/constants';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import styles from './DatePickerForm.module.css';
|
||||
|
||||
export function DatePickerForm({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useFormat } from 'components/hooks';
|
||||
|
||||
export function DevicesTable(props: MetricsTableProps) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@ import { Loading } from 'react-basics';
|
|||
import { colord } from 'colord';
|
||||
import BarChart from './BarChart';
|
||||
import { getDateArray } from 'lib/date';
|
||||
import { useApi, useLocale, useDateRange, useTimezone, useNavigation } from 'components/hooks';
|
||||
import {
|
||||
useLocale,
|
||||
useDateRange,
|
||||
useTimezone,
|
||||
useNavigation,
|
||||
useWebsiteEvents,
|
||||
} from 'components/hooks';
|
||||
import { EVENT_COLORS } from 'lib/constants';
|
||||
import { renderDateLabels, renderStatusTooltipPopup } from 'lib/charts';
|
||||
|
||||
|
|
@ -14,34 +20,29 @@ export interface EventsChartProps {
|
|||
}
|
||||
|
||||
export function EventsChart({ websiteId, className, token }: EventsChartProps) {
|
||||
const { get, useQuery } = useApi();
|
||||
const [{ startDate, endDate, unit, modified }] = useDateRange(websiteId);
|
||||
const [{ startDate, endDate, unit, offset }] = useDateRange(websiteId);
|
||||
const { locale } = useLocale();
|
||||
const [timezone] = useTimezone();
|
||||
const {
|
||||
query: { url, event },
|
||||
} = useNavigation();
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['events', websiteId, modified, event],
|
||||
queryFn: () =>
|
||||
get(`/websites/${websiteId}/events`, {
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
unit,
|
||||
timezone,
|
||||
url,
|
||||
event,
|
||||
token,
|
||||
}),
|
||||
enabled: !!websiteId,
|
||||
const { data, isLoading } = useWebsiteEvents(websiteId, {
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
unit,
|
||||
timezone,
|
||||
url,
|
||||
event,
|
||||
token,
|
||||
offset,
|
||||
});
|
||||
|
||||
const datasets = useMemo(() => {
|
||||
if (!data) return [];
|
||||
if (isLoading) return data;
|
||||
|
||||
const map = data.reduce((obj, { x, t, y }) => {
|
||||
const map = (data as any[]).reduce((obj, { x, t, y }) => {
|
||||
if (!obj[x]) {
|
||||
obj[x] = [];
|
||||
}
|
||||
|
|
@ -75,12 +76,12 @@ export function EventsChart({ websiteId, className, token }: EventsChartProps) {
|
|||
return (
|
||||
<BarChart
|
||||
className={className}
|
||||
datasets={datasets}
|
||||
datasets={datasets as any[]}
|
||||
unit={unit}
|
||||
loading={isLoading}
|
||||
stacked
|
||||
stacked={true}
|
||||
renderXLabel={renderDateLabels(unit, locale)}
|
||||
renderTooltipPopup={renderStatusTooltipPopup(unit, locale)}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useMessages } from 'components/hooks';
|
||||
|
||||
export function EventsTable(props: MetricsTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { safeDecodeURI } from 'next-basics';
|
||||
import { Button, Icon, Icons, Text } from 'react-basics';
|
||||
import useNavigation from 'components/hooks/useNavigation';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useFormat from 'components/hooks/useFormat';
|
||||
import { useNavigation } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useFormat } from 'components/hooks';
|
||||
import styles from './FilterTags.module.css';
|
||||
|
||||
export function FilterTags({ params }) {
|
||||
|
|
@ -10,7 +10,7 @@ export function FilterTags({ params }) {
|
|||
const { formatValue } = useFormat();
|
||||
const {
|
||||
router,
|
||||
makeUrl,
|
||||
renderUrl,
|
||||
query: { view },
|
||||
} = useNavigation();
|
||||
|
||||
|
|
@ -19,11 +19,11 @@ export function FilterTags({ params }) {
|
|||
}
|
||||
|
||||
function handleCloseFilter(param?: string) {
|
||||
router.push(makeUrl({ [param]: undefined }));
|
||||
router.push(renderUrl({ [param]: undefined }));
|
||||
}
|
||||
|
||||
function handleResetFilter() {
|
||||
router.push(makeUrl({ view }, true));
|
||||
router.push(renderUrl({ view }, true));
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import useLanguageNames from 'components/hooks/useLanguageNames';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useLanguageNames } from 'components/hooks';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
|
||||
export function LanguagesTable({
|
||||
onDataLoad,
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@ import { useEffect } from 'react';
|
|||
import { StatusLight } from 'react-basics';
|
||||
import { colord } from 'colord';
|
||||
import classNames from 'classnames';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import useForceUpdate from 'components/hooks/useForceUpdate';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useForceUpdate } from 'components/hooks';
|
||||
import styles from './Legend.module.css';
|
||||
|
||||
export function Legend({ chart }) {
|
||||
const { locale } = useLocale();
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
const handleClick = index => {
|
||||
const handleClick = (index: string | number) => {
|
||||
const meta = chart.getDatasetMeta(index);
|
||||
|
||||
meta.hidden = meta.hidden === null ? !chart.data.datasets[index].hidden : null;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { useSpring, animated, config } from '@react-spring/web';
|
|||
import classNames from 'classnames';
|
||||
import Empty from 'components/common/Empty';
|
||||
import { formatLongNumber } from 'lib/format';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import styles from './ListTable.module.css';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
|
|
@ -63,6 +63,7 @@ export function ListTable({
|
|||
{data?.length === 0 && <Empty className={styles.empty} />}
|
||||
{virtualize && data.length > 0 ? (
|
||||
<FixedSizeList
|
||||
width="100%"
|
||||
height={itemCount * ITEM_SIZE}
|
||||
itemCount={data.length}
|
||||
itemSize={ITEM_SIZE}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
import { ReactNode, useMemo, useState } from 'react';
|
||||
import { Loading, Icon, Text, SearchField } from 'react-basics';
|
||||
import classNames from 'classnames';
|
||||
import useApi from 'components/hooks/useApi';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import useDateRange from 'components/hooks/useDateRange';
|
||||
import useNavigation from 'components/hooks/useNavigation';
|
||||
import ErrorMessage from 'components/common/ErrorMessage';
|
||||
import LinkButton from 'components/common/LinkButton';
|
||||
import ListTable, { ListTableProps } from './ListTable';
|
||||
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import {
|
||||
useDateRange,
|
||||
useNavigation,
|
||||
useWebsiteMetrics,
|
||||
useMessages,
|
||||
useLocale,
|
||||
useFormat,
|
||||
} from 'components/hooks';
|
||||
import Icons from 'components/icons';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import useFormat from 'components//hooks/useFormat';
|
||||
import ListTable, { ListTableProps } from './ListTable';
|
||||
import styles from './MetricsTable.module.css';
|
||||
|
||||
export interface MetricsTableProps extends ListTableProps {
|
||||
|
|
@ -43,55 +45,36 @@ export function MetricsTable({
|
|||
}: MetricsTableProps) {
|
||||
const [search, setSearch] = useState('');
|
||||
const { formatValue } = useFormat();
|
||||
const [{ startDate, endDate, modified }] = useDateRange(websiteId);
|
||||
const [{ startDate, endDate }] = useDateRange(websiteId);
|
||||
const {
|
||||
makeUrl,
|
||||
renderUrl,
|
||||
query: { url, referrer, title, os, browser, device, country, region, city },
|
||||
} = useNavigation();
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { get, useQuery } = useApi();
|
||||
const { dir } = useLocale();
|
||||
const { data, isLoading, isFetched, error } = useQuery({
|
||||
queryKey: [
|
||||
'websites:metrics',
|
||||
{
|
||||
websiteId,
|
||||
type,
|
||||
modified,
|
||||
url,
|
||||
referrer,
|
||||
os,
|
||||
title,
|
||||
browser,
|
||||
device,
|
||||
country,
|
||||
region,
|
||||
city,
|
||||
},
|
||||
],
|
||||
queryFn: async () => {
|
||||
const filters = { url, title, referrer, os, browser, device, country, region, city };
|
||||
|
||||
filters[type] = undefined;
|
||||
|
||||
const data = await get(`/websites/${websiteId}/metrics`, {
|
||||
type,
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
limit,
|
||||
...filters,
|
||||
});
|
||||
|
||||
onDataLoad?.(data);
|
||||
|
||||
return data;
|
||||
const { data, isLoading, isFetched, error } = useWebsiteMetrics(
|
||||
websiteId,
|
||||
{
|
||||
type,
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
url,
|
||||
referrer,
|
||||
os,
|
||||
title,
|
||||
browser,
|
||||
device,
|
||||
country,
|
||||
region,
|
||||
city,
|
||||
},
|
||||
retryDelay: delay || DEFAULT_ANIMATION_DURATION,
|
||||
});
|
||||
{ retryDelay: delay || DEFAULT_ANIMATION_DURATION, onDataLoad },
|
||||
);
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (data) {
|
||||
let items: any[] = data;
|
||||
let items = data as any[];
|
||||
|
||||
if (dataFilter) {
|
||||
if (Array.isArray(dataFilter)) {
|
||||
|
|
@ -142,7 +125,7 @@ export function MetricsTable({
|
|||
{!data && isLoading && !isFetched && <Loading icon="dots" />}
|
||||
<div className={styles.footer}>
|
||||
{data && !error && limit && (
|
||||
<LinkButton href={makeUrl({ view: type })} variant="quiet">
|
||||
<LinkButton href={renderUrl({ view: type })} variant="quiet">
|
||||
<Text>{formatMessage(labels.more)}</Text>
|
||||
<Icon size="sm" rotate={dir === 'rtl' ? 180 : 0}>
|
||||
<Icons.ArrowRight />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useFormat from 'components/hooks/useFormat';
|
||||
import { useMessages, useFormat } from 'components/hooks';
|
||||
|
||||
export function OSTable(props: MetricsTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import FilterLink from 'components/common/FilterLink';
|
||||
import FilterButtons from 'components/common/FilterButtons';
|
||||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useNavigation from 'components/hooks/useNavigation';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useNavigation } from 'components/hooks';
|
||||
import { emptyFilter } from 'lib/filters';
|
||||
|
||||
export interface PagesTableProps extends MetricsTableProps {
|
||||
|
|
@ -12,13 +12,13 @@ export interface PagesTableProps extends MetricsTableProps {
|
|||
export function PagesTable({ allowFilter, domainName, ...props }: PagesTableProps) {
|
||||
const {
|
||||
router,
|
||||
makeUrl,
|
||||
renderUrl,
|
||||
query: { view = 'url' },
|
||||
} = useNavigation();
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const handleSelect = (key: any) => {
|
||||
router.push(makeUrl({ view: key }), { scroll: true });
|
||||
router.push(renderUrl({ view: key }), { scroll: true });
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import FilterButtons from 'components/common/FilterButtons';
|
|||
import { emptyFilter, paramFilter } from 'lib/filters';
|
||||
import { FILTER_RAW, FILTER_COMBINED } from 'lib/constants';
|
||||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import styles from './QueryParametersTable.module.css';
|
||||
|
||||
const filters = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useMessages } from 'components/hooks';
|
||||
|
||||
export function ReferrersTable(props: MetricsTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import FilterLink from 'components/common/FilterLink';
|
||||
import { emptyFilter } from 'lib/filters';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import useCountryNames from 'components/hooks/useCountryNames';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useCountryNames } from 'components/hooks';
|
||||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import regions from 'public/iso-3166-2.json';
|
||||
import regions from '../../../public/iso-3166-2.json';
|
||||
|
||||
export function RegionsTable(props: MetricsTableProps) {
|
||||
const { locale } = useLocale();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useMessages } from 'components/hooks';
|
||||
|
||||
export function ScreenTable(props: MetricsTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ import classNames from 'classnames';
|
|||
import { colord } from 'colord';
|
||||
import HoverTooltip from 'components/common/HoverTooltip';
|
||||
import { ISO_COUNTRIES, MAP_FILE } from 'lib/constants';
|
||||
import useTheme from 'components/hooks/useTheme';
|
||||
import useCountryNames from 'components/hooks/useCountryNames';
|
||||
import useLocale from 'components/hooks/useLocale';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import { useTheme } from 'components/hooks';
|
||||
import { useCountryNames } from 'components/hooks';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { formatLongNumber } from 'lib/format';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import styles from './WorldMap.module.css';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue