mirror of
https://github.com/umami-software/umami.git
synced 2026-02-18 03:25:40 +01:00
Compare commits
2 commits
40492ec7c4
...
9a5604f236
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a5604f236 | ||
|
|
bcafa12349 |
17 changed files with 60 additions and 85 deletions
|
|
@ -78,7 +78,7 @@
|
||||||
"@react-spring/web": "^10.0.3",
|
"@react-spring/web": "^10.0.3",
|
||||||
"@svgr/cli": "^8.1.0",
|
"@svgr/cli": "^8.1.0",
|
||||||
"@tanstack/react-query": "^5.90.5",
|
"@tanstack/react-query": "^5.90.5",
|
||||||
"@umami/react-zen": "^0.200.0",
|
"@umami/react-zen": "^0.203.0",
|
||||||
"@umami/redis-client": "^0.29.0",
|
"@umami/redis-client": "^0.29.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
|
|
|
||||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
|
@ -45,8 +45,8 @@ importers:
|
||||||
specifier: ^5.90.5
|
specifier: ^5.90.5
|
||||||
version: 5.90.5(react@19.2.0)
|
version: 5.90.5(react@19.2.0)
|
||||||
'@umami/react-zen':
|
'@umami/react-zen':
|
||||||
specifier: ^0.200.0
|
specifier: ^0.203.0
|
||||||
version: 0.200.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0))
|
version: 0.203.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0))
|
||||||
'@umami/redis-client':
|
'@umami/redis-client':
|
||||||
specifier: ^0.29.0
|
specifier: ^0.29.0
|
||||||
version: 0.29.0
|
version: 0.29.0
|
||||||
|
|
@ -2921,8 +2921,8 @@ packages:
|
||||||
resolution: {integrity: sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==}
|
resolution: {integrity: sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@umami/react-zen@0.200.0':
|
'@umami/react-zen@0.203.0':
|
||||||
resolution: {integrity: sha512-En5H5XpssItNPPSxb+xwGyMUalmqeoWCzMInGi/MJau/kkcJ2V0mSrgZ8RVRryl8cBg8fpktK7JaCTNULweUFA==}
|
resolution: {integrity: sha512-lgGUapA0zDbLu63GINaEPndIsT8ry85vE316AWU/EEH3qYDBNscetcBfZFr+DTD/c5eLKy9OxmMwIpbs7k+/UA==}
|
||||||
|
|
||||||
'@umami/redis-client@0.29.0':
|
'@umami/redis-client@0.29.0':
|
||||||
resolution: {integrity: sha512-Jaqh++jskqDB7ny75pfC02OvKp1JTS4asGDsFrRL3qy8sxL3PAl9+/mybCJe4/6vWrXDJKqpgkSfUDJq2bFjyw==}
|
resolution: {integrity: sha512-Jaqh++jskqDB7ny75pfC02OvKp1JTS4asGDsFrRL3qy8sxL3PAl9+/mybCJe4/6vWrXDJKqpgkSfUDJq2bFjyw==}
|
||||||
|
|
@ -10670,7 +10670,7 @@ snapshots:
|
||||||
'@typescript-eslint/types': 8.46.1
|
'@typescript-eslint/types': 8.46.1
|
||||||
eslint-visitor-keys: 4.2.1
|
eslint-visitor-keys: 4.2.1
|
||||||
|
|
||||||
'@umami/react-zen@0.200.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0))':
|
'@umami/react-zen@0.203.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@fontsource/jetbrains-mono': 5.2.8
|
'@fontsource/jetbrains-mono': 5.2.8
|
||||||
'@internationalized/date': 3.10.0
|
'@internationalized/date': 3.10.0
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import Link from 'next/link';
|
||||||
import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav';
|
import { WebsiteNav } from '@/app/(main)/websites/[websiteId]/WebsiteNav';
|
||||||
import { Logo } from '@/components/svg';
|
import { Logo } from '@/components/svg';
|
||||||
import { NavButton } from '@/components/input/NavButton';
|
import { NavButton } from '@/components/input/NavButton';
|
||||||
import { MobileMenu } from '@/components/common/MobileMenu';
|
import { MobileMenuButton } from '@/components/input/MobileMenuButton';
|
||||||
|
|
||||||
export function MobileNav() {
|
export function MobileNav() {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
|
|
@ -33,8 +33,8 @@ export function MobileNav() {
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid columns="auto 1fr" flexGrow={1}>
|
<Grid columns="auto 1fr" flexGrow={1} backgroundColor="3" borderRadius>
|
||||||
<MobileMenu>
|
<MobileMenuButton>
|
||||||
{({ close }) => {
|
{({ close }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -54,7 +54,7 @@ export function MobileNav() {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</MobileMenu>
|
</MobileMenuButton>
|
||||||
<Row alignItems="center" justifyContent="center" flexGrow={1}>
|
<Row alignItems="center" justifyContent="center" flexGrow={1}>
|
||||||
<IconLabel icon={<Logo />} style={{ width: 'auto' }}>
|
<IconLabel icon={<Logo />} style={{ width: 'auto' }}>
|
||||||
<Text weight="bold">umami</Text>
|
<Text weight="bold">umami</Text>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Dialog, Modal, useBreakpoint } from '@umami/react-zen';
|
import { Dialog, Modal } from '@umami/react-zen';
|
||||||
import { WebsiteExpandedView } from '@/app/(main)/websites/[websiteId]/WebsiteExpandedView';
|
import { WebsiteExpandedView } from '@/app/(main)/websites/[websiteId]/WebsiteExpandedView';
|
||||||
import { useNavigation } from '@/components/hooks';
|
import { useNavigation, useMobile } from '@/components/hooks';
|
||||||
|
|
||||||
export function ExpandedViewModal({
|
export function ExpandedViewModal({
|
||||||
websiteId,
|
websiteId,
|
||||||
|
|
@ -14,8 +14,7 @@ export function ExpandedViewModal({
|
||||||
query: { view },
|
query: { view },
|
||||||
updateParams,
|
updateParams,
|
||||||
} = useNavigation();
|
} = useNavigation();
|
||||||
const breakpoint = useBreakpoint();
|
const { isMobile } = useMobile();
|
||||||
const isMobile = ['xs', 'sm', 'md'].includes(breakpoint);
|
|
||||||
|
|
||||||
const handleClose = (close: () => void) => {
|
const handleClose = (close: () => void) => {
|
||||||
router.push(updateParams({ view: undefined }));
|
router.push(updateParams({ view: undefined }));
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { Grid, Column, Row } from '@umami/react-zen';
|
||||||
import { useMessages, useNavigation } from '@/components/hooks';
|
import { useMessages, useNavigation } from '@/components/hooks';
|
||||||
import { MetricsExpandedTable } from '@/components/metrics/MetricsExpandedTable';
|
import { MetricsExpandedTable } from '@/components/metrics/MetricsExpandedTable';
|
||||||
import { WebsiteExpandedMenu } from '@/app/(main)/websites/[websiteId]/WebsiteExpandedMenu';
|
import { WebsiteExpandedMenu } from '@/app/(main)/websites/[websiteId]/WebsiteExpandedMenu';
|
||||||
import { MobileMenu } from '@/components/common/MobileMenu';
|
import { MobileMenuButton } from '@/components/input/MobileMenuButton';
|
||||||
|
|
||||||
export function WebsiteExpandedView({
|
export function WebsiteExpandedView({
|
||||||
websiteId,
|
websiteId,
|
||||||
|
|
@ -21,11 +21,11 @@ export function WebsiteExpandedView({
|
||||||
return (
|
return (
|
||||||
<Column gap>
|
<Column gap>
|
||||||
<Row display={{ xs: 'flex', md: 'none' }}>
|
<Row display={{ xs: 'flex', md: 'none' }}>
|
||||||
<MobileMenu>
|
<MobileMenuButton>
|
||||||
{({ close }) => {
|
{({ close }) => {
|
||||||
return <WebsiteExpandedMenu excludedIds={excludedIds} onItemClick={close} />;
|
return <WebsiteExpandedMenu excludedIds={excludedIds} onItemClick={close} />;
|
||||||
}}
|
}}
|
||||||
</MobileMenu>
|
</MobileMenuButton>
|
||||||
</Row>
|
</Row>
|
||||||
<Grid columns={{ xs: '1fr', md: 'auto 1fr' }} gap="6" height="100%" overflow="hidden">
|
<Grid columns={{ xs: '1fr', md: 'auto 1fr' }} gap="6" height="100%" overflow="hidden">
|
||||||
<Column
|
<Column
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button, Icon, Text, Row, DialogTrigger, Dialog, Modal } from '@umami/react-zen';
|
import { Icon, Text, Row } from '@umami/react-zen';
|
||||||
import { PageHeader } from '@/components/common/PageHeader';
|
import { PageHeader } from '@/components/common/PageHeader';
|
||||||
import { Share, Edit } from '@/components/icons';
|
import { Share, Edit } from '@/components/icons';
|
||||||
import { Favicon } from '@/components/common/Favicon';
|
import { Favicon } from '@/components/common/Favicon';
|
||||||
|
|
@ -6,6 +6,7 @@ import { ActiveUsers } from '@/components/metrics/ActiveUsers';
|
||||||
import { WebsiteShareForm } from '@/app/(main)/websites/[websiteId]/settings/WebsiteShareForm';
|
import { WebsiteShareForm } from '@/app/(main)/websites/[websiteId]/settings/WebsiteShareForm';
|
||||||
import { useMessages, useNavigation, useWebsite } from '@/components/hooks';
|
import { useMessages, useNavigation, useWebsite } from '@/components/hooks';
|
||||||
import { LinkButton } from '@/components/common/LinkButton';
|
import { LinkButton } from '@/components/common/LinkButton';
|
||||||
|
import { DialogButton } from '@/components/input/DialogButton';
|
||||||
|
|
||||||
export function WebsiteHeader({ showActions }: { showActions?: boolean }) {
|
export function WebsiteHeader({ showActions }: { showActions?: boolean }) {
|
||||||
const website = useWebsite();
|
const website = useWebsite();
|
||||||
|
|
@ -45,20 +46,10 @@ const ShareButton = ({ websiteId, shareId }) => {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogTrigger>
|
<DialogButton icon={<Share />} label={formatMessage(labels.share)} width="800px">
|
||||||
<Button>
|
{({ close }) => {
|
||||||
<Icon>
|
return <WebsiteShareForm websiteId={websiteId} shareId={shareId} onClose={close} />;
|
||||||
<Share />
|
}}
|
||||||
</Icon>
|
</DialogButton>
|
||||||
<Text>Share</Text>
|
|
||||||
</Button>
|
|
||||||
<Modal>
|
|
||||||
<Dialog title={formatMessage(labels.share)} style={{ width: 800 }}>
|
|
||||||
{({ close }) => {
|
|
||||||
return <WebsiteShareForm websiteId={websiteId} shareId={shareId} onClose={close} />;
|
|
||||||
}}
|
|
||||||
</Dialog>
|
|
||||||
</Modal>
|
|
||||||
</DialogTrigger>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ export function WebsiteNav({
|
||||||
.find(({ path }) => path && pathname.endsWith(path.split('?')[0]))?.id;
|
.find(({ path }) => path && pathname.endsWith(path.split('?')[0]))?.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column padding="3" gap>
|
<Column padding="3" position="sticky" top="0" gap>
|
||||||
<WebsiteSelect
|
<WebsiteSelect
|
||||||
websiteId={websiteId}
|
websiteId={websiteId}
|
||||||
teamId={teamId}
|
teamId={teamId}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ export function WebsitePanels({ websiteId }: { websiteId: string }) {
|
||||||
</GridRow>
|
</GridRow>
|
||||||
|
|
||||||
<GridRow layout="two-one" {...rowProps}>
|
<GridRow layout="two-one" {...rowProps}>
|
||||||
<Panel gridColumn={{ xs: 'span 1', md: 'span 2' }} padding="0">
|
<Panel gridColumn={{ xs: 'span 1', md: 'span 2' }} paddingX="0" paddingY="0">
|
||||||
<WorldMap websiteId={websiteId} />
|
<WorldMap websiteId={websiteId} />
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import {
|
||||||
cloneElement,
|
cloneElement,
|
||||||
isValidElement,
|
isValidElement,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { SearchField, Row, Column, useBreakpoint } from '@umami/react-zen';
|
import { SearchField, Row, Column } from '@umami/react-zen';
|
||||||
import { UseQueryResult } from '@tanstack/react-query';
|
import { UseQueryResult } from '@tanstack/react-query';
|
||||||
import { useMessages, useNavigation } from '@/components/hooks';
|
import { useMessages, useMobile, useNavigation } from '@/components/hooks';
|
||||||
import { Pager } from '@/components/common/Pager';
|
import { Pager } from '@/components/common/Pager';
|
||||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||||
import { PageResult } from '@/lib/types';
|
import { PageResult } from '@/lib/types';
|
||||||
|
|
@ -42,8 +42,8 @@ export function DataGrid({
|
||||||
const { router, updateParams, query: queryParams } = useNavigation();
|
const { router, updateParams, query: queryParams } = useNavigation();
|
||||||
const [search, setSearch] = useState(queryParams?.search || data?.search || '');
|
const [search, setSearch] = useState(queryParams?.search || data?.search || '');
|
||||||
const showPager = allowPaging && data && data.count > data.pageSize;
|
const showPager = allowPaging && data && data.count > data.pageSize;
|
||||||
const breakpoint = useBreakpoint();
|
const { isMobile } = useMobile();
|
||||||
const displayMode = ['xs', 'sm', 'md', 'lg'].includes(breakpoint) ? 'cards' : undefined;
|
const displayMode = isMobile ? 'cards' : undefined;
|
||||||
|
|
||||||
const handleSearch = (value: string) => {
|
const handleSearch = (value: string) => {
|
||||||
if (value !== search) {
|
if (value !== search) {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,8 @@
|
||||||
import { useState, Key, Fragment } from 'react';
|
import { useState, Key, Fragment } from 'react';
|
||||||
import {
|
import { Modal, Select, ListItem, ListSeparator, Dialog, SelectProps } from '@umami/react-zen';
|
||||||
Modal,
|
|
||||||
Select,
|
|
||||||
ListItem,
|
|
||||||
ListSeparator,
|
|
||||||
Dialog,
|
|
||||||
SelectProps,
|
|
||||||
useBreakpoint,
|
|
||||||
} from '@umami/react-zen';
|
|
||||||
import { endOfYear } from 'date-fns';
|
import { endOfYear } from 'date-fns';
|
||||||
import { DatePickerForm } from '@/components/metrics/DatePickerForm';
|
import { DatePickerForm } from '@/components/metrics/DatePickerForm';
|
||||||
import { useMessages } from '@/components/hooks';
|
import { useMessages, useMobile } from '@/components/hooks';
|
||||||
import { DateDisplay } from '@/components/common/DateDisplay';
|
import { DateDisplay } from '@/components/common/DateDisplay';
|
||||||
import { parseDateRange } from '@/lib/date';
|
import { parseDateRange } from '@/lib/date';
|
||||||
|
|
||||||
|
|
@ -33,8 +25,7 @@ export function DateFilter({
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const [showPicker, setShowPicker] = useState(false);
|
const [showPicker, setShowPicker] = useState(false);
|
||||||
const { startDate, endDate } = parseDateRange(value) || {};
|
const { startDate, endDate } = parseDateRange(value) || {};
|
||||||
const breakpoint = useBreakpoint();
|
const { isMobile } = useMobile();
|
||||||
const isMobile = ['xs', 'sm', 'md'].includes(breakpoint);
|
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{ label: formatMessage(labels.today), value: '0day' },
|
{ label: formatMessage(labels.today), value: '0day' },
|
||||||
|
|
@ -119,7 +110,8 @@ export function DateFilter({
|
||||||
placeholder={formatMessage(labels.selectDate)}
|
placeholder={formatMessage(labels.selectDate)}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
renderValue={renderValue}
|
renderValue={renderValue}
|
||||||
popoverProps={{ placement, isNonModal: isMobile }}
|
popoverProps={{ placement }}
|
||||||
|
isFullscreen={isMobile}
|
||||||
>
|
>
|
||||||
{options.map(({ label, value, divider }: any) => {
|
{options.map(({ label, value, divider }: any) => {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export function DialogButton({
|
||||||
icon,
|
icon,
|
||||||
label,
|
label,
|
||||||
title,
|
title,
|
||||||
width = '800px',
|
width,
|
||||||
height,
|
height,
|
||||||
minWidth,
|
minWidth,
|
||||||
minHeight,
|
minHeight,
|
||||||
|
|
@ -46,7 +46,6 @@ export function DialogButton({
|
||||||
<Button {...props}>
|
<Button {...props}>
|
||||||
<IconLabel icon={icon} label={label} />
|
<IconLabel icon={icon} label={label} />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Modal placement={isMobile ? 'fullscreen' : 'center'}>
|
<Modal placement={isMobile ? 'fullscreen' : 'center'}>
|
||||||
<Dialog variant={isMobile ? 'sheet' : undefined} title={title || label} style={style}>
|
<Dialog variant={isMobile ? 'sheet' : undefined} title={title || label} style={style}>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useFilters, useMessages, useNavigation } from '@/components/hooks';
|
import { useFilters, useMessages, useMobile, useNavigation } from '@/components/hooks';
|
||||||
import { FieldFilters } from '@/components/input/FieldFilters';
|
import { FieldFilters } from '@/components/input/FieldFilters';
|
||||||
import { SegmentFilters } from '@/components/input/SegmentFilters';
|
import { SegmentFilters } from '@/components/input/SegmentFilters';
|
||||||
import { Button, Column, Row, Tab, TabList, TabPanel, Tabs, useBreakpoint } from '@umami/react-zen';
|
import { Button, Column, Row, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
export interface FilterEditFormProps {
|
export interface FilterEditFormProps {
|
||||||
|
|
@ -20,8 +20,7 @@ export function FilterEditForm({ websiteId, onChange, onClose }: FilterEditFormP
|
||||||
const [currentFilters, setCurrentFilters] = useState(filters);
|
const [currentFilters, setCurrentFilters] = useState(filters);
|
||||||
const [currentSegment, setCurrentSegment] = useState(segment);
|
const [currentSegment, setCurrentSegment] = useState(segment);
|
||||||
const [currentCohort, setCurrentCohort] = useState(cohort);
|
const [currentCohort, setCurrentCohort] = useState(cohort);
|
||||||
const breakpoint = useBreakpoint();
|
const { isMobile } = useMobile();
|
||||||
const isMobile = ['xs', 'sm', 'md'].includes(breakpoint);
|
|
||||||
const excludeFilters = pathname.includes('/pixels') || pathname.includes('/links');
|
const excludeFilters = pathname.includes('/pixels') || pathname.includes('/links');
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Dialog, DialogTrigger, Button, Icon, Modal, DialogProps } from '@umami/react-zen';
|
import { Dialog, DialogTrigger, Button, Icon, Modal, DialogProps } from '@umami/react-zen';
|
||||||
import { Menu } from '@/components/icons';
|
import { Menu } from '@/components/icons';
|
||||||
|
|
||||||
export function MobileMenu(props: DialogProps) {
|
export function MobileMenuButton(props: DialogProps) {
|
||||||
return (
|
return (
|
||||||
<DialogTrigger>
|
<DialogTrigger>
|
||||||
<Button>
|
<Button>
|
||||||
|
|
@ -12,9 +12,14 @@ import {
|
||||||
Column,
|
Column,
|
||||||
Pressable,
|
Pressable,
|
||||||
IconLabel,
|
IconLabel,
|
||||||
useBreakpoint,
|
|
||||||
} from '@umami/react-zen';
|
} from '@umami/react-zen';
|
||||||
import { useConfig, useLoginQuery, useMessages, useNavigation } from '@/components/hooks';
|
import {
|
||||||
|
useConfig,
|
||||||
|
useLoginQuery,
|
||||||
|
useMessages,
|
||||||
|
useMobile,
|
||||||
|
useNavigation,
|
||||||
|
} from '@/components/hooks';
|
||||||
import {
|
import {
|
||||||
BookText,
|
BookText,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
|
|
@ -40,11 +45,10 @@ export function NavButton({ showText = true }: TeamsButtonProps) {
|
||||||
const { cloudMode } = useConfig();
|
const { cloudMode } = useConfig();
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { teamId } = useNavigation();
|
const { teamId } = useNavigation();
|
||||||
const breakpoint = useBreakpoint();
|
const { isMobile } = useMobile();
|
||||||
const team = user?.teams?.find(({ id }) => id === teamId);
|
const team = user?.teams?.find(({ id }) => id === teamId);
|
||||||
const selectedKeys = new Set([teamId || 'user']);
|
const selectedKeys = new Set([teamId || 'user']);
|
||||||
const label = teamId ? team?.name : user.username;
|
const label = teamId ? team?.name : user.username;
|
||||||
const isMobile = ['xs', 'sm', 'md'].includes(breakpoint);
|
|
||||||
|
|
||||||
const getUrl = (url: string) => {
|
const getUrl = (url: string) => {
|
||||||
return cloudMode ? `${process.env.cloudUrl}${url}` : url;
|
return cloudMode ? `${process.env.cloudUrl}${url}` : url;
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,18 @@
|
||||||
import { Button, Icon, DialogTrigger, Dialog, Text, Modal, useBreakpoint } from '@umami/react-zen';
|
|
||||||
import { ListFilter } from '@/components/icons';
|
import { ListFilter } from '@/components/icons';
|
||||||
import { FilterEditForm } from '@/components/input/FilterEditForm';
|
import { FilterEditForm } from '@/components/input/FilterEditForm';
|
||||||
|
import { DialogButton } from '@/components/input/DialogButton';
|
||||||
import { useMessages, useNavigation } from '@/components/hooks';
|
import { useMessages, useNavigation } from '@/components/hooks';
|
||||||
import { filtersArrayToObject } from '@/lib/params';
|
import { filtersArrayToObject } from '@/lib/params';
|
||||||
|
|
||||||
export function WebsiteFilterButton({
|
export function WebsiteFilterButton({
|
||||||
websiteId,
|
websiteId,
|
||||||
showText = true,
|
|
||||||
}: {
|
}: {
|
||||||
websiteId: string;
|
websiteId: string;
|
||||||
position?: 'bottom' | 'top' | 'left' | 'right';
|
position?: 'bottom' | 'top' | 'left' | 'right';
|
||||||
alignment?: 'end' | 'center' | 'start';
|
alignment?: 'end' | 'center' | 'start';
|
||||||
showText?: boolean;
|
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { updateParams, router } = useNavigation();
|
const { updateParams, router } = useNavigation();
|
||||||
const breakpoint = useBreakpoint();
|
|
||||||
const isMobile = ['xs', 'sm', 'md'].includes(breakpoint);
|
|
||||||
|
|
||||||
const handleChange = ({ filters, segment, cohort }: any) => {
|
const handleChange = ({ filters, segment, cohort }: any) => {
|
||||||
const params = filtersArrayToObject(filters);
|
const params = filtersArrayToObject(filters);
|
||||||
|
|
@ -27,20 +23,10 @@ export function WebsiteFilterButton({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogTrigger>
|
<DialogButton icon={<ListFilter />} label={formatMessage(labels.filter)} variant="outline">
|
||||||
<Button variant="outline">
|
{({ close }) => {
|
||||||
<Icon>
|
return <FilterEditForm websiteId={websiteId} onChange={handleChange} onClose={close} />;
|
||||||
<ListFilter />
|
}}
|
||||||
</Icon>
|
</DialogButton>
|
||||||
{showText && <Text>{formatMessage(labels.filter)}</Text>}
|
|
||||||
</Button>
|
|
||||||
<Modal placement={isMobile ? 'fullscreen' : 'center'}>
|
|
||||||
<Dialog title={formatMessage(labels.filters)}>
|
|
||||||
{({ close }) => {
|
|
||||||
return <FilterEditForm websiteId={websiteId} onChange={handleChange} onClose={close} />;
|
|
||||||
}}
|
|
||||||
</Dialog>
|
|
||||||
</Modal>
|
|
||||||
</DialogTrigger>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ export function DatePickerForm({
|
||||||
<Calendar value={date} minValue={minDate} maxValue={maxDate} onChange={setDate} />
|
<Calendar value={date} minValue={minDate} maxValue={maxDate} onChange={setDate} />
|
||||||
)}
|
)}
|
||||||
{selected.includes(FILTER_RANGE) && (
|
{selected.includes(FILTER_RANGE) && (
|
||||||
<Row gap>
|
<Row gap wrap="wrap" style={{ margin: '0 auto' }}>
|
||||||
<Calendar
|
<Calendar
|
||||||
value={startDate}
|
value={startDate}
|
||||||
minValue={minDate}
|
minValue={minDate}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,12 @@ export function WorldMap({ websiteId, data, ...props }: WorldMapProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column {...props} data-tip="" data-for="world-map-tooltip" style={{ margin: 'auto 0' }}>
|
<Column
|
||||||
|
{...props}
|
||||||
|
data-tip=""
|
||||||
|
data-for="world-map-tooltip"
|
||||||
|
style={{ margin: 'auto 0', overflow: 'hidden' }}
|
||||||
|
>
|
||||||
<ComposableMap projection="geoMercator">
|
<ComposableMap projection="geoMercator">
|
||||||
<ZoomableGroup zoom={0.8} minZoom={0.7} center={[0, 40]}>
|
<ZoomableGroup zoom={0.8} minZoom={0.7} center={[0, 40]}>
|
||||||
<Geographies geography={`${process.env.basePath || ''}${MAP_FILE}`}>
|
<Geographies geography={`${process.env.basePath || ''}${MAP_FILE}`}>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue