mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 12:47:13 +01:00
Refactored tables.
This commit is contained in:
parent
600a3d28c3
commit
c8fe93dd9d
56 changed files with 643 additions and 1038 deletions
|
|
@ -13,7 +13,7 @@ import {
|
|||
LayoutDashboard,
|
||||
Link as LinkIcon,
|
||||
Logo,
|
||||
Grid2X2,
|
||||
Pixel,
|
||||
Settings,
|
||||
PanelLeft,
|
||||
} from '@/components/icons';
|
||||
|
|
@ -21,6 +21,7 @@ import { useMessages, useNavigation, useGlobalState } from '@/components/hooks';
|
|||
import { TeamsButton } from '@/components/input/TeamsButton';
|
||||
import { PanelButton } from '@/components/input/PanelButton';
|
||||
import { ProfileButton } from '@/components/input/ProfileButton';
|
||||
import { LanguageButton } from '@/components/input/LanguageButton';
|
||||
|
||||
export function SideNav(props: SidebarProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
@ -52,7 +53,7 @@ export function SideNav(props: SidebarProps) {
|
|||
id: 'pixels',
|
||||
label: formatMessage(labels.pixels),
|
||||
path: '/pixels',
|
||||
icon: <Grid2X2 />,
|
||||
icon: <Pixel />,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -97,6 +98,7 @@ export function SideNav(props: SidebarProps) {
|
|||
<ProfileButton />
|
||||
{!isCollapsed && !hasNav && (
|
||||
<Row>
|
||||
<LanguageButton />
|
||||
<ThemeButton />
|
||||
</Row>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useLink, useMessages, useSlug } from '@/components/hooks';
|
||||
import { PageHeader } from '@/components/common/PageHeader';
|
||||
import { Icon, Text } from '@umami/react-zen';
|
||||
import { ExternalLink } from '@/components/icons';
|
||||
import { ExternalLink, Link } from '@/components/icons';
|
||||
import { LinkButton } from '@/components/common/LinkButton';
|
||||
|
||||
export function LinkHeader() {
|
||||
|
|
@ -10,7 +10,7 @@ export function LinkHeader() {
|
|||
const link = useLink();
|
||||
|
||||
return (
|
||||
<PageHeader title={link.name} description={link.url}>
|
||||
<PageHeader title={link.name} description={link.url} icon={<Link />}>
|
||||
<LinkButton href={getSlugUrl(link.slug)} target="_blank">
|
||||
<Icon>
|
||||
<ExternalLink />
|
||||
|
|
|
|||
|
|
@ -6,25 +6,9 @@ import { Panel } from '@/components/common/Panel';
|
|||
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
|
||||
import { LinkMetricsBar } from '@/app/(main)/links/[linkId]/LinkMetricsBar';
|
||||
import { LinkControls } from '@/app/(main)/links/[linkId]/LinkControls';
|
||||
import { Grid, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
|
||||
import { GridRow } from '@/components/common/GridRow';
|
||||
import { ReferrersTable } from '@/components/metrics/ReferrersTable';
|
||||
import { BrowsersTable } from '@/components/metrics/BrowsersTable';
|
||||
import { OSTable } from '@/components/metrics/OSTable';
|
||||
import { DevicesTable } from '@/components/metrics/DevicesTable';
|
||||
import { WorldMap } from '@/components/metrics/WorldMap';
|
||||
import { CountriesTable } from '@/components/metrics/CountriesTable';
|
||||
import { ChannelsTable } from '@/components/metrics/ChannelsTable';
|
||||
import { RegionsTable } from '@/components/metrics/RegionsTable';
|
||||
import { CitiesTable } from '@/components/metrics/CitiesTable';
|
||||
import { SessionsWeekly } from '@/app/(main)/websites/[websiteId]/sessions/SessionsWeekly';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
import { LinkPanels } from '@/app/(main)/links/[linkId]/LinkPanels';
|
||||
|
||||
export function LinkPage({ linkId }: { linkId: string }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const tableProps = { websiteId: linkId, limit: 10, allowDownload: false };
|
||||
const rowProps = { minHeight: 570 };
|
||||
|
||||
return (
|
||||
<LinkProvider linkId={linkId}>
|
||||
<PageBody gap>
|
||||
|
|
@ -34,70 +18,7 @@ export function LinkPage({ linkId }: { linkId: string }) {
|
|||
<Panel>
|
||||
<WebsiteChart websiteId={linkId} />
|
||||
</Panel>
|
||||
<Grid gap>
|
||||
<GridRow layout="one" {...rowProps}>
|
||||
<Panel>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="referrer">{formatMessage(labels.referrers)}</Tab>
|
||||
<Tab id="channel">{formatMessage(labels.channels)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="referrer">
|
||||
<ReferrersTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="channel">
|
||||
<ChannelsTable {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
<GridRow layout="two-one" {...rowProps}>
|
||||
<Panel gridColumn="span 2" noPadding>
|
||||
<WorldMap websiteId={linkId} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="country">{formatMessage(labels.countries)}</Tab>
|
||||
<Tab id="region">{formatMessage(labels.regions)}</Tab>
|
||||
<Tab id="city">{formatMessage(labels.cities)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="country">
|
||||
<CountriesTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="region">
|
||||
<RegionsTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="city">
|
||||
<CitiesTable {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="browser">{formatMessage(labels.browsers)}</Tab>
|
||||
<Tab id="os">{formatMessage(labels.os)}</Tab>
|
||||
<Tab id="device">{formatMessage(labels.devices)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="browser">
|
||||
<BrowsersTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="os">
|
||||
<OSTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="device">
|
||||
<DevicesTable {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
<Panel>
|
||||
<SessionsWeekly websiteId={linkId} />
|
||||
</Panel>
|
||||
</GridRow>
|
||||
</Grid>
|
||||
<LinkPanels linkId={linkId} />
|
||||
</PageBody>
|
||||
</LinkProvider>
|
||||
);
|
||||
|
|
|
|||
83
src/app/(main)/links/[linkId]/LinkPanels.tsx
Normal file
83
src/app/(main)/links/[linkId]/LinkPanels.tsx
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { Grid, Tabs, Tab, TabList, TabPanel, Heading } from '@umami/react-zen';
|
||||
import { GridRow } from '@/components/common/GridRow';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { WorldMap } from '@/components/metrics/WorldMap';
|
||||
import { MetricsTable } from '@/components/metrics/MetricsTable';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
|
||||
export function LinkPanels({ linkId }: { linkId: string }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const tableProps = {
|
||||
websiteId: linkId,
|
||||
limit: 10,
|
||||
allowDownload: false,
|
||||
showMore: true,
|
||||
metric: formatMessage(labels.visitors),
|
||||
};
|
||||
const rowProps = { minHeight: 570 };
|
||||
|
||||
return (
|
||||
<Grid gap="3">
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.sources)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="referrer">{formatMessage(labels.referrers)}</Tab>
|
||||
<Tab id="channel">{formatMessage(labels.channels)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="referrer">
|
||||
<MetricsTable type="referrer" title={formatMessage(labels.domain)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="channel">
|
||||
<MetricsTable type="channel" title={formatMessage(labels.type)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.environment)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="browser">{formatMessage(labels.browsers)}</Tab>
|
||||
<Tab id="os">{formatMessage(labels.os)}</Tab>
|
||||
<Tab id="device">{formatMessage(labels.devices)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="browser">
|
||||
<MetricsTable type="browser" title={formatMessage(labels.browser)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="os">
|
||||
<MetricsTable type="os" title={formatMessage(labels.os)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="device">
|
||||
<MetricsTable type="device" title={formatMessage(labels.device)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel noPadding>
|
||||
<WorldMap websiteId={linkId} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.location)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="country">{formatMessage(labels.countries)}</Tab>
|
||||
<Tab id="region">{formatMessage(labels.regions)}</Tab>
|
||||
<Tab id="city">{formatMessage(labels.cities)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="country">
|
||||
<MetricsTable type="country" title={formatMessage(labels.country)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="region">
|
||||
<MetricsTable type="region" title={formatMessage(labels.region)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="city">
|
||||
<MetricsTable type="city" title={formatMessage(labels.city)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { usePixel, useMessages, useSlug } from '@/components/hooks';
|
||||
import { PageHeader } from '@/components/common/PageHeader';
|
||||
import { Icon, Text } from '@umami/react-zen';
|
||||
import { ExternalLink } from '@/components/icons';
|
||||
import { ExternalLink, Pixel } from '@/components/icons';
|
||||
import { LinkButton } from '@/components/common/LinkButton';
|
||||
|
||||
export function PixelHeader() {
|
||||
|
|
@ -10,7 +10,7 @@ export function PixelHeader() {
|
|||
const pixel = usePixel();
|
||||
|
||||
return (
|
||||
<PageHeader title={pixel.name} description={pixel.url}>
|
||||
<PageHeader title={pixel.name} description={pixel.url} icon={<Pixel />}>
|
||||
<LinkButton href={getSlugUrl(pixel.slug)} target="_blank">
|
||||
<Icon>
|
||||
<ExternalLink />
|
||||
|
|
|
|||
|
|
@ -6,25 +6,9 @@ import { Panel } from '@/components/common/Panel';
|
|||
import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
|
||||
import { PixelMetricsBar } from '@/app/(main)/pixels/[pixelId]/PixelMetricsBar';
|
||||
import { PixelControls } from '@/app/(main)/pixels/[pixelId]/PixelControls';
|
||||
import { Grid, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
|
||||
import { GridRow } from '@/components/common/GridRow';
|
||||
import { ReferrersTable } from '@/components/metrics/ReferrersTable';
|
||||
import { BrowsersTable } from '@/components/metrics/BrowsersTable';
|
||||
import { OSTable } from '@/components/metrics/OSTable';
|
||||
import { DevicesTable } from '@/components/metrics/DevicesTable';
|
||||
import { WorldMap } from '@/components/metrics/WorldMap';
|
||||
import { CountriesTable } from '@/components/metrics/CountriesTable';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
import { ChannelsTable } from '@/components/metrics/ChannelsTable';
|
||||
import { RegionsTable } from '@/components/metrics/RegionsTable';
|
||||
import { CitiesTable } from '@/components/metrics/CitiesTable';
|
||||
import { SessionsWeekly } from '@/app/(main)/websites/[websiteId]/sessions/SessionsWeekly';
|
||||
import { PixelPanels } from '@/app/(main)/pixels/[pixelId]/PixelPanels';
|
||||
|
||||
export function PixelPage({ pixelId }: { pixelId: string }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const tableProps = { websiteId: pixelId, limit: 10, allowDownload: false };
|
||||
const rowProps = { minHeight: 570 };
|
||||
|
||||
return (
|
||||
<PixelProvider pixelId={pixelId}>
|
||||
<PageBody gap>
|
||||
|
|
@ -34,70 +18,7 @@ export function PixelPage({ pixelId }: { pixelId: string }) {
|
|||
<Panel>
|
||||
<WebsiteChart websiteId={pixelId} />
|
||||
</Panel>
|
||||
<Grid gap>
|
||||
<GridRow layout="one" {...rowProps}>
|
||||
<Panel>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="referrer">{formatMessage(labels.referrers)}</Tab>
|
||||
<Tab id="channel">{formatMessage(labels.channels)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="referrer">
|
||||
<ReferrersTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="channel">
|
||||
<ChannelsTable {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
<GridRow layout="two-one" {...rowProps}>
|
||||
<Panel gridColumn="span 2" noPadding>
|
||||
<WorldMap websiteId={pixelId} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="country">{formatMessage(labels.countries)}</Tab>
|
||||
<Tab id="region">{formatMessage(labels.regions)}</Tab>
|
||||
<Tab id="city">{formatMessage(labels.cities)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="country">
|
||||
<CountriesTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="region">
|
||||
<RegionsTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="city">
|
||||
<CitiesTable {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="browser">{formatMessage(labels.browsers)}</Tab>
|
||||
<Tab id="os">{formatMessage(labels.os)}</Tab>
|
||||
<Tab id="device">{formatMessage(labels.devices)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="browser">
|
||||
<BrowsersTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="os">
|
||||
<OSTable {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="device">
|
||||
<DevicesTable {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
<Panel>
|
||||
<SessionsWeekly websiteId={pixelId} />
|
||||
</Panel>
|
||||
</GridRow>
|
||||
</Grid>
|
||||
<PixelPanels pixelId={pixelId} />
|
||||
</PageBody>
|
||||
</PixelProvider>
|
||||
);
|
||||
|
|
|
|||
83
src/app/(main)/pixels/[pixelId]/PixelPanels.tsx
Normal file
83
src/app/(main)/pixels/[pixelId]/PixelPanels.tsx
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { Grid, Tabs, Tab, TabList, TabPanel, Heading } from '@umami/react-zen';
|
||||
import { GridRow } from '@/components/common/GridRow';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { WorldMap } from '@/components/metrics/WorldMap';
|
||||
import { MetricsTable } from '@/components/metrics/MetricsTable';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
|
||||
export function PixelPanels({ pixelId }: { pixelId: string }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const tableProps = {
|
||||
websiteId: pixelId,
|
||||
limit: 10,
|
||||
allowDownload: false,
|
||||
showMore: true,
|
||||
metric: formatMessage(labels.visitors),
|
||||
};
|
||||
const rowProps = { minHeight: 570 };
|
||||
|
||||
return (
|
||||
<Grid gap="3">
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.sources)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="referrer">{formatMessage(labels.referrers)}</Tab>
|
||||
<Tab id="channel">{formatMessage(labels.channels)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="referrer">
|
||||
<MetricsTable type="referrer" title={formatMessage(labels.domain)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="channel">
|
||||
<MetricsTable type="channel" title={formatMessage(labels.type)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.environment)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="browser">{formatMessage(labels.browsers)}</Tab>
|
||||
<Tab id="os">{formatMessage(labels.os)}</Tab>
|
||||
<Tab id="device">{formatMessage(labels.devices)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="browser">
|
||||
<MetricsTable type="browser" title={formatMessage(labels.browser)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="os">
|
||||
<MetricsTable type="os" title={formatMessage(labels.os)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="device">
|
||||
<MetricsTable type="device" title={formatMessage(labels.device)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel noPadding>
|
||||
<WorldMap websiteId={pixelId} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.location)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="country">{formatMessage(labels.countries)}</Tab>
|
||||
<Tab id="region">{formatMessage(labels.regions)}</Tab>
|
||||
<Tab id="city">{formatMessage(labels.cities)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="country">
|
||||
<MetricsTable type="country" title={formatMessage(labels.country)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="region">
|
||||
<MetricsTable type="region" title={formatMessage(labels.region)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="city">
|
||||
<MetricsTable type="city" title={formatMessage(labels.city)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
|
@ -47,7 +47,13 @@ export function WebsiteChart({
|
|||
}, [data, startDate, endDate, unit]);
|
||||
|
||||
return (
|
||||
<LoadingPanel data={data} isFetching={isFetching} isLoading={isLoading} error={error}>
|
||||
<LoadingPanel
|
||||
data={data}
|
||||
isFetching={isFetching}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
minHeight="520px"
|
||||
>
|
||||
<PageviewsChart
|
||||
key={value}
|
||||
data={chartData}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,12 @@
|
|||
import { Grid, Heading, Column, Row, NavMenu, NavMenuItem, Text } from '@umami/react-zen';
|
||||
import { useDateRange, useMessages, useNavigation } from '@/components/hooks';
|
||||
import { BrowsersTable } from '@/components/metrics/BrowsersTable';
|
||||
import { ChangeLabel } from '@/components/metrics/ChangeLabel';
|
||||
import { CitiesTable } from '@/components/metrics/CitiesTable';
|
||||
import { CountriesTable } from '@/components/metrics/CountriesTable';
|
||||
import { DevicesTable } from '@/components/metrics/DevicesTable';
|
||||
import { EventsTable } from '@/components/metrics/EventsTable';
|
||||
import { LanguagesTable } from '@/components/metrics/LanguagesTable';
|
||||
import { MetricsTable } from '@/components/metrics/MetricsTable';
|
||||
import { OSTable } from '@/components/metrics/OSTable';
|
||||
import { PagesTable } from '@/components/metrics/PagesTable';
|
||||
import { QueryParametersTable } from '@/components/metrics/QueryParametersTable';
|
||||
import { ReferrersTable } from '@/components/metrics/ReferrersTable';
|
||||
import { RegionsTable } from '@/components/metrics/RegionsTable';
|
||||
import { ScreenTable } from '@/components/metrics/ScreenTable';
|
||||
import { TagsTable } from '@/components/metrics/TagsTable';
|
||||
import { getCompareDate } from '@/lib/date';
|
||||
import { formatNumber } from '@/lib/format';
|
||||
import { useState } from 'react';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { DateDisplay } from '@/components/common/DateDisplay';
|
||||
|
||||
const views = {
|
||||
path: PagesTable,
|
||||
title: PagesTable,
|
||||
referrer: ReferrersTable,
|
||||
browser: BrowsersTable,
|
||||
os: OSTable,
|
||||
device: DevicesTable,
|
||||
screen: ScreenTable,
|
||||
country: CountriesTable,
|
||||
region: RegionsTable,
|
||||
city: CitiesTable,
|
||||
language: LanguagesTable,
|
||||
event: EventsTable,
|
||||
query: QueryParametersTable,
|
||||
tag: TagsTable,
|
||||
};
|
||||
import { ChangeLabel } from '@/components/metrics/ChangeLabel';
|
||||
|
||||
export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
|
||||
const [data] = useState([]);
|
||||
|
|
@ -46,7 +16,6 @@ export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
|
|||
updateParams,
|
||||
query: { view },
|
||||
} = useNavigation();
|
||||
const Component: typeof MetricsTable = views[view || 'path'] || (() => null);
|
||||
|
||||
const items = [
|
||||
{
|
||||
|
|
@ -121,7 +90,7 @@ export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
|
|||
},
|
||||
];
|
||||
|
||||
const renderChange = ({ x, y }) => {
|
||||
const renderChange = ({ label: x, count: y }) => {
|
||||
const prev = data.find(d => d.x === x)?.y;
|
||||
const value = y - prev;
|
||||
const change = Math.abs(((y - prev) / prev) * 100);
|
||||
|
|
@ -163,15 +132,22 @@ export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
|
|||
<Heading size="1">{formatMessage(labels.previous)}</Heading>
|
||||
<DateDisplay startDate={startDate} endDate={endDate} />
|
||||
</Row>
|
||||
<Component websiteId={websiteId} limit={20} showMore={false} params={params} />
|
||||
<MetricsTable
|
||||
websiteId={websiteId}
|
||||
type={view}
|
||||
limit={20}
|
||||
showMore={false}
|
||||
params={params}
|
||||
/>
|
||||
</Column>
|
||||
<Column border="left" paddingLeft="6" gap="6">
|
||||
<Row alignItems="center" justifyContent="space-between">
|
||||
<Heading size="1"> {formatMessage(labels.current)}</Heading>
|
||||
<DateDisplay startDate={dateRange.startDate} endDate={dateRange.endDate} />
|
||||
</Row>
|
||||
<Component
|
||||
<MetricsTable
|
||||
websiteId={websiteId}
|
||||
type={view}
|
||||
limit={20}
|
||||
showMore={false}
|
||||
renderChange={renderChange}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,7 @@
|
|||
import Link from 'next/link';
|
||||
import { Grid, Column, NavMenu, NavMenuItem } from '@umami/react-zen';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
import { BrowsersTable } from '@/components/metrics/BrowsersTable';
|
||||
import { CitiesTable } from '@/components/metrics/CitiesTable';
|
||||
import { CountriesTable } from '@/components/metrics/CountriesTable';
|
||||
import { DevicesTable } from '@/components/metrics/DevicesTable';
|
||||
import { EventsTable } from '@/components/metrics/EventsTable';
|
||||
import { HostnamesTable } from '@/components/metrics/HostnamesTable';
|
||||
import { LanguagesTable } from '@/components/metrics/LanguagesTable';
|
||||
import { OSTable } from '@/components/metrics/OSTable';
|
||||
import { PagesTable } from '@/components/metrics/PagesTable';
|
||||
import { QueryParametersTable } from '@/components/metrics/QueryParametersTable';
|
||||
import { ReferrersTable } from '@/components/metrics/ReferrersTable';
|
||||
import { RegionsTable } from '@/components/metrics/RegionsTable';
|
||||
import { ScreenTable } from '@/components/metrics/ScreenTable';
|
||||
import { TagsTable } from '@/components/metrics/TagsTable';
|
||||
import { ChannelsTable } from '@/components/metrics/ChannelsTable';
|
||||
import Link from 'next/link';
|
||||
|
||||
const views = {
|
||||
path: PagesTable,
|
||||
entry: PagesTable,
|
||||
exit: PagesTable,
|
||||
title: PagesTable,
|
||||
referrer: ReferrersTable,
|
||||
grouped: ReferrersTable,
|
||||
hostname: HostnamesTable,
|
||||
browser: BrowsersTable,
|
||||
os: OSTable,
|
||||
device: DevicesTable,
|
||||
screen: ScreenTable,
|
||||
country: CountriesTable,
|
||||
region: RegionsTable,
|
||||
city: CitiesTable,
|
||||
language: LanguagesTable,
|
||||
event: EventsTable,
|
||||
query: QueryParametersTable,
|
||||
tag: TagsTable,
|
||||
channel: ChannelsTable,
|
||||
};
|
||||
import { MetricsExpandedTable } from '@/components/metrics/MetricsExpandedTable';
|
||||
|
||||
export function WebsiteExpandedView({
|
||||
websiteId,
|
||||
|
|
@ -130,8 +94,6 @@ export function WebsiteExpandedView({
|
|||
},
|
||||
];
|
||||
|
||||
const DetailsComponent = views[view] || (() => null);
|
||||
|
||||
return (
|
||||
<Grid columns="auto 1fr" gap="6" height="100%" overflow="hidden">
|
||||
<Column gap="6" width="200px" border="right" paddingRight="3">
|
||||
|
|
@ -146,15 +108,13 @@ export function WebsiteExpandedView({
|
|||
</NavMenu>
|
||||
</Column>
|
||||
<Column overflow="hidden">
|
||||
<DetailsComponent
|
||||
<MetricsExpandedTable
|
||||
title={formatMessage(labels[view])}
|
||||
type={view}
|
||||
websiteId={websiteId}
|
||||
animate={false}
|
||||
virtualize={true}
|
||||
itemCount={25}
|
||||
allowFilter={true}
|
||||
allowSearch={true}
|
||||
isExpanded={true}
|
||||
onClose={onClose}
|
||||
allowSearch
|
||||
allowDownload
|
||||
/>
|
||||
</Column>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Panel } from '@/components/common/Panel';
|
|||
import { WebsiteChart } from './WebsiteChart';
|
||||
import { WebsiteExpandedView } from './WebsiteExpandedView';
|
||||
import { WebsiteMetricsBar } from './WebsiteMetricsBar';
|
||||
import { WebsiteTableView } from './WebsiteTableView';
|
||||
import { WebsitePanels } from './WebsitePanels';
|
||||
import { WebsiteControls } from './WebsiteControls';
|
||||
|
||||
export function WebsitePage({ websiteId }: { websiteId: string }) {
|
||||
|
|
@ -32,7 +32,7 @@ export function WebsitePage({ websiteId }: { websiteId: string }) {
|
|||
<Panel>
|
||||
<WebsiteChart websiteId={websiteId} compareMode={compare} />
|
||||
</Panel>
|
||||
<WebsiteTableView websiteId={websiteId} />
|
||||
<WebsitePanels websiteId={websiteId} />
|
||||
<Modal isOpen={!!view} onOpenChange={handleOpenChange} isDismissable>
|
||||
<Dialog style={{ maxWidth: 1320, width: '100vw', height: 'calc(100vh - 40px)' }}>
|
||||
{({ close }) => {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
import { Grid, Tabs, Tab, TabList, TabPanel } from '@umami/react-zen';
|
||||
import { Grid, Tabs, Tab, TabList, TabPanel, Heading, Row } from '@umami/react-zen';
|
||||
import { GridRow } from '@/components/common/GridRow';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
import { PagesTable } from '@/components/metrics/PagesTable';
|
||||
import { ReferrersTable } from '@/components/metrics/ReferrersTable';
|
||||
import { BrowsersTable } from '@/components/metrics/BrowsersTable';
|
||||
import { OSTable } from '@/components/metrics/OSTable';
|
||||
import { DevicesTable } from '@/components/metrics/DevicesTable';
|
||||
import { WorldMap } from '@/components/metrics/WorldMap';
|
||||
import { CountriesTable } from '@/components/metrics/CountriesTable';
|
||||
import { MetricsTable } from '@/components/metrics/MetricsTable';
|
||||
import { WeeklyTraffic } from '@/components/metrics/WeeklyTraffic';
|
||||
import { useMessages } from '@/components/hooks';
|
||||
import { ChannelsTable } from '@/components/metrics/ChannelsTable';
|
||||
import { RegionsTable } from '@/components/metrics/RegionsTable';
|
||||
import { CitiesTable } from '@/components/metrics/CitiesTable';
|
||||
import { SessionsWeekly } from '@/app/(main)/websites/[websiteId]/sessions/SessionsWeekly';
|
||||
|
||||
export function WebsiteTableView({ websiteId }: { websiteId: string }) {
|
||||
export function WebsitePanels({ websiteId }: { websiteId: string }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const tableProps = { websiteId, limit: 10, allowDownload: false };
|
||||
const tableProps = {
|
||||
websiteId,
|
||||
limit: 10,
|
||||
allowDownload: false,
|
||||
showMore: true,
|
||||
metric: formatMessage(labels.visitors),
|
||||
};
|
||||
const rowProps = { minHeight: 570 };
|
||||
|
||||
return (
|
||||
<Grid gap="3">
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.pages)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="page">{formatMessage(labels.pages)}</Tab>
|
||||
|
|
@ -30,27 +29,28 @@ export function WebsiteTableView({ websiteId }: { websiteId: string }) {
|
|||
<Tab id="exit">{formatMessage(labels.exit)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="page">
|
||||
<PagesTable type="path" {...tableProps} />
|
||||
<MetricsTable type="path" title={formatMessage(labels.path)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="entry">
|
||||
<PagesTable type="entry" {...tableProps} />
|
||||
<MetricsTable type="entry" title={formatMessage(labels.path)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="exit">
|
||||
<PagesTable type="exit" {...tableProps} />
|
||||
<MetricsTable type="exit" title={formatMessage(labels.path)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.sources)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="referrer">{formatMessage(labels.referrers)}</Tab>
|
||||
<Tab id="channel">{formatMessage(labels.channels)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="referrer">
|
||||
<ReferrersTable {...tableProps} />
|
||||
<MetricsTable type="referrer" title={formatMessage(labels.domain)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="channel">
|
||||
<ChannelsTable {...tableProps} />
|
||||
<MetricsTable type="channel" title={formatMessage(labels.type)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
|
|
@ -60,6 +60,7 @@ export function WebsiteTableView({ websiteId }: { websiteId: string }) {
|
|||
<WorldMap websiteId={websiteId} />
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.location)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="country">{formatMessage(labels.countries)}</Tab>
|
||||
|
|
@ -67,19 +68,20 @@ export function WebsiteTableView({ websiteId }: { websiteId: string }) {
|
|||
<Tab id="city">{formatMessage(labels.cities)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="country">
|
||||
<CountriesTable {...tableProps} />
|
||||
<MetricsTable type="country" title={formatMessage(labels.country)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="region">
|
||||
<RegionsTable {...tableProps} />
|
||||
<MetricsTable type="region" title={formatMessage(labels.region)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="city">
|
||||
<CitiesTable {...tableProps} />
|
||||
<MetricsTable type="city" title={formatMessage(labels.city)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
</GridRow>
|
||||
<GridRow layout="two" {...rowProps}>
|
||||
<Panel>
|
||||
<Heading size="2">{formatMessage(labels.environment)}</Heading>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab id="browser">{formatMessage(labels.browsers)}</Tab>
|
||||
|
|
@ -87,18 +89,20 @@ export function WebsiteTableView({ websiteId }: { websiteId: string }) {
|
|||
<Tab id="device">{formatMessage(labels.devices)}</Tab>
|
||||
</TabList>
|
||||
<TabPanel id="browser">
|
||||
<BrowsersTable {...tableProps} />
|
||||
<MetricsTable type="browser" title={formatMessage(labels.browser)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="os">
|
||||
<OSTable {...tableProps} />
|
||||
<MetricsTable type="os" title={formatMessage(labels.os)} {...tableProps} />
|
||||
</TabPanel>
|
||||
<TabPanel id="device">
|
||||
<DevicesTable {...tableProps} />
|
||||
<MetricsTable type="device" title={formatMessage(labels.device)} {...tableProps} />
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Panel>
|
||||
<Panel>
|
||||
<SessionsWeekly websiteId={websiteId} />
|
||||
<Heading size="2">{formatMessage(labels.traffic)}</Heading>
|
||||
<Row border="bottom" marginBottom="4" />
|
||||
<WeeklyTraffic websiteId={websiteId} />
|
||||
</Panel>
|
||||
</GridRow>
|
||||
</Grid>
|
||||
|
|
@ -5,10 +5,11 @@ import { DateDistance } from '@/components/common/DateDistance';
|
|||
import { filtersObjectToArray } from '@/lib/params';
|
||||
import { CohortEditButton } from '@/app/(main)/websites/[websiteId]/cohorts/CohortEditButton';
|
||||
import { CohortDeleteButton } from '@/app/(main)/websites/[websiteId]/cohorts/CohortDeleteButton';
|
||||
import Link from 'next/link';
|
||||
|
||||
export function CohortsTable({ data = [] }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { websiteId } = useNavigation();
|
||||
const { websiteId, renderUrl } = useNavigation();
|
||||
|
||||
if (data.length === 0) {
|
||||
return <Empty />;
|
||||
|
|
@ -16,7 +17,11 @@ export function CohortsTable({ data = [] }) {
|
|||
|
||||
return (
|
||||
<DataTable data={data}>
|
||||
<DataColumn id="name" label={formatMessage(labels.name)} />
|
||||
<DataColumn id="name" label={formatMessage(labels.name)}>
|
||||
{(row: any) => (
|
||||
<Link href={renderUrl(`/websites/${websiteId}?cohort=${row.id}`)}>{row.name}</Link>
|
||||
)}
|
||||
</DataColumn>
|
||||
<DataColumn id="created" label={formatMessage(labels.created)}>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
</DataColumn>
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ const EventValues = ({ websiteId, eventName, propertyName }) => {
|
|||
const tableData = useMemo(() => {
|
||||
if (!propertyName || !values || propertySum === 0) return [];
|
||||
return values.map(({ value, total }) => ({
|
||||
x: value,
|
||||
y: total,
|
||||
z: 100 * (total / propertySum),
|
||||
label: value,
|
||||
count: total,
|
||||
percent: 100 * (total / propertySum),
|
||||
}));
|
||||
}, [propertyName, values, propertySum]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
import { TabList, Tab, Tabs, TabPanel, Column } from '@umami/react-zen';
|
||||
import { EventsTable } from '@/components/metrics/EventsTable';
|
||||
import { MetricsTable } from '@/components/metrics/MetricsTable';
|
||||
import { useState, Key } from 'react';
|
||||
import { EventsDataTable } from './EventsDataTable';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
|
|
@ -13,14 +13,9 @@ import { getItem, setItem } from '@/lib/storage';
|
|||
const KEY_NAME = 'umami.events.tab';
|
||||
|
||||
export function EventsPage({ websiteId }) {
|
||||
const [label, setLabel] = useState(null);
|
||||
const [tab, setTab] = useState(getItem(KEY_NAME) || 'chart');
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const handleLabelClick = (value: string) => {
|
||||
setLabel(value !== label ? value : '');
|
||||
};
|
||||
|
||||
const handleSelect = (value: Key) => {
|
||||
setItem(KEY_NAME, value);
|
||||
setTab(value);
|
||||
|
|
@ -42,14 +37,13 @@ export function EventsPage({ websiteId }) {
|
|||
<TabPanel id="chart">
|
||||
<Column gap="6">
|
||||
<Column border="bottom" paddingBottom="6">
|
||||
<EventsChart websiteId={websiteId} focusLabel={label} />
|
||||
<EventsChart websiteId={websiteId} />
|
||||
</Column>
|
||||
<EventsTable
|
||||
<MetricsTable
|
||||
websiteId={websiteId}
|
||||
type="event"
|
||||
title={formatMessage(labels.events)}
|
||||
metric={formatMessage(labels.actions)}
|
||||
onLabelClick={handleLabelClick}
|
||||
/>
|
||||
</Column>
|
||||
</TabPanel>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ import { DateDistance } from '@/components/common/DateDistance';
|
|||
import { filtersObjectToArray } from '@/lib/params';
|
||||
import { SegmentEditButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentEditButton';
|
||||
import { SegmentDeleteButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton';
|
||||
import Link from 'next/link';
|
||||
|
||||
export function SegmentsTable({ data = [] }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { websiteId } = useNavigation();
|
||||
const { websiteId, renderUrl } = useNavigation();
|
||||
|
||||
if (data.length === 0) {
|
||||
return <Empty />;
|
||||
|
|
@ -16,7 +17,11 @@ export function SegmentsTable({ data = [] }) {
|
|||
|
||||
return (
|
||||
<DataTable data={data}>
|
||||
<DataColumn id="name" label={formatMessage(labels.name)} />
|
||||
<DataColumn id="name" label={formatMessage(labels.name)}>
|
||||
{(row: any) => (
|
||||
<Link href={renderUrl(`/websites/${websiteId}?segment=${row.id}`)}>{row.name}</Link>
|
||||
)}
|
||||
</DataColumn>
|
||||
<DataColumn id="created" label={formatMessage(labels.created)}>
|
||||
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
|
||||
</DataColumn>
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ const SessionValues = ({ websiteId, propertyName }) => {
|
|||
const tableData = useMemo(() => {
|
||||
if (!propertyName || !data || propertySum === 0) return [];
|
||||
return data.map(({ value, total }) => ({
|
||||
x: value,
|
||||
y: total,
|
||||
z: 100 * (total / propertySum),
|
||||
label: value,
|
||||
count: total,
|
||||
percent: 100 * (total / propertySum),
|
||||
}));
|
||||
}, [propertyName, data, propertySum]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,112 +0,0 @@
|
|||
import { Row, Grid, Text } from '@umami/react-zen';
|
||||
import { format, startOfDay, addHours } from 'date-fns';
|
||||
import { useLocale, useMessages, useWebsiteSessionsWeeklyQuery } from '@/components/hooks';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { getDayOfWeekAsDate } from '@/lib/date';
|
||||
import { Focusable, Tooltip, TooltipTrigger } from '@umami/react-zen';
|
||||
|
||||
export function SessionsWeekly({ websiteId }: { websiteId: string }) {
|
||||
const { data, isLoading, error } = useWebsiteSessionsWeeklyQuery(websiteId);
|
||||
const { dateLocale } = useLocale();
|
||||
const { labels, formatMessage } = useMessages();
|
||||
const { weekStartsOn } = dateLocale.options;
|
||||
const daysOfWeek = Array(7)
|
||||
.fill(weekStartsOn)
|
||||
.map((d, i) => (d + i) % 7);
|
||||
|
||||
const [, max = 1] = data
|
||||
? data.reduce((arr: number[], hours: number[], index: number) => {
|
||||
const min = Math.min(...hours);
|
||||
const max = Math.max(...hours);
|
||||
|
||||
if (index === 0) {
|
||||
return [min, max];
|
||||
}
|
||||
|
||||
if (min < arr[0]) {
|
||||
arr[0] = min;
|
||||
}
|
||||
|
||||
if (max > arr[1]) {
|
||||
arr[1] = max;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}, [])
|
||||
: [];
|
||||
|
||||
return (
|
||||
<LoadingPanel data={data} isLoading={isLoading} error={error}>
|
||||
<Grid columns="repeat(8, 1fr)" gap>
|
||||
{data && (
|
||||
<>
|
||||
<Grid rows="repeat(25, 20px)" gap="1">
|
||||
<Row> </Row>
|
||||
{Array(24)
|
||||
.fill(null)
|
||||
.map((_, i) => {
|
||||
const label = format(addHours(startOfDay(new Date()), i), 'p', {
|
||||
locale: dateLocale,
|
||||
})
|
||||
.replace(/\D00 ?/, '')
|
||||
.toLowerCase();
|
||||
return (
|
||||
<Row key={i} justifyContent="flex-end">
|
||||
<Text color="muted">{label}</Text>
|
||||
</Row>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
{daysOfWeek.map((index: number) => {
|
||||
const day = data[index];
|
||||
return (
|
||||
<Grid
|
||||
rows="repeat(24, 20px)"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
key={index}
|
||||
gap="1"
|
||||
>
|
||||
<Row alignItems="center" justifyContent="center" marginBottom="3">
|
||||
<Text weight="bold" align="center">
|
||||
{format(getDayOfWeekAsDate(index), 'EEE', { locale: dateLocale })}
|
||||
</Text>
|
||||
</Row>
|
||||
{day?.map((count: number, j) => {
|
||||
const pct = max ? count / max : 0;
|
||||
return (
|
||||
<TooltipTrigger key={j} delay={0} isDisabled={count <= 0}>
|
||||
<Focusable>
|
||||
<Row
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
backgroundColor="2"
|
||||
width="20px"
|
||||
height="20px"
|
||||
borderRadius="full"
|
||||
style={{ margin: '0 auto' }}
|
||||
>
|
||||
<Row
|
||||
backgroundColor="primary"
|
||||
width="20px"
|
||||
height="20px"
|
||||
borderRadius="full"
|
||||
style={{ opacity: pct, transform: `scale(${pct})` }}
|
||||
/>
|
||||
</Row>
|
||||
</Focusable>
|
||||
<Tooltip placement="right">{`${formatMessage(
|
||||
labels.visitors,
|
||||
)}: ${count}`}</Tooltip>
|
||||
</TooltipTrigger>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</LoadingPanel>
|
||||
);
|
||||
}
|
||||
|
|
@ -11,9 +11,9 @@ import {
|
|||
Text,
|
||||
} from '@umami/react-zen';
|
||||
import {
|
||||
useApi,
|
||||
useLoginQuery,
|
||||
useMessages,
|
||||
useUpdateQuery,
|
||||
useUserTeamsQuery,
|
||||
useWebsite,
|
||||
} from '@/components/hooks';
|
||||
|
|
@ -32,10 +32,7 @@ export function WebsiteTransferForm({
|
|||
const website = useWebsite();
|
||||
const [teamId, setTeamId] = useState<string>(null);
|
||||
const { formatMessage, labels, messages } = useMessages();
|
||||
const { post, useMutation } = useApi();
|
||||
const { mutate, error } = useMutation({
|
||||
mutationFn: (data: any) => post(`/websites/${websiteId}/transfer`, data),
|
||||
});
|
||||
const { mutate, error, isPending } = useUpdateQuery(`/websites/${websiteId}/transfer`);
|
||||
const { data: teams, isLoading } = useUserTeamsQuery(user.id);
|
||||
const isTeamWebsite = !!website?.teamId;
|
||||
|
||||
|
|
@ -92,7 +89,11 @@ export function WebsiteTransferForm({
|
|||
</FormField>
|
||||
<FormButtons>
|
||||
<Button onPress={onClose}>{formatMessage(labels.cancel)}</Button>
|
||||
<FormSubmitButton variant="primary" isDisabled={!isTeamWebsite && !teamId}>
|
||||
<FormSubmitButton
|
||||
variant="primary"
|
||||
isPending={isPending}
|
||||
isDisabled={!isTeamWebsite && !teamId}
|
||||
>
|
||||
{formatMessage(labels.transfer)}
|
||||
</FormSubmitButton>
|
||||
</FormButtons>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { getQueryFilters, parseRequest } from '@/lib/request';
|
|||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/validations';
|
||||
import { pagingParams, timezoneParam } from '@/lib/schema';
|
||||
import { getWebsiteSessionsWeekly } from '@/queries';
|
||||
import { getWeeklyTraffic } from '@/queries';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
|
|
@ -30,7 +30,7 @@ export async function GET(
|
|||
|
||||
const filters = await getQueryFilters(query, websiteId);
|
||||
|
||||
const data = await getWebsiteSessionsWeekly(websiteId, filters);
|
||||
const data = await getWeeklyTraffic(websiteId, filters);
|
||||
|
||||
return json(data);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue