mirror of
https://github.com/umami-software/umami.git
synced 2026-02-10 07:37:11 +01:00
Refactored fetching to use react-query.
This commit is contained in:
parent
7bbed0e12b
commit
c56f02c475
112 changed files with 255 additions and 492 deletions
|
|
@ -1,15 +1,17 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { StatusLight } from 'react-basics';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import Dot from 'components/common/Dot';
|
||||
import useApi from 'hooks/useApi';
|
||||
import styles from './ActiveUsers.module.css';
|
||||
|
||||
export default function ActiveUsers({ websiteId, className, value, interval = 60000 }) {
|
||||
export default function ActiveUsers({ websiteId, className, value, refetchInterval = 60000 }) {
|
||||
const url = websiteId ? `/websites/${websiteId}/active` : null;
|
||||
const { data } = useFetch(url, {
|
||||
interval,
|
||||
const { get, useQuery } = useApi();
|
||||
const { data } = useQuery(['websites:active', websiteId], () => get(url), {
|
||||
refetchInterval,
|
||||
});
|
||||
|
||||
const count = useMemo(() => {
|
||||
if (websiteId) {
|
||||
return data?.[0]?.x || 0;
|
||||
|
|
@ -24,7 +26,7 @@ export default function ActiveUsers({ websiteId, className, value, interval = 60
|
|||
|
||||
return (
|
||||
<div className={classNames(styles.container, className)}>
|
||||
<Dot />
|
||||
<StatusLight variant="success" />
|
||||
<div className={styles.text}>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import ChartJS from 'chart.js';
|
||||
import Legend from 'components/metrics/Legend';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import MetricsTable from 'components/metrics/MetricsTable';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import Dot from 'components/common/Dot';
|
||||
import { StatusLight } from 'react-basics';
|
||||
import styles from './ChartTooltip.module.css';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
|
||||
|
|
@ -16,7 +15,7 @@ export default function ChartTooltip({ chartId, tooltip }) {
|
|||
<div className={styles.content}>
|
||||
<div className={styles.title}>{title}</div>
|
||||
<div className={styles.metric}>
|
||||
<Dot color={labelColor} />
|
||||
<StatusLight color={labelColor} />
|
||||
{value} {label}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import { useIntl, defineMessages } from 'react-intl';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import { useSpring, animated, config } from 'react-spring';
|
||||
import classNames from 'classnames';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import { useIntl, FormattedMessage } from 'react-intl';
|
||||
import { getDeviceMessage } from 'components/messages';
|
||||
|
|
|
|||
|
|
@ -1,39 +1,37 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { Loading } from 'react-basics';
|
||||
import { colord } from 'colord';
|
||||
import BarChart from './BarChart';
|
||||
import { getDateArray, getDateLength } from 'lib/date';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import useApi from 'hooks/useApi';
|
||||
import useDateRange from 'hooks/useDateRange';
|
||||
import useTimezone from 'hooks/useTimezone';
|
||||
import usePageQuery from 'hooks/usePageQuery';
|
||||
import { EVENT_COLORS } from 'lib/constants';
|
||||
|
||||
export default function EventsChart({ websiteId, className, token }) {
|
||||
const { get, useQuery } = useApi();
|
||||
const [{ startDate, endDate, unit, modified }] = useDateRange(websiteId);
|
||||
const [timezone] = useTimezone();
|
||||
const {
|
||||
query: { url, eventName },
|
||||
} = usePageQuery();
|
||||
|
||||
const { data, loading } = useFetch(
|
||||
`/websites/${websiteId}/events`,
|
||||
{
|
||||
params: {
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
unit,
|
||||
tz: timezone,
|
||||
url,
|
||||
eventName,
|
||||
token,
|
||||
},
|
||||
},
|
||||
[modified, eventName],
|
||||
const { data, isLoading } = useQuery(['events', { websiteId, modified, eventName }], () =>
|
||||
get(`/websites/${websiteId}/events`, {
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
unit,
|
||||
timezone,
|
||||
url,
|
||||
eventName,
|
||||
token,
|
||||
}),
|
||||
);
|
||||
|
||||
const datasets = useMemo(() => {
|
||||
if (!data) return [];
|
||||
if (loading) return data;
|
||||
if (isLoading) return data;
|
||||
|
||||
const map = data.reduce((obj, { x, t, y }) => {
|
||||
if (!obj[x]) {
|
||||
|
|
@ -60,7 +58,7 @@ export default function EventsChart({ websiteId, className, token }) {
|
|||
borderWidth: 1,
|
||||
};
|
||||
});
|
||||
}, [data, loading]);
|
||||
}, [data, isLoading]);
|
||||
|
||||
function handleUpdate(chart) {
|
||||
chart.data.datasets = datasets;
|
||||
|
|
@ -68,6 +66,10 @@ export default function EventsChart({ websiteId, className, token }) {
|
|||
chart.update();
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading variant="dots" />;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -81,7 +83,7 @@ export default function EventsChart({ websiteId, className, token }) {
|
|||
height={300}
|
||||
records={getDateLength(startDate, endDate, unit)}
|
||||
onUpdate={handleUpdate}
|
||||
loading={loading}
|
||||
loading={isLoading}
|
||||
stacked
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { safeDecodeURI } from 'next-basics';
|
||||
import { Button } from 'react-basics';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { StatusLight } from 'react-basics';
|
||||
import { colord } from 'colord';
|
||||
import classNames from 'classnames';
|
||||
import Dot from 'components/common/Dot';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
import useForceUpdate from 'hooks/useForceUpdate';
|
||||
import styles from './Legend.module.css';
|
||||
|
|
@ -35,7 +34,7 @@ export default function Legend({ chart }) {
|
|||
className={classNames(styles.label, { [styles.hidden]: hidden })}
|
||||
onClick={() => handleClick(datasetIndex)}
|
||||
>
|
||||
<Dot color={color.alpha(color.alpha() + 0.2).toHex()} />
|
||||
<StatusLight color={color.alpha(color.alpha() + 0.2).toHex()} />
|
||||
<span className={locale}>{text}</span>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import { useSpring, animated } from 'react-spring';
|
||||
import { formatNumber } from 'lib/format';
|
||||
import styles from './MetricCard.module.css';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { Loading } from 'react-basics';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import Loading from 'components/common/Loading';
|
||||
import ErrorMessage from 'components/common/ErrorMessage';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import useApi from 'hooks/useApi';
|
||||
import useDateRange from 'hooks/useDateRange';
|
||||
import usePageQuery from 'hooks/usePageQuery';
|
||||
import { formatShortTime, formatNumber, formatLongNumber } from 'lib/format';
|
||||
|
|
@ -11,6 +11,7 @@ import MetricCard from './MetricCard';
|
|||
import styles from './MetricsBar.module.css';
|
||||
|
||||
export default function MetricsBar({ websiteId, className }) {
|
||||
const { get, useQuery } = useApi();
|
||||
const [dateRange] = useDateRange(websiteId);
|
||||
const { startDate, endDate, modified } = dateRange;
|
||||
const [format, setFormat] = useState(true);
|
||||
|
|
@ -18,10 +19,10 @@ export default function MetricsBar({ websiteId, className }) {
|
|||
query: { url, referrer, os, browser, device, country },
|
||||
} = usePageQuery();
|
||||
|
||||
const { data, error, loading } = useFetch(
|
||||
`/websites/${websiteId}/stats`,
|
||||
{
|
||||
params: {
|
||||
const { data, error, isLoading } = useQuery(
|
||||
['websites:stats', { websiteId, modified, url, referrer, os, browser, device, country }],
|
||||
() =>
|
||||
get(`/websites/${websiteId}/stats`, {
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
url,
|
||||
|
|
@ -30,9 +31,7 @@ export default function MetricsBar({ websiteId, className }) {
|
|||
browser,
|
||||
device,
|
||||
country,
|
||||
},
|
||||
},
|
||||
[modified, url, referrer, os, browser, device, country],
|
||||
}),
|
||||
);
|
||||
|
||||
const formatFunc = format
|
||||
|
|
@ -54,7 +53,7 @@ export default function MetricsBar({ websiteId, className }) {
|
|||
|
||||
return (
|
||||
<div className={classNames(styles.bar, className)} onClick={handleSetFormat}>
|
||||
{!data && loading && <Loading />}
|
||||
{isLoading && <Loading variant="dots" />}
|
||||
{error && <ErrorMessage />}
|
||||
{data && !error && (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { Loading } from 'react-basics';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import firstBy from 'thenby';
|
||||
import classNames from 'classnames';
|
||||
import Link from 'components/common/Link';
|
||||
import Loading from 'components/common/Loading';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import useApi from 'hooks/useApi';
|
||||
import Arrow from 'assets/arrow-right.svg';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import useDateRange from 'hooks/useDateRange';
|
||||
|
|
@ -36,11 +36,15 @@ export default function MetricsTable({
|
|||
query: { url, referrer, os, browser, device, country },
|
||||
} = usePageQuery();
|
||||
const { formatMessage } = useIntl();
|
||||
const { get, useQuery } = useApi();
|
||||
|
||||
const { data, loading, error } = useFetch(
|
||||
`/websites/${websiteId}/metrics`,
|
||||
{
|
||||
params: {
|
||||
const { data, isLoading, error } = useQuery(
|
||||
[
|
||||
'websites:mnetrics',
|
||||
{ websiteId, type, modified, url, referrer, os, browser, device, country },
|
||||
],
|
||||
() =>
|
||||
get(`/websites/${websiteId}/metrics`, {
|
||||
type,
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
|
|
@ -50,11 +54,8 @@ export default function MetricsTable({
|
|||
browser,
|
||||
device,
|
||||
country,
|
||||
},
|
||||
onDataLoad,
|
||||
delay: delay || DEFAULT_ANIMATION_DURATION,
|
||||
},
|
||||
[type, modified, url, referrer, os, browser, device, country],
|
||||
}),
|
||||
{ onSuccess: onDataLoad, retryDelay: delay || DEFAULT_ANIMATION_DURATION },
|
||||
);
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
|
|
@ -73,7 +74,7 @@ export default function MetricsTable({
|
|||
|
||||
return (
|
||||
<div className={classNames(styles.container, className)}>
|
||||
{!data && loading && <Loading />}
|
||||
{!data && isLoading && <Loading variant="dots" />}
|
||||
{error && <ErrorMessage />}
|
||||
{data && !error && <DataTable {...props} data={filteredData} className={className} />}
|
||||
<div className={styles.footer}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useIntl, defineMessage } from 'react-intl';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import FilterButtons from 'components/common/FilterButtons';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { colord } from 'colord';
|
||||
import CheckVisible from 'components/helpers/CheckVisible';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useMemo, useRef } from 'react';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { format, parseISO, startOfMinute, subMinutes, isBefore } from 'date-fns';
|
||||
import PageviewsChart from './PageviewsChart';
|
||||
import { getDateArray } from 'lib/date';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { differenceInMinutes } from 'date-fns';
|
||||
import PageHeader from 'components/layout/PageHeader';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { StatusLight } from 'react-basics';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import firstBy from 'thenby';
|
||||
import { Icon } from 'react-basics';
|
||||
import Dot from 'components/common/Dot';
|
||||
import FilterButtons from 'components/common/FilterButtons';
|
||||
import NoData from 'components/common/NoData';
|
||||
import { getDeviceMessage, labels } from 'components/messages';
|
||||
|
|
@ -149,7 +149,7 @@ export default function RealtimeLog({ data, websites, websiteId }) {
|
|||
return (
|
||||
<div className={styles.row} style={style}>
|
||||
<div>
|
||||
<Dot color={getColor(row)} />
|
||||
<StatusLight color={getColor(row)} />
|
||||
</div>
|
||||
<div className={styles.time}>{getTime(row)}</div>
|
||||
<div className={styles.detail}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import { useMemo, useState, useCallback } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import firstBy from 'thenby';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useIntl, defineMessages } from 'react-intl';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import FilterButtons from 'components/common/FilterButtons';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useMemo } from 'react';
|
||||
import { Row, Column } from 'react-basics';
|
||||
import { Row, Column, Loading } from 'react-basics';
|
||||
import PageviewsChart from './PageviewsChart';
|
||||
import MetricsBar from './MetricsBar';
|
||||
import WebsiteHeader from './WebsiteHeader';
|
||||
|
|
@ -7,12 +7,11 @@ import DateFilter from 'components/common/DateFilter';
|
|||
import StickyHeader from 'components/helpers/StickyHeader';
|
||||
import ErrorMessage from 'components/common/ErrorMessage';
|
||||
import FilterTags from 'components/metrics/FilterTags';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import useApi from 'hooks/useApi';
|
||||
import useDateRange from 'hooks/useDateRange';
|
||||
import useTimezone from 'hooks/useTimezone';
|
||||
import usePageQuery from 'hooks/usePageQuery';
|
||||
import { getDateArray, getDateLength, getDateRangeValues } from 'lib/date';
|
||||
import useApi from 'hooks/useApi';
|
||||
import styles from './WebsiteChart.module.css';
|
||||
|
||||
export default function WebsiteChart({
|
||||
|
|
@ -31,26 +30,24 @@ export default function WebsiteChart({
|
|||
resolve,
|
||||
query: { url, referrer, os, browser, device, country },
|
||||
} = usePageQuery();
|
||||
const { get } = useApi();
|
||||
const { get, useQuery } = useApi();
|
||||
|
||||
const { data, loading, error } = useFetch(
|
||||
`/websites/${websiteId}/pageviews`,
|
||||
{
|
||||
params: {
|
||||
const { data, isLoading, error } = useQuery(
|
||||
['websites:pageviews', { websiteId, modified, url, referrer, os, browser, device, country }],
|
||||
() =>
|
||||
get(`/websites/${websiteId}/pageviews`, {
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
unit,
|
||||
tz: timezone,
|
||||
timezone,
|
||||
url,
|
||||
referrer,
|
||||
os,
|
||||
browser,
|
||||
device,
|
||||
country,
|
||||
},
|
||||
onDataLoad,
|
||||
},
|
||||
[modified, url, referrer, os, browser, device, country],
|
||||
}),
|
||||
{ onSuccess: onDataLoad },
|
||||
);
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
|
|
@ -78,10 +75,13 @@ export default function WebsiteChart({
|
|||
}
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading variant="dots" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<WebsiteHeader websiteId={websiteId} title={title} domain={domain} />
|
||||
|
||||
<StickyHeader
|
||||
className={styles.metrics}
|
||||
stickyClassName={styles.sticky}
|
||||
|
|
@ -114,7 +114,7 @@ export default function WebsiteChart({
|
|||
data={chartData}
|
||||
unit={unit}
|
||||
records={getDateLength(startDate, endDate, unit)}
|
||||
loading={loading}
|
||||
loading={isLoading}
|
||||
/>
|
||||
)}
|
||||
</Column>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue