mirror of
https://github.com/umami-software/umami.git
synced 2026-02-05 21:27:20 +01:00
Merge branch 'dev' of https://github.com/umami-software/umami into dev
# Conflicts: # src/components/metrics/ReferrersTable.tsx
This commit is contained in:
commit
274d654833
17 changed files with 137 additions and 137 deletions
|
|
@ -89,9 +89,16 @@ export function FilterBar({ websiteId }: { websiteId: string }) {
|
|||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
<Modal>
|
||||
<Dialog title={formatMessage(labels.segment)} style={{ width: 800 }}>
|
||||
<Dialog title={formatMessage(labels.segment)} style={{ width: 400 }}>
|
||||
{({ close }) => {
|
||||
return <SegmentEditForm websiteId={websiteId} onClose={close} />;
|
||||
return (
|
||||
<SegmentEditForm
|
||||
websiteId={websiteId}
|
||||
onClose={close}
|
||||
filters={filters}
|
||||
showFilters={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -344,8 +344,9 @@ export const labels = defineMessages({
|
|||
growth: { id: 'label.growth', defaultMessage: 'Growth' },
|
||||
account: { id: 'label.account', defaultMessage: 'Account' },
|
||||
application: { id: 'label.application', defaultMessage: 'Application' },
|
||||
saveSegment: { id: 'label.save-segment', defaultMessage: 'Save segment' },
|
||||
saveCohort: { id: 'label.save-cohort', defaultMessage: 'Save cohort' },
|
||||
saveSegment: { id: 'label.save-segment', defaultMessage: 'Save as segment' },
|
||||
saveCohort: { id: 'label.save-cohort', defaultMessage: 'Save as cohort' },
|
||||
analysis: { id: 'label.analysis', defaultMessage: 'Analysis' },
|
||||
});
|
||||
|
||||
export const messages = defineMessages({
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ import styles from './ListExpandedTable.module.css';
|
|||
export interface ListExpandedTableProps {
|
||||
data?: any[];
|
||||
title?: string;
|
||||
type?: string;
|
||||
renderLabel?: (row: any, index: number) => ReactNode;
|
||||
}
|
||||
|
||||
export function ListExpandedTable({ data = [], title, type, renderLabel }: ListExpandedTableProps) {
|
||||
export function ListExpandedTable({ data = [], title, renderLabel }: ListExpandedTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
return (
|
||||
|
|
@ -32,26 +31,18 @@ export function ListExpandedTable({ data = [], title, type, renderLabel }: ListE
|
|||
<DataColumn id="pageviews" label={formatMessage(labels.views)} align="end">
|
||||
{row => row?.['pageviews']?.toLocaleString()}
|
||||
</DataColumn>
|
||||
{type !== 'exit' && type !== 'entry' ? (
|
||||
<DataColumn id="bounceRate" label={formatMessage(labels.bounceRate)} align="end">
|
||||
{row => {
|
||||
const n = (Math.min(row?.['visits'], row?.['bounces']) / row?.['visits']) * 100;
|
||||
return Math.round(+n) + '%';
|
||||
}}
|
||||
</DataColumn>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{type !== 'exit' && type !== 'entry' ? (
|
||||
<DataColumn id="visitDuration" label={formatMessage(labels.visitDuration)} align="end">
|
||||
{row => {
|
||||
const n = (row?.['totaltime'] / row?.['visits']) * 100;
|
||||
return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`;
|
||||
}}
|
||||
</DataColumn>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<DataColumn id="bounceRate" label={formatMessage(labels.bounceRate)} align="end">
|
||||
{row => {
|
||||
const n = (Math.min(row?.['visits'], row?.['bounces']) / row?.['visits']) * 100;
|
||||
return Math.round(+n) + '%';
|
||||
}}
|
||||
</DataColumn>
|
||||
<DataColumn id="visitDuration" label={formatMessage(labels.visitDuration)} align="end">
|
||||
{row => {
|
||||
const n = (row?.['totaltime'] / row?.['visits']) * 100;
|
||||
return `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`;
|
||||
}}
|
||||
</DataColumn>
|
||||
</DataTable>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ export function MetricsTable({
|
|||
|
||||
return (
|
||||
<Column gap="3" justifyContent="space-between">
|
||||
<LoadingPanel data={data} isFetching={isFetching} isLoading={isLoading} error={error} gap>
|
||||
<LoadingPanel isFetching={isFetching} isLoading={isLoading} error={error} gap>
|
||||
<Row alignItems="center" justifyContent="space-between">
|
||||
{allowSearch && <SearchField value={search} onSearch={setSearch} delay={300} />}
|
||||
<Row>
|
||||
|
|
@ -124,7 +124,7 @@ export function MetricsTable({
|
|||
</Row>
|
||||
{data &&
|
||||
(expanded ? (
|
||||
<ListExpandedTable {...(props as ListExpandedTableProps)} data={data} type={type} />
|
||||
<ListExpandedTable {...(props as ListExpandedTableProps)} data={data} />
|
||||
) : (
|
||||
<ListTable {...(props as ListTableProps)} data={filteredData} />
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { Row } from '@umami/react-zen';
|
||||
import { FilterLink } from '@/components/common/FilterLink';
|
||||
import { Favicon } from '@/components/common/Favicon';
|
||||
import { FilterButtons } from '@/components/input/FilterButtons';
|
||||
import { FilterLink } from '@/components/common/FilterLink';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
import { MetricsTable, MetricsTableProps } from './MetricsTable';
|
||||
import thenby from 'thenby';
|
||||
import { GROUPED_DOMAINS } from '@/lib/constants';
|
||||
import { emptyFilter } from '@/lib/filters';
|
||||
import { Row } from '@umami/react-zen';
|
||||
import { MetricsTable, MetricsTableProps } from './MetricsTable';
|
||||
|
||||
export interface ReferrersTableProps extends MetricsTableProps {
|
||||
allowFilter?: boolean;
|
||||
|
|
@ -36,7 +36,7 @@ export function ReferrersTable({ allowFilter, ...props }: ReferrersTableProps) {
|
|||
|
||||
const renderLink = ({ x: referrer }) => {
|
||||
if (view === 'grouped') {
|
||||
if (referrer === '_other') {
|
||||
if (referrer === 'Other') {
|
||||
return `(${formatMessage(labels.other)})`;
|
||||
} else {
|
||||
return (
|
||||
|
|
@ -60,38 +60,13 @@ export function ReferrersTable({ allowFilter, ...props }: ReferrersTableProps) {
|
|||
);
|
||||
};
|
||||
|
||||
const getDomain = (x: string) => {
|
||||
for (const { domain, match } of GROUPED_DOMAINS) {
|
||||
if (Array.isArray(match) ? match.some(str => x.includes(str)) : x.includes(match)) {
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
return '_other';
|
||||
};
|
||||
|
||||
const groupedFilter = (data: any[]) => {
|
||||
const groups = { _other: 0 };
|
||||
|
||||
for (const { x, y } of data) {
|
||||
const domain = getDomain(x);
|
||||
if (!groups[domain]) {
|
||||
groups[domain] = 0;
|
||||
}
|
||||
groups[domain] += +y;
|
||||
}
|
||||
|
||||
return Object.keys(groups)
|
||||
.map((key: any) => ({ x: key, y: groups[key] }))
|
||||
.sort(thenby.firstBy('y', -1));
|
||||
};
|
||||
|
||||
return (
|
||||
<MetricsTable
|
||||
{...props}
|
||||
title={formatMessage(labels.referrers)}
|
||||
type="referrer"
|
||||
type={view}
|
||||
metric={formatMessage(labels.visitors)}
|
||||
dataFilter={view === 'grouped' ? groupedFilter : undefined}
|
||||
dataFilter={emptyFilter}
|
||||
renderLabel={renderLink}
|
||||
>
|
||||
{allowFilter && <FilterButtons items={buttons} value={view} onChange={handleSelect} />}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue