Refactored realtime components.

This commit is contained in:
Mike Cao 2020-10-10 01:16:28 -07:00
parent 8912daa2fa
commit a039f405b6
8 changed files with 51 additions and 51 deletions

View File

@ -6,6 +6,11 @@
flex: 1; flex: 1;
} }
.body {
position: relative;
flex: 1;
}
.header { .header {
display: flex; display: flex;
align-items: center; align-items: center;
@ -88,9 +93,3 @@
background: var(--primary400); background: var(--primary400);
z-index: -1; z-index: -1;
} }
.body {
position: relative;
flex: 1;
overflow: hidden;
}

View File

@ -25,6 +25,7 @@ export default function MetricsTable({
filterOptions, filterOptions,
limit, limit,
renderLabel, renderLabel,
height,
onDataLoad = () => {}, onDataLoad = () => {},
}) { }) {
const [dateRange] = useDateRange(websiteId); const [dateRange] = useDateRange(websiteId);
@ -75,6 +76,7 @@ export default function MetricsTable({
className={className} className={className}
renderLabel={renderLabel} renderLabel={renderLabel}
limit={limit} limit={limit}
height={height}
animate={limit > 0} animate={limit > 0}
/> />
)} )}

View File

@ -1,11 +1,9 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { FixedSizeList } from 'react-window'; import { FixedSizeList } from 'react-window';
import classNames from 'classnames';
import firstBy from 'thenby'; import firstBy from 'thenby';
import { format } from 'date-fns'; import { format } from 'date-fns';
import Icon from 'components/common/Icon'; import Icon from 'components/common/Icon';
import Table, { TableRow } from 'components/common/Table';
import Tag from 'components/common/Tag'; import Tag from 'components/common/Tag';
import useLocale from 'hooks/useLocale'; import useLocale from 'hooks/useLocale';
import useCountryNames from 'hooks/useCountryNames'; import useCountryNames from 'hooks/useCountryNames';
@ -33,29 +31,6 @@ export default function RealtimeLog({ data, websites }) {
return [...pageviews, ...sessions, ...events].sort(firstBy('created_at', -1)); return [...pageviews, ...sessions, ...events].sort(firstBy('created_at', -1));
}, [data]); }, [data]);
const columns = [
{
key: 'time',
className: classNames(styles.time, 'col-3 col-lg-1'),
render: ({ created_at }) => format(new Date(created_at), 'h:mm:ss'),
},
{
key: 'website',
className: classNames(styles.website, 'col-9 col-lg-2'),
render: getWebsite,
},
{
key: 'detail',
className: classNames(styles.detail, 'col-12 col-lg-9'),
render: row => (
<>
<Icon className={styles.icon} icon={getIcon(row)} />
{getDetail(row)}
</>
),
},
];
function getType({ view_id, session_id, event_id }) { function getType({ view_id, session_id, event_id }) {
if (event_id) { if (event_id) {
return TYPE_EVENT; return TYPE_EVENT;
@ -110,29 +85,29 @@ export default function RealtimeLog({ data, websites }) {
} }
const Row = ({ index, style }) => { const Row = ({ index, style }) => {
const row = logs[index];
return ( return (
<div style={style}> <div className={styles.row} style={style}>
<TableRow key={index} columns={columns} row={logs[index]} /> <div className={styles.time}>{format(new Date(row.created_at), 'h:mm:ss')}</div>
<div className={styles.website}>{getWebsite(row)}</div>
<div className={styles.detail}>
<Icon className={styles.icon} icon={getIcon(row)} />
{getDetail(row)}
</div>
</div> </div>
); );
}; };
return ( return (
<div className={styles.log}> <div className={styles.table}>
<div className={styles.header}> <div className={styles.header}>
<FormattedMessage id="label.realtime-logs" defaultMessage="Realtime logs" /> <FormattedMessage id="label.realtime-logs" defaultMessage="Realtime logs" />
</div> </div>
<Table <div className={styles.body}>
className={styles.table} <FixedSizeList height={400} itemCount={logs.length} itemSize={40}>
bodyClassName={styles.body}
columns={columns}
rows={logs}
showHeader={false}
>
<FixedSizeList height={400} itemCount={logs.length} itemSize={46}>
{Row} {Row}
</FixedSizeList> </FixedSizeList>
</Table> </div>
</div> </div>
); );
} }

View File

@ -6,12 +6,15 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
font-size: 16px;
line-height: 40px; line-height: 40px;
font-weight: 600; font-weight: 600;
} }
.row { .row {
display: flex; display: flex;
align-items: center;
height: 40px;
border-bottom: 1px solid var(--gray300); border-bottom: 1px solid var(--gray300);
} }
@ -20,17 +23,23 @@
} }
.icon { .icon {
align-self: center; margin-right: 10px;
margin-right: 20px; }
.time {
min-width: 60px;
overflow: hidden;
} }
.website { .website {
min-width: 120px;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
} }
.detail { .detail {
display: flex;
flex: 1; flex: 1;
} }

