mirror of
https://github.com/umami-software/umami.git
synced 2026-02-10 07:37:11 +01:00
Refactored data tables. Added realtime tables.
This commit is contained in:
parent
51955c69ec
commit
8912daa2fa
29 changed files with 335 additions and 226 deletions
|
|
@ -1,19 +1,17 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import { useSpring, animated, config } from 'react-spring';
|
||||
import classNames from 'classnames';
|
||||
import Link from 'components/common/Link';
|
||||
import Loading from 'components/common/Loading';
|
||||
import NoData from 'components/common/NoData';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import Arrow from 'assets/arrow-right.svg';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import { formatNumber, formatLongNumber } from 'lib/format';
|
||||
import useDateRange from 'hooks/useDateRange';
|
||||
import usePageQuery from 'hooks/usePageQuery';
|
||||
import ErrorMessage from 'components/common/ErrorMessage';
|
||||
import DataTable from './DataTable';
|
||||
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
|
||||
import styles from './MetricsTable.module.css';
|
||||
import ErrorMessage from '../common/ErrorMessage';
|
||||
|
||||
export default function MetricsTable({
|
||||
websiteId,
|
||||
|
|
@ -49,15 +47,12 @@ export default function MetricsTable({
|
|||
token,
|
||||
},
|
||||
onDataLoad,
|
||||
delay: 300,
|
||||
delay: DEFAULT_ANIMATION_DURATION,
|
||||
},
|
||||
[modified],
|
||||
);
|
||||
const [format, setFormat] = useState(true);
|
||||
const formatFunc = format ? formatLongNumber : formatNumber;
|
||||
const shouldAnimate = limit > 0;
|
||||
|
||||
const rankings = useMemo(() => {
|
||||
const filteredData = useMemo(() => {
|
||||
if (data) {
|
||||
const items = percentFilter(dataFilter ? dataFilter(data, filterOptions) : data);
|
||||
if (limit) {
|
||||
|
|
@ -68,91 +63,34 @@ export default function MetricsTable({
|
|||
return [];
|
||||
}, [data, error, dataFilter, filterOptions]);
|
||||
|
||||
const handleSetFormat = () => setFormat(state => !state);
|
||||
|
||||
const getRow = row => {
|
||||
const { x: label, y: value, z: percent } = row;
|
||||
return (
|
||||
<AnimatedRow
|
||||
key={label}
|
||||
label={renderLabel ? renderLabel(row) : label}
|
||||
value={value}
|
||||
percent={percent}
|
||||
animate={shouldAnimate}
|
||||
format={formatFunc}
|
||||
onClick={handleSetFormat}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Row = ({ index, style }) => {
|
||||
return <div style={style}>{getRow(rankings[index])}</div>;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.container, className)}>
|
||||
{!data && loading && <Loading />}
|
||||
{error && <ErrorMessage />}
|
||||
{data && !error && (
|
||||
<>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.title}>{title}</div>
|
||||
<div className={styles.metric} onClick={handleSetFormat}>
|
||||
{metric}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.body}>
|
||||
{rankings?.length === 0 && <NoData />}
|
||||
{limit
|
||||
? rankings.map(row => getRow(row))
|
||||
: rankings.length > 0 && (
|
||||
<FixedSizeList height={500} itemCount={rankings.length} itemSize={30}>
|
||||
{Row}
|
||||
</FixedSizeList>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
{limit && (
|
||||
<Link
|
||||
icon={<Arrow />}
|
||||
href={router.pathname}
|
||||
as={resolve({ view: type })}
|
||||
size="small"
|
||||
iconRight
|
||||
>
|
||||
<FormattedMessage id="button.more" defaultMessage="More" />
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
<DataTable
|
||||
title={title}
|
||||
data={filteredData}
|
||||
metric={metric}
|
||||
className={className}
|
||||
renderLabel={renderLabel}
|
||||
limit={limit}
|
||||
animate={limit > 0}
|
||||
/>
|
||||
)}
|
||||
<div className={styles.footer}>
|
||||
{limit && (
|
||||
<Link
|
||||
icon={<Arrow />}
|
||||
href={router.pathname}
|
||||
as={resolve({ view: type })}
|
||||
size="small"
|
||||
iconRight
|
||||
>
|
||||
<FormattedMessage id="button.more" defaultMessage="More" />
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const AnimatedRow = ({ label, value = 0, percent, animate, format, onClick }) => {
|
||||
const props = useSpring({
|
||||
width: percent,
|
||||
y: value,
|
||||
from: { width: 0, y: 0 },
|
||||
config: animate ? config.default : { duration: 0 },
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.row}>
|
||||
<div className={styles.label}>{label}</div>
|
||||
<div className={styles.value} onClick={onClick}>
|
||||
<animated.div className={styles.value}>{props.y?.interpolate(format)}</animated.div>
|
||||
</div>
|
||||
<div className={styles.percent}>
|
||||
<animated.div
|
||||
className={styles.bar}
|
||||
style={{ width: props.width.interpolate(n => `${n}%`) }}
|
||||
/>
|
||||
<animated.span className={styles.percentValue}>
|
||||
{props.width.interpolate(n => `${n.toFixed(0)}%`)}
|
||||
</animated.span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue