Merge branch 'dev' into analytics

This commit is contained in:
Mike Cao 2023-08-25 17:07:00 -07:00
commit ac43f55636
14 changed files with 65 additions and 58 deletions

View File

@ -1,6 +1,6 @@
{
"name": "umami",
"version": "2.5.0",
"version": "2.6.0",
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
"author": "Mike Cao <mike@mikecao.com>",
"license": "MIT",

View File

@ -29,16 +29,6 @@ const aliasConfig = {
customResolver,
};
const external = [
'react',
'react-dom',
'react/jsx-runtime',
'react-intl',
'react-basics',
'classnames',
'next',
];
const jsBundle = {
input: 'src/index.ts',
output: [

View File

@ -4,7 +4,7 @@ const path = require('path');
const https = require('https');
const chalk = require('chalk');
const src = path.resolve(__dirname, '../lang');
const src = path.resolve(__dirname, '../src/lang');
const dest = path.resolve(__dirname, '../public/intl/country');
const files = fs.readdirSync(src);

View File

@ -4,7 +4,7 @@ const path = require('path');
const https = require('https');
const chalk = require('chalk');
const src = path.resolve(__dirname, '../lang');
const src = path.resolve(__dirname, '../src/lang');
const dest = path.resolve(__dirname, '../public/intl/language');
const files = fs.readdirSync(src);

View File

@ -3,7 +3,7 @@ const path = require('path');
const del = require('del');
const prettier = require('prettier');
const src = path.resolve(__dirname, '../lang');
const src = path.resolve(__dirname, '../src/lang');
const dest = path.resolve(__dirname, '../build/messages');
const files = fs.readdirSync(src);
@ -17,7 +17,7 @@ async function run() {
await fs.ensureDir(dest);
files.forEach(file => {
const lang = require(`../lang/${file}`);
const lang = require(`../src/lang/${file}`);
const keys = Object.keys(lang).sort();
const formatted = keys.reduce((obj, key) => {

View File

@ -1,3 +1,4 @@
import { createPortal } from 'react-dom';
import classNames from 'classnames';
import { useRouter } from 'next/router';
import Link from 'next/link';
@ -28,10 +29,11 @@ export function MobileMenu({ items = [], onClose }) {
</div>
);
return (
return createPortal(
<div className={classNames(styles.menu)}>
<Items items={items} />
</div>
</div>,
document.body,
);
}

View File

@ -8,9 +8,10 @@ import styles from './WebsiteDateFilter.module.css';
export function WebsiteDateFilter({ websiteId }) {
const [dateRange, setDateRange] = useDateRange(websiteId);
const { value, startDate, endDate, selectedUnit } = dateRange;
const isFutureDate =
value !== 'all' && isAfter(incrementDateRange(dateRange, -1).startDate, new Date());
value !== 'all' &&
selectedUnit &&
isAfter(incrementDateRange(dateRange, -1).startDate, new Date());
const handleChange = value => {
setDateRange(value);
@ -21,7 +22,21 @@ export function WebsiteDateFilter({ websiteId }) {
};
return (
<>
<Flexbox justifyContent="center" gap={10}>
{value !== 'all' && selectedUnit && (
<Flexbox justifyContent="center" className={styles.buttons}>
<Button onClick={() => handleIncrement(1)}>
<Icon rotate={90}>
<Icons.ChevronDown />
</Icon>
</Button>
<Button onClick={() => handleIncrement(-1)} disabled={isFutureDate}>
<Icon rotate={270}>
<Icons.ChevronDown />
</Icon>
</Button>
</Flexbox>
)}
<DateFilter
className={styles.dropdown}
value={value}
@ -31,22 +46,7 @@ export function WebsiteDateFilter({ websiteId }) {
onChange={handleChange}
showAllTime={true}
/>
{value !== 'all' && (
<Flexbox justifyContent="center" gap={10} className={styles.container}>
<Button onClick={() => handleIncrement(1)}>
<Icon rotate={90}>
<Icons.ChevronDown />
</Icon>
</Button>
<Button onClick={() => handleIncrement(-1)} disabled={isFutureDate}>
<Icon rotate={270}>
<Icons.ChevronDown />
</Icon>
</Button>
</Flexbox>
)}
</>
</Flexbox>
);
}

View File

@ -1,3 +1,14 @@
.dropdown {
min-width: 200px;
}
.buttons button:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.buttons button:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 1px solid var(--base400) !important;
}

View File

@ -10,7 +10,7 @@
width: 100vw;
grid-column: 1;
grid-row: 1 / 2;
z-index: 1;
z-index: var(--z-index-popup);
}
.body {

View File

@ -1,8 +1,8 @@
import { safeDecodeURI } from 'next-basics';
import { Button, Icon, Icons, Text } from 'react-basics';
import usePageQuery from 'components/hooks/usePageQuery';
import styles from './FilterTags.module.css';
import useMessages from 'components/hooks/useMessages';
import styles from './FilterTags.module.css';
export function FilterTags({ params }) {
const { formatMessage, labels } = useMessages();
@ -26,6 +26,7 @@ export function FilterTags({ params }) {
return (
<div className={styles.filters}>
<div className={styles.label}>{formatMessage(labels.filters)}</div>
{Object.keys(params).map(key => {
if (!params[key]) {
return null;

View File

@ -4,19 +4,23 @@
gap: 10px;
}
.label {
font-weight: 700;
}
.tag {
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
font-size: var(--font-size-sm);
border: 1px solid var(--base600);
border: 1px solid var(--blue400);
border-radius: var(--border-radius);
line-height: 30px;
padding: 0 8px;
padding: 8px 16px;
cursor: pointer;
background: var(--blue100);
}
.tag:hover {
background: var(--base75);
background: var(--blue200);
}

View File

@ -22,12 +22,12 @@ export default function WebsiteDetailsPage({ websiteId }) {
return (
<Page loading={isLoading} error={error}>
<WebsiteHeader websiteId={websiteId} showLinks={showLinks} />
<WebsiteMetricsBar websiteId={websiteId} sticky={true} />
<WebsiteChart websiteId={websiteId} />
<FilterTags
websiteId={websiteId}
params={{ url, referrer, os, browser, device, country, region, city, title }}
/>
<WebsiteMetricsBar websiteId={websiteId} sticky={true} />
<WebsiteChart websiteId={websiteId} />
{!website && <Loading icon="dots" style={{ minHeight: 300 }} />}
{website && (
<>

View File

@ -1,4 +1,4 @@
import { Flexbox } from 'react-basics';
import { Flexbox, Loading } from 'react-basics';
import EventDataTable from 'components/pages/event-data/EventDataTable';
import EventDataValueTable from 'components/pages/event-data/EventDataValueTable';
import { EventDataMetricsBar } from 'components/pages/event-data/EventDataMetricsBar';
@ -28,13 +28,14 @@ export default function WebsiteEventData({ websiteId }) {
const {
query: { event },
} = usePageQuery();
const { data } = useData(websiteId, event);
const { data, isLoading } = useData(websiteId, event);
return (
<Flexbox className={styles.container} direction="column" gap={20}>
<EventDataMetricsBar websiteId={websiteId} />
{!event && <EventDataTable data={data} />}
{event && <EventDataValueTable event={event} data={data} />}
{isLoading && <Loading position="page" />}
{event && data && <EventDataValueTable event={event} data={data} />}
</Flexbox>
);
}

View File

@ -7,10 +7,10 @@ import MetricsBar from 'components/metrics/MetricsBar';
import FilterSelectForm from 'components/pages/reports/FilterSelectForm';
import PopupForm from 'components/pages/reports/PopupForm';
import { formatShortTime } from 'lib/format';
import { Button, Column, Icon, Icons, Popup, PopupTrigger, Row, TooltipPopup } from 'react-basics';
import { Button, Column, Icon, Icons, Popup, PopupTrigger, Row } from 'react-basics';
import styles from './WebsiteMetricsBar.module.css';
export function WebsiteMetricsBar({ websiteId, showFilter = true, sticky }) {
export function WebsiteMetricsBar({ websiteId, showFilter = true, showRefresh = true, sticky }) {
const { formatMessage, labels } = useMessages();
const { get, useQuery } = useApi();
@ -71,14 +71,12 @@ export function WebsiteMetricsBar({ websiteId, showFilter = true, sticky }) {
const WebsiteFilterButton = () => {
return (
<PopupTrigger>
<TooltipPopup label={formatMessage(labels.addFilter)} position="top">
<Button>
<Icon>
<Icons.Plus />
</Icon>
{formatMessage(labels.filter)}
</Button>
</TooltipPopup>
<Button>
<Icon>
<Icons.Plus />
</Icon>
{formatMessage(labels.filter)}
</Button>
<Popup position="bottom" alignment="start" className={styles.popup}>
{close => {
return (
@ -163,8 +161,8 @@ export function WebsiteMetricsBar({ websiteId, showFilter = true, sticky }) {
<Column defaultSize={12} xl={4}>
<div className={styles.actions}>
{showFilter && <WebsiteFilterButton />}
{showRefresh && <RefreshButton websiteId={websiteId} />}
<WebsiteDateFilter websiteId={websiteId} />
<RefreshButton websiteId={websiteId} />
</div>
</Column>
</Row>