View File

@ -16,7 +16,7 @@ import useCountryNames from 'hooks/useCountryNames';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
const REALTIME_RANGE = 30; const REALTIME_RANGE = 30;
const REALTIME_INTERVAL = 5000; const REALTIME_INTERVAL = 55000;
function mergeData(state, data, time) { function mergeData(state, data, time) {
const ids = state.map(({ __id }) => __id); const ids = state.map(({ __id }) => __id);
@ -151,17 +151,18 @@ export default function RealtimeDashboard() {
</div> </div>
<GridLayout> <GridLayout>
<GridRow> <GridRow>
<GridColumn xs={12} lg={8}>
<RealtimeLog data={realtimeData} websites={websites} />
</GridColumn>
<GridColumn xs={12} lg={4}> <GridColumn xs={12} lg={4}>
<DataTable <DataTable
title={<FormattedMessage id="metrics.referrers" defaultMessage="Referrers" />} title={<FormattedMessage id="metrics.referrers" defaultMessage="Referrers" />}
metric={<FormattedMessage id="metrics.views" defaultMessage="Views" />} metric={<FormattedMessage id="metrics.views" defaultMessage="Views" />}
data={referrers} data={referrers}
height={400}
animate={false} animate={false}
/> />
</GridColumn> </GridColumn>
<GridColumn xs={12} lg={8}>
<RealtimeLog data={realtimeData} websites={websites} />
</GridColumn>
</GridRow> </GridRow>
<GridRow> <GridRow>
<GridColumn xs={12} lg={4}> <GridColumn xs={12} lg={4}>
@ -170,6 +171,7 @@ export default function RealtimeDashboard() {
metric={<FormattedMessage id="metrics.visitors" defaultMessage="Visitors" />} metric={<FormattedMessage id="metrics.visitors" defaultMessage="Visitors" />}
data={countries} data={countries}
renderLabel={renderCountryName} renderLabel={renderCountryName}
height={500}
animate={false} animate={false}
/> />
</GridColumn> </GridColumn>

View File

@ -171,7 +171,7 @@ export default function WebsiteDetails({ websiteId, token }) {
contentClassName={styles.content} contentClassName={styles.content}
menu={menuOptions} menu={menuOptions}
> >
<DetailsComponent {...tableProps} limit={false} showFilters={true} /> <DetailsComponent {...tableProps} height={500} limit={false} showFilters={true} />
</MenuLayout> </MenuLayout>
)} )}
</Page> </Page>

View File

@ -1,6 +1,6 @@
{ {
"name": "umami", "name": "umami",
"version": "0.91.0", "version": "0.92.0",
"description": "A simple, fast, website analytics alternative to Google Analytics. ", "description": "A simple, fast, website analytics alternative to Google Analytics. ",
"author": "Mike Cao <mike@mikecao.com>", "author": "Mike Cao <mike@mikecao.com>",
"license": "MIT", "license": "MIT",
@ -83,6 +83,7 @@
"react-simple-maps": "^2.1.2", "react-simple-maps": "^2.1.2",
"react-spring": "^8.0.27", "react-spring": "^8.0.27",
"react-tooltip": "^4.2.10", "react-tooltip": "^4.2.10",
"react-use-measure": "^2.0.2",
"react-window": "^1.8.5", "react-window": "^1.8.5",
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",

View File

@ -3228,6 +3228,11 @@ date-fns@^2.16.1:
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b"
integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ== integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==
debounce@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"
integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
@ -7337,6 +7342,13 @@ react-tooltip@^4.2.10:
prop-types "^15.7.2" prop-types "^15.7.2"
uuid "^7.0.3" uuid "^7.0.3"
react-use-measure@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/react-use-measure/-/react-use-measure-2.0.2.tgz#06b4f99b887d5dfcd7b7167a2da063d97ec8f62f"
integrity sha512-/+eSmQiU2ePNTwFCXX4JPrQNMvyu3sWrSDi/n5F6IMXwboB46IvtU8VHvG7Nc+egvtM7sBJKwmUx/vx6KIRDog==
dependencies:
debounce "^1.2.0"
react-window@^1.8.5: react-window@^1.8.5:
version "1.8.5" version "1.8.5"
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1" resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1